diff --git a/.checkignore b/.checkignore
deleted file mode 100644
index 902ad5922b4..00000000000
--- a/.checkignore
+++ /dev/null
@@ -1,7 +0,0 @@
-# Quantified Code ignore file. https://www.quantifiedcode.com
-
-# Ignore tests folder
-**/tests/**
-**/tests/
-tests/
-
diff --git a/.ciocheck b/.ciocheck
deleted file mode 100644
index 04d64ace7cb..00000000000
--- a/.ciocheck
+++ /dev/null
@@ -1,81 +0,0 @@
-# -----------------------------------------------------------------------------
-# ciocheck
-# https://github.com/ContinuumIO/ciocheck
-# -----------------------------------------------------------------------------
-[ciocheck]
-branch = origin/master
-diff_mode = commited
-file_mode = lines
-check = pep8,pydocstyle,flake8
-enforce = pep8,pydocstyle,flake8
-
-# Python (pyformat)
-add_copyright = true
-add_header = true
-add_init = true
-
-# -----------------------------------------------------------------------------
-# pep8
-# http://pep8.readthedocs.io/en/latest/intro.html#configuration
-# -----------------------------------------------------------------------------
-[pep8]
-exclude = */tests/*
-ignore = E126, E402,
-max-line-length = 79
-
-# -----------------------------------------------------------------------------
-# pydocstyle
-# http://www.pydocstyle.org/en/latest/usage.html#example
-# -----------------------------------------------------------------------------
-[pydocstyle]
-add-ignore = D203
-inherit = false
-
-# -----------------------------------------------------------------------------
-# Flake 8
-# http://flake8.readthedocs.io/en/latest/config.html
-# -----------------------------------------------------------------------------
-[flake8]
-exclude = */tests/*
-ignore = E126, E402,
-max-line-length = 79
-max-complexity = 64
-
-# -----------------------------------------------------------------------------
-# pylint
-# https://pylint.readthedocs.io/en/latest/
-# -----------------------------------------------------------------------------
-#[pylint:messages]
-
-# -----------------------------------------------------------------------------
-# isort
-# https://github.com/timothycrosley/isort/wiki/isort-Settings
-# -----------------------------------------------------------------------------
-[isort]
-from_first = true
-import_heading_stdlib = Standard library imports
-import_heading_thirdparty = Third party imports
-import_heading_firstparty = Local imports
-indent = ' '
-known_first_party = spyder
-known_third_party =
-line_length = 79
-sections = FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
-
-# -----------------------------------------------------------------------------
-# yapf
-# https://github.com/google/yapf#formatting-style
-# -----------------------------------------------------------------------------
-[yapf:style]
-based_on_style = pep8
-column_limit = 79
-spaces_before_comment = 2
-
-# -----------------------------------------------------------------------------
-# autopep8
-# http://pep8.readthedocs.io/en/latest/intro.html#configuration
-# -----------------------------------------------------------------------------
-[autopep8]
-exclude = */tests/*
-ignore = E126,
-max-line-length = 79
diff --git a/.ciocopyright b/.ciocopyright
deleted file mode 100644
index 6e3a13d3e68..00000000000
--- a/.ciocopyright
+++ /dev/null
@@ -1,6 +0,0 @@
-# -----------------------------------------------------------------------------
-# Copyright (c) Spyder Project Contributors
-#
-# Licensed under the terms of the MIT License
-# (see spyder/__init__.py for details)
-# -----------------------------------------------------------------------------
\ No newline at end of file
diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 00000000000..92d0bacf42f
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,51 @@
+version: 2
+
+main: &main
+ machine: true
+ steps:
+ - checkout
+ - run:
+ command: docker pull dorowu/ubuntu-desktop-lxde-vnc:xenial
+ - run:
+ name: Install system packages
+ command: |
+ sudo apt-get -qq update
+ sudo apt-get install libegl1-mesa
+ - run:
+ command: ./continuous_integration/travis/install.sh
+ - run:
+ command: ./continuous_integration/circle/modules_test.sh || ./continuous_integration/circle/modules_test.sh
+
+jobs:
+ python2.7:
+ <<: *main
+ environment:
+ - PYTHON_VERSION: "2.7"
+ - USE_CONDA: "yes"
+
+ python3.5:
+ <<: *main
+ environment:
+ - PYTHON_VERSION: "3.5"
+ - USE_CONDA: "no"
+
+ python3.6:
+ <<: *main
+ environment:
+ - PYTHON_VERSION: "3.6"
+ - USE_CONDA: "yes"
+
+ python3.7:
+ <<: *main
+ environment:
+ - PYTHON_VERSION: "3.7"
+ - USE_CONDA: "yes"
+
+workflows:
+ version: 2
+ build_and_test:
+ jobs:
+ - python2.7
+ - python3.5
+ - python3.6
+ - python3.7
diff --git a/.codecov.yml b/.codecov.yml
index 87543f9d44a..c329f5d788e 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -1,6 +1,6 @@
codecov:
notify:
- require_ci_to_pass: yes
+ require_ci_to_pass: no
codecov:
branch: master
@@ -9,14 +9,14 @@ coverage:
precision: 2
round: down
range: "70...100"
-
+
status:
project:
default:
threshold: 1%
patch: no
changes: no
-
+
parsers:
gcov:
branch_detection:
@@ -24,5 +24,5 @@ parsers:
loop: yes
method: no
macro: no
-
+
comment: false
diff --git a/.coveragerc b/.coveragerc
index 88f2947dbf7..1d57b0cc264 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -8,4 +8,11 @@ omit =
*/utils/site/*
[report]
+# Regexes for lines to exclude from consideration
+exclude_lines =
+ # Have to re-enable the standard pragma
+ pragma: no cover
+
+ # Don't complain if non-runnable code isn't run
+ if __name__ == .__main__.:
fail_under=0
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index d1be074a642..a14ae8450e6 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,34 +1,37 @@
-
-
+
+
+
+
-### Pull Request Checklist
+## Description of Changes
-* [ ] Read and followed this repo's [Contributing Guidelines](https://github.com/spyder-ide/spyder/blob/master/CONTRIBUTING.md)
-* [ ] Based your PR on the latest version of the correct branch (master or 3.x)
-* [ ] Followed [PEP8](https://www.python.org/dev/peps/pep-0008/) for code style
-* [ ] Ensured your pull request hasn't eliminated unrelated blank lines/spaces,
- modified the ``spyder/defaults`` directory, or added new icons/assets
-* [ ] Wrote at least one-line docstrings for any new functions
-* [ ] Added at least one unit test covering the changes, if at all possible
-* [ ] Described your changes and the motivation for them below
-* [ ] Noted what issue(s) this pull request resolves, creating one if needed
-* [ ] Included a screenshot, if this PR makes any visible changes to the UI
+* [ ] Wrote at least one-line docstrings (for any new functions)
+* [ ] Added unit test(s) covering the changes (if testable)
+
+* [ ] Included a screenshot or animation (if affecting the UI, see [Licecap](https://www.cockos.com/licecap/))
-## Description of Changes
-
+
### Issue(s) Resolved
-
-
-
+
Fixes #
+### Affirmation
+
+By submitting this Pull Request or typing my (user)name below,
+I affirm the [Developer Certificate of Origin](https://developercertificate.org)
+with respect to all commits and content included in this PR,
+and understand I am releasing the same under Spyder's MIT (Expat) license.
+
+
+I certify the above statement is true and correct:
+
diff --git a/.gitignore b/.gitignore
index 17b1824e598..f16a4a8e683 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,3 +26,10 @@ spyder_crash.log
# git .orig files
*.orig
+
+# log files
+*.log
+
+# Rope project folders
+.ropeproject/
+.vscode/
\ No newline at end of file
diff --git a/.project b/.project
deleted file mode 100644
index 8c053367f5a..00000000000
--- a/.project
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
- Spyder is a free open-source Python development environment providing MATLAB-like features in a simple and light-weighted software.
+ Spyder is a powerful scientific environment written in Python, for Python, and designed by and for scientists, engineers and data analysts.
+ It features a unique combination of the advanced editing, analysis, debugging and profiling functionality of a comprehensive development tool
+ with the data exploration, interactive execution, deep inspection and beautiful visualization capabilities of an analysis package.
- It contains a powerful interactive development environment for the Python language with advanced editing, interactive testing, debugging and introspection features
- and a numerical computing environment thanks to the support of IPython (enhanced interactive Python interpreter) and popular Python libraries such as NumPy
- (linear algebra), SciPy (signal and image processing) or matplotlib (interactive 2D/3D plotting).
-
- Spyder may also be used as a library providing powerful console-related widgets for your PyQt-based applications – for example, it may be used to integrate
- a debugging console directly in the layout of your graphical user interface.
+ Furthermore, Spyder offers built-in integration with many popular scientific libraries,
+ including NumPy, SciPy, Pandas, IPython, QtConsole, Matplotlib, SymPy, and more, and can be extended further with full plugin support.
+ Spyder can also be used as a PyQt5 extension library, allowing you to build upon its functionality and embed its components,
+ such as the interactive console, in your own software.
Created by Pierre Raybaut.
-
+ Spyder {spyder_ver} {revision}
+
+ Created by Pierre Raybaut; current maintainer is Carlos Cordoba.
+ Developed by the
+ international
+ Spyder community. Many thanks to all the Spyder beta testers
+ and dedicated users.
+ For help with Spyder errors and crashes, please read our
- Troubleshooting page, and for bug reports and
- feature requests, visit our Github website.
- For project discussion, see our Google Group.
- This project is part of a larger effort to promote and
+ Troubleshooting Guide, and for bug
+ reports and feature requests, visit our
+ Github site. For project discussion,
+ see our Google Group.
+
+ This project is part of a larger effort to promote and
facilitate the use of Python for scientific and engineering
- software development. The popular Python distributions
- Anaconda,
- WinPython and
- Python(x,y)
+ software development.
+ The popular Python distributions
+ Anaconda and
+ WinPython
also contribute to this plan.
- Python %s %dbits, Qt %s, %s %s on %s
- Most of the icons for the Spyder 2 theme come from the Crystal
- Project (© 2006-2007 Everaldo Coelho). Other icons for that
- theme come from Yusuke
- Kamiyamane (all rights reserved) and from
-
- The Oxygen icon theme.
- """
- % (versions['spyder'], revlink, __project_url__, __trouble_url__,
- __project_url__, __forum_url__, versions['python'],
- versions['bitness'], versions['qt'], versions['qt_api'],
- versions['qt_api_ver'], versions['system']))
+
+ Python {python_ver} {bitness}-bit | Qt {qt_ver} |
+ {qt_api} {qt_api_ver} | {os_name} {os_ver}
+ Certain source files under other compatible permissive
+ licenses and/or originally by other authors.
+ Spyder 3 theme icons derived from
+ Font Awesome 4.7
+ (© 2016 David Gandy; SIL OFL 1.1) and
+ Material Design
+ (© 2014 Austin Andrews; SIL OFL 1.1).
+ Most Spyder 2 theme icons sourced from the
+ Crystal Project iconset
+ (© 2006-2007 Everaldo Coelho; LGPL 2.1+).
+ Other icons from
+ Yusuke Kamiyamane
+ (© 2013 Yusuke Kamiyamane; CC-BY 3.0),
+ the FamFamFam
+ Silk icon set 1.3 (© 2006 Mark James; CC-BY 2.5), and
+ the KDE Oxygen icons
+ (© 2007 KDE Artists; LGPL 3.0+).
+
+ See the NOTICE
+ file for full legal information.
+
+Enjoy!
-Carlos
@@ -130,49 +130,57 @@ scientific computing and software development.
# Beta release
-**Subject**: [ANN] Spyder 3.0 seventh public beta release
+**Subject**: [ANN] Spyder 4.0 second public beta release
Hi all,
On the behalf of the [Spyder Project Contributors](https://github.com/spyder-ide/spyder/graphs/contributors),
-I'm pleased to announce the seventh beta of our next major version: Spyder **3.0**.
+I'm pleased to announce the second beta of our next major version: Spyder **4.0**.
-We've been working on this version for more than two years now and as far as we know
+We've been working on this version for almost three years now and as far as we know
it's working very well. There are still several bugs to squash but we encourage all
people who like the bleeding edge to give it a try. This beta version is released
-two weeks after our sixth one and it includes more than 200 commits.
+10 months after Spyder 4.0 beta1 and it includes 2150 commits.
-Spyder 3.0 comes with several interesting and exciting new features. The most
+Spyder 4.0 comes with several interesting and exciting new features. The most
important ones are:
-* Third-party plugins: External developers can now create plugins that extend Spyder in
- novel and interesting ways. For example, we already have plugins for the line-profiler
- and memory-profiler projects, and also a graphical frontend for the conda package
- manager. These plugins can be distributed as pip and/or conda packages for authors
- convenience.
-* Improved projects support: Projects have been revamped and improved significantly in
- Spyder 3.0. With our new projects support, people will have the possibility of easily
- working on different coding efforts at the same time. That's because projects save the
- state of open files in the Editor and allow Python packages created as part of the
- project to be imported in our consoles.
-* Support for much more programming languages: Spyder relies now on the excellent Pygments
- library to provide syntax highlight and suggest code completions in the Editor, for all
- programming languages supported by it.
-* A new file switcher: Spyder 3.0 comes with a fancy file switcher, very similar in
- spirit to the one present in Sublime Text. This is a dialog to select among the open
- files in the Editor, by doing a fuzzy search through their names. It also lets users to
- view the list of classes, methods and functions defined in the current file, and select
- one of them. This dialog is activated with `Ctrl+P`.
-* A Numpy array graphical builder: Users who need to create NumPy arrays in Spyder for
- matrices and vectors can do it now in a graphical way by pressing `Ctrl+M` in the Editor
- or the Consoles. This will open an empty 2D table widget to be filled with the data
- required by the user.
-* A new icon theme based on FontAwesome.
-* A new set of default pane layouts for those coming from Rstudio or Matlab (under
- `View > Window layouts`).
-* A simpler and more intuitive way to introduce keyboard shortcuts.
-* Support for PyQt5, which fixes problems in MacOS X and in high definition screens.
+- Main Window
+ * Dark theme for the entire application.
+ * A new Plots pane to browse all inline figures generated by the
+ IPython console.
+ * Create a separate window when undocking all panes.
+ * Add translations for Simplified Chinese and German.
+
+- Editor
+ * Code folding.
+ * Indent guides.
+ * A class/method/function lookup “context panel”.
+ * Autosave functionality to recover unsaved files after a crash.
+ * Code completion and linting are provided by the Language Server Protocol.
+
+- IPython Console
+ * Add menu options to start consoles in Pylab, Sympy and Cython modes.
+ * Cells are run through a function called runcell.
+
+- Variable Explorer
+ * Add MultiIndex display support to the Dataframe viewer.
+ * Add support for all Pandas indexes.
+ * Add support for sets.
+
+- File Explorer
+
+ * Add `Open With OS` context menu action to all files, to open any file or
+ directory externally.
+ * Add multi-select functionality (Ctrl/Shift+click).
+ * Add the ability to copy/paste files and their absolute or relative paths.
+ * Use special icons for different file types.
+ * Add an option to open files and directories with a single click.
+
+- Outline Explorer
+ * Show cells grouped in sections.
+
For a complete list of changes, please see our
[changelog](https://github.com/spyder-ide/spyder/wiki/Beta-version-changelog)
@@ -180,13 +188,12 @@ For a complete list of changes, please see our
You can easily install this beta if you use Anaconda by running:
conda update qt pyqt
- conda install -c qttesting qt pyqt
- conda install -c spyder-ide spyder==3.0.0b7
+ conda install -c spyder-ide spyder=4.0.0b2
Or you can use pip with this command:
pip install --pre -U spyder
-Enjoy!
--Carlos
+Enjoy!
+Carlos
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c706cbfb698..a537729c038 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,1141 @@
# History of changes
+## Version 4.0beta2 (2019-05-19)
+
+### Issues Closed
+
+* [Issue 9341](https://github.com/spyder-ide/spyder/issues/9341) - RuntimeError after closing a split editor ([PR 9345](https://github.com/spyder-ide/spyder/pull/9345))
+* [Issue 9332](https://github.com/spyder-ide/spyder/issues/9332) - Search is broken in file switcher and produces exception due to indentation error ([PR 9333](https://github.com/spyder-ide/spyder/pull/9333))
+* [Issue 9323](https://github.com/spyder-ide/spyder/issues/9323) - Close brackets or close quotes doesn't update the LSP ([PR 9324](https://github.com/spyder-ide/spyder/pull/9324))
+* [Issue 9311](https://github.com/spyder-ide/spyder/issues/9311) - Some issues with calltips and hovers ([PR 9322](https://github.com/spyder-ide/spyder/pull/9322))
+* [Issue 9299](https://github.com/spyder-ide/spyder/issues/9299) - Code style warnings are not updated in the Editor after "Delete line" shortcut ([PR 9300](https://github.com/spyder-ide/spyder/pull/9300))
+* [Issue 9298](https://github.com/spyder-ide/spyder/issues/9298) - About dialog on OSX is too big and bolded ([PR 9306](https://github.com/spyder-ide/spyder/pull/9306))
+* [Issue 9294](https://github.com/spyder-ide/spyder/issues/9294) - Error when getting hover of "dict" ([PR 9301](https://github.com/spyder-ide/spyder/pull/9301))
+* [Issue 9287](https://github.com/spyder-ide/spyder/issues/9287) - Hovers, tooltips and calltips are shown at the wrong position on Linux ([PR 9293](https://github.com/spyder-ide/spyder/pull/9293))
+* [Issue 9281](https://github.com/spyder-ide/spyder/issues/9281) - Avoid the possibility of duplicate preferences dialogs ([PR 9280](https://github.com/spyder-ide/spyder/pull/9280))
+* [Issue 9273](https://github.com/spyder-ide/spyder/issues/9273) - Autocomplete choice 1 option ([PR 9260](https://github.com/spyder-ide/spyder/pull/9260))
+* [Issue 9269](https://github.com/spyder-ide/spyder/issues/9269) - Autocompletion doesn't update ([PR 9260](https://github.com/spyder-ide/spyder/pull/9260))
+* [Issue 9268](https://github.com/spyder-ide/spyder/issues/9268) - Autocompletion appears right before return and change the text ([PR 9260](https://github.com/spyder-ide/spyder/pull/9260))
+* [Issue 9267](https://github.com/spyder-ide/spyder/issues/9267) - Auto completion widget shows even after line return ([PR 9260](https://github.com/spyder-ide/spyder/pull/9260))
+* [Issue 9257](https://github.com/spyder-ide/spyder/issues/9257) - Spyder steals my letters! ([PR 9260](https://github.com/spyder-ide/spyder/pull/9260))
+* [Issue 9248](https://github.com/spyder-ide/spyder/issues/9248) - Appearance preferences for syntax highlighting with dark theme look weird ([PR 9348](https://github.com/spyder-ide/spyder/pull/9348))
+* [Issue 9245](https://github.com/spyder-ide/spyder/issues/9245) - Improve dialog to start servers for other languages
+* [Issue 9242](https://github.com/spyder-ide/spyder/issues/9242) - Remove unused Pyflakes and pep8 checks ([PR 9243](https://github.com/spyder-ide/spyder/pull/9243))
+* [Issue 9236](https://github.com/spyder-ide/spyder/issues/9236) - Opening a new editor window results in an error ([PR 9282](https://github.com/spyder-ide/spyder/pull/9282))
+* [Issue 9211](https://github.com/spyder-ide/spyder/issues/9211) - Show PyLS server errors in Spyder's error report dialog ([PR 9266](https://github.com/spyder-ide/spyder/pull/9266))
+* [Issue 9209](https://github.com/spyder-ide/spyder/issues/9209) - Setting ignore rules for Pycodestyle is not working ([PR 9231](https://github.com/spyder-ide/spyder/pull/9231))
+* [Issue 9208](https://github.com/spyder-ide/spyder/issues/9208) - Hide debugger panel for files that are not Python ones ([PR 9289](https://github.com/spyder-ide/spyder/pull/9289))
+* [Issue 9207](https://github.com/spyder-ide/spyder/issues/9207) - Rename plugins for a simpler, less crowded interface ([PR 9237](https://github.com/spyder-ide/spyder/pull/9237))
+* [Issue 9195](https://github.com/spyder-ide/spyder/issues/9195) - Cannot connect to an external PyLS server ([PR 9203](https://github.com/spyder-ide/spyder/pull/9203))
+* [Issue 9187](https://github.com/spyder-ide/spyder/issues/9187) - Define Hint behavior ([PR 9191](https://github.com/spyder-ide/spyder/pull/9191))
+* [Issue 9173](https://github.com/spyder-ide/spyder/issues/9173) - Error when closing a panel ([PR 9175](https://github.com/spyder-ide/spyder/pull/9175))
+* [Issue 9151](https://github.com/spyder-ide/spyder/issues/9151) - Add icons for Latex file type ([PR 9228](https://github.com/spyder-ide/spyder/pull/9228))
+* [Issue 9150](https://github.com/spyder-ide/spyder/issues/9150) - Improve the "Open recent" menu ([PR 9230](https://github.com/spyder-ide/spyder/pull/9230))
+* [Issue 9120](https://github.com/spyder-ide/spyder/issues/9120) - QDarkStyle issue on Mac for status bar ([PR 9121](https://github.com/spyder-ide/spyder/pull/9121))
+* [Issue 9044](https://github.com/spyder-ide/spyder/issues/9044) - Editor text is all shown in bold text ([PR 9046](https://github.com/spyder-ide/spyder/pull/9046))
+* [Issue 9006](https://github.com/spyder-ide/spyder/issues/9006) - Shorten status bar widgets size ([PR 9010](https://github.com/spyder-ide/spyder/pull/9010))
+* [Issue 8985](https://github.com/spyder-ide/spyder/issues/8985) - Reconnect warning menu with PyLS output ([PR 9011](https://github.com/spyder-ide/spyder/pull/9011))
+* [Issue 8930](https://github.com/spyder-ide/spyder/issues/8930) - Single click to interact with items in Project Explorer, rather than double-click ([PR 9024](https://github.com/spyder-ide/spyder/pull/9024))
+* [Issue 8865](https://github.com/spyder-ide/spyder/issues/8865) - LSP services don't work in any split Editor pane but the first (left/topmost) one ([PR 9075](https://github.com/spyder-ide/spyder/pull/9075))
+* [Issue 8859](https://github.com/spyder-ide/spyder/issues/8859) - Completion popup menu isn't dismissed after typing a delimiter and causes unexpected behavior ([PR 9057](https://github.com/spyder-ide/spyder/pull/9057))
+* [Issue 8846](https://github.com/spyder-ide/spyder/issues/8846) - Errors in the debugger panel and stuck indicator after ending the debugging ([PR 8854](https://github.com/spyder-ide/spyder/pull/8854))
+* [Issue 8828](https://github.com/spyder-ide/spyder/issues/8828) - Tests are failing with PyLS 0.23+ ([PR 8972](https://github.com/spyder-ide/spyder/pull/8972))
+* [Issue 8816](https://github.com/spyder-ide/spyder/issues/8816) - Deleting a server in the LSP preferences pane when only one is present raises exceptions ([PR 8647](https://github.com/spyder-ide/spyder/pull/8647))
+* [Issue 8815](https://github.com/spyder-ide/spyder/issues/8815) - Error in code completion when case-sensitive completions are disabled ([PR 9104](https://github.com/spyder-ide/spyder/pull/9104))
+* [Issue 8813](https://github.com/spyder-ide/spyder/issues/8813) - Errors triggered when saving "Saving as" a file in latest master ([PR 8932](https://github.com/spyder-ide/spyder/pull/8932))
+* [Issue 8749](https://github.com/spyder-ide/spyder/issues/8749) - Closing moved files creates IndexError ([PR 8782](https://github.com/spyder-ide/spyder/pull/8782))
+* [Issue 8727](https://github.com/spyder-ide/spyder/issues/8727) - autocomplete fails to select an option in the list ([PR 8724](https://github.com/spyder-ide/spyder/pull/8724))
+* [Issue 8723](https://github.com/spyder-ide/spyder/issues/8723) - autocomplete fails when pressing tab too quickly ([PR 8724](https://github.com/spyder-ide/spyder/pull/8724))
+* [Issue 8655](https://github.com/spyder-ide/spyder/issues/8655) - Autosave not removed when closing a changed file without saving ([PR 8733](https://github.com/spyder-ide/spyder/pull/8733))
+* [Issue 8654](https://github.com/spyder-ide/spyder/issues/8654) - Text files are wrongly autosaved when opened without changing them ([PR 9205](https://github.com/spyder-ide/spyder/pull/9205))
+* [Issue 8641](https://github.com/spyder-ide/spyder/issues/8641) - Assign a keyboard shortcut for "next figure" and "previous figure" of the Plots pane ([PR 8643](https://github.com/spyder-ide/spyder/pull/8643))
+* [Issue 8640](https://github.com/spyder-ide/spyder/issues/8640) - Assign a keyboard shortcut to switch to the Plots pane ([PR 9036](https://github.com/spyder-ide/spyder/pull/9036))
+* [Issue 8631](https://github.com/spyder-ide/spyder/issues/8631) - Cannot restore files between different drives in Windows ([PR 8650](https://github.com/spyder-ide/spyder/pull/8650))
+* [Issue 8628](https://github.com/spyder-ide/spyder/issues/8628) - Autocomplete replace "import" keyword ([PR 8648](https://github.com/spyder-ide/spyder/pull/8648))
+* [Issue 8626](https://github.com/spyder-ide/spyder/issues/8626) - Display warning about rendering of plots below the new IPython prompt ([PR 8627](https://github.com/spyder-ide/spyder/pull/8627))
+* [Issue 8613](https://github.com/spyder-ide/spyder/issues/8613) - Use new functionality in Qt 5.6 to resize dockwidgets programatically ([PR 9155](https://github.com/spyder-ide/spyder/pull/9155))
+* [Issue 8609](https://github.com/spyder-ide/spyder/issues/8609) - Disabling Automatic Code Completion makes completion, analysis and calltips stop working permanently ([PR 9104](https://github.com/spyder-ide/spyder/pull/9104))
+* [Issue 8603](https://github.com/spyder-ide/spyder/issues/8603) - The command line does not appear in ipython console after the warning about rendering of plots is displayed. ([PR 8604](https://github.com/spyder-ide/spyder/pull/8604))
+* [Issue 8579](https://github.com/spyder-ide/spyder/issues/8579) - Error when triggering completion in the Internal Console ([PR 8593](https://github.com/spyder-ide/spyder/pull/8593))
+* [Issue 8567](https://github.com/spyder-ide/spyder/issues/8567) - Deleting a folder which contains a sub-folder(s) raises an error ([PR 8599](https://github.com/spyder-ide/spyder/pull/8599))
+* [Issue 8566](https://github.com/spyder-ide/spyder/issues/8566) - File names pasted in editor when copied from OS file manager ([PR 8569](https://github.com/spyder-ide/spyder/pull/8569))
+* [Issue 8565](https://github.com/spyder-ide/spyder/issues/8565) - Code analysis and completion often break when the "Automatic code completion" option is checked ([PR 8600](https://github.com/spyder-ide/spyder/pull/8600))
+* [Issue 8560](https://github.com/spyder-ide/spyder/issues/8560) - Sometimes segmentation Fault when placing the mouse cursor over linenumbers ([PR 5283](https://github.com/spyder-ide/spyder/pull/5283))
+* [Issue 8557](https://github.com/spyder-ide/spyder/issues/8557) - KeyError when closing dataframe editor ([PR 8559](https://github.com/spyder-ide/spyder/pull/8559))
+* [Issue 8556](https://github.com/spyder-ide/spyder/issues/8556) - Outline Explorer does not properly handle async functions and methods ([PR 8821](https://github.com/spyder-ide/spyder/pull/8821))
+* [Issue 8545](https://github.com/spyder-ide/spyder/issues/8545) - Full Screen in dual monitor enviroment (windows) ([PR 8546](https://github.com/spyder-ide/spyder/pull/8546))
+* [Issue 8523](https://github.com/spyder-ide/spyder/issues/8523) - Plot plugin context menu wrong style and copy to clipboard action glitches ([PR 8524](https://github.com/spyder-ide/spyder/pull/8524))
+* [Issue 8520](https://github.com/spyder-ide/spyder/issues/8520) - Enclose console warning about plots being rendered in the Plots plugin in horizontal bars ([PR 8584](https://github.com/spyder-ide/spyder/pull/8584))
+* [Issue 8515](https://github.com/spyder-ide/spyder/issues/8515) - Error when deleting a project ([PR 8516](https://github.com/spyder-ide/spyder/pull/8516))
+* [Issue 8511](https://github.com/spyder-ide/spyder/issues/8511) - Not working shortcut for copy figure in Plots Widget if there are multiple consoles. ([PR 8512](https://github.com/spyder-ide/spyder/pull/8512))
+* [Issue 8510](https://github.com/spyder-ide/spyder/issues/8510) - Error when trying to go to cursor position in Outline ([PR 8517](https://github.com/spyder-ide/spyder/pull/8517))
+* [Issue 8506](https://github.com/spyder-ide/spyder/issues/8506) - AttributeError: 'WebView' object has no attribute 'setBackgroundColor' ([PR 8508](https://github.com/spyder-ide/spyder/pull/8508))
+* [Issue 8486](https://github.com/spyder-ide/spyder/issues/8486) - The editor menu has undock option after undock. ([PR 8489](https://github.com/spyder-ide/spyder/pull/8489))
+* [Issue 8478](https://github.com/spyder-ide/spyder/issues/8478) - Improve IPython console Options menu ([PR 8578](https://github.com/spyder-ide/spyder/pull/8578))
+* [Issue 8477](https://github.com/spyder-ide/spyder/issues/8477) - Set dark color for blank html template ([PR 8497](https://github.com/spyder-ide/spyder/pull/8497))
+* [Issue 8468](https://github.com/spyder-ide/spyder/issues/8468) - Feature Request: copy figure of plot widget to clipboard ([PR 8470](https://github.com/spyder-ide/spyder/pull/8470))
+* [Issue 8458](https://github.com/spyder-ide/spyder/issues/8458) - Spyder won't load previously open files from any project with a clean prefs file ([PR 8460](https://github.com/spyder-ide/spyder/pull/8460))
+* [Issue 8455](https://github.com/spyder-ide/spyder/issues/8455) - Project Explorer is sometimes not set correctly when switching projects ([PR 8456](https://github.com/spyder-ide/spyder/pull/8456))
+* [Issue 8450](https://github.com/spyder-ide/spyder/issues/8450) - Project switching with recent projects menu fails to open correct project ([PR 8452](https://github.com/spyder-ide/spyder/pull/8452))
+* [Issue 8443](https://github.com/spyder-ide/spyder/issues/8443) - Backgroud color of Plotwidget in dark theme ([PR 8446](https://github.com/spyder-ide/spyder/pull/8446))
+* [Issue 8388](https://github.com/spyder-ide/spyder/issues/8388) - Use language type icons present in Material design ([PR 8440](https://github.com/spyder-ide/spyder/pull/8440))
+* [Issue 8386](https://github.com/spyder-ide/spyder/issues/8386) - Change function/class/method icons ([PR 8390](https://github.com/spyder-ide/spyder/pull/8390))
+* [Issue 8375](https://github.com/spyder-ide/spyder/issues/8375) - Spyder editor does not open previously opened files in a project ([PR 8429](https://github.com/spyder-ide/spyder/pull/8429))
+* [Issue 8344](https://github.com/spyder-ide/spyder/issues/8344) - Title field of error dialog is too small in macOS ([PR 8378](https://github.com/spyder-ide/spyder/pull/8378))
+* [Issue 8330](https://github.com/spyder-ide/spyder/issues/8330) - qtawsome 0.5.0 requirements is not high enough for master ([PR 8340](https://github.com/spyder-ide/spyder/pull/8340))
+* [Issue 8321](https://github.com/spyder-ide/spyder/issues/8321) - Make a copy of a files inside Project explorer ([PR 8606](https://github.com/spyder-ide/spyder/pull/8606))
+* [Issue 8320](https://github.com/spyder-ide/spyder/issues/8320) - Some issues with the Plots plugin ([PR 8419](https://github.com/spyder-ide/spyder/pull/8419))
+* [Issue 8309](https://github.com/spyder-ide/spyder/issues/8309) - A word write wrong in portuguese in the file pt_BR/LC_MESSAGES/spyder.po ([PR 8441](https://github.com/spyder-ide/spyder/pull/8441))
+* [Issue 8297](https://github.com/spyder-ide/spyder/issues/8297) - Autocomplete doesn't replace text sometimes ([PR 8434](https://github.com/spyder-ide/spyder/pull/8434))
+* [Issue 8293](https://github.com/spyder-ide/spyder/issues/8293) - More easily override conflicted shortcuts ([PR 9031](https://github.com/spyder-ide/spyder/pull/9031))
+* [Issue 8291](https://github.com/spyder-ide/spyder/issues/8291) - Add QDarkstyle to the Dependencies list ([PR 8300](https://github.com/spyder-ide/spyder/pull/8300))
+* [Issue 8284](https://github.com/spyder-ide/spyder/issues/8284) - Improve "Spyder Dark" syntax highlighting theme ([PR 8357](https://github.com/spyder-ide/spyder/pull/8357))
+* [Issue 8283](https://github.com/spyder-ide/spyder/issues/8283) - AttributeError: 'NoneType' object has no attribute 'raise_' error on startup in latest master ([PR 8349](https://github.com/spyder-ide/spyder/pull/8349))
+* [Issue 8270](https://github.com/spyder-ide/spyder/issues/8270) - Simplify Github PR template ([PR 8272](https://github.com/spyder-ide/spyder/pull/8272))
+* [Issue 8267](https://github.com/spyder-ide/spyder/issues/8267) - Triple quotes in a code cell breaks runcell ([PR 8276](https://github.com/spyder-ide/spyder/pull/8276))
+* [Issue 8244](https://github.com/spyder-ide/spyder/issues/8244) - Runcell traceback line number off by one for every code block it's after ([PR 8245](https://github.com/spyder-ide/spyder/pull/8245))
+* [Issue 8242](https://github.com/spyder-ide/spyder/issues/8242) - Double Quotes at the begining or end of the a code cell breaks runcell ([PR 8245](https://github.com/spyder-ide/spyder/pull/8245))
+* [Issue 8241](https://github.com/spyder-ide/spyder/issues/8241) - Cannot runcell if double backslash is present ([PR 8243](https://github.com/spyder-ide/spyder/pull/8243))
+* [Issue 8237](https://github.com/spyder-ide/spyder/issues/8237) - Mitigate Spyder wiping users' files with more robust atomic saves/autosaves ([PR 8347](https://github.com/spyder-ide/spyder/pull/8347))
+* [Issue 8213](https://github.com/spyder-ide/spyder/issues/8213) - PyLS hangs if definition cannot be located ([PR 9138](https://github.com/spyder-ide/spyder/pull/9138))
+* [Issue 8172](https://github.com/spyder-ide/spyder/issues/8172) - Warnings and errors from PyLS don't go away after fixing them, even when saving file ([PR 8257](https://github.com/spyder-ide/spyder/pull/8257))
+* [Issue 8171](https://github.com/spyder-ide/spyder/issues/8171) - Plots plugin is not docked correctly after first start ([PR 8192](https://github.com/spyder-ide/spyder/pull/8192))
+* [Issue 8159](https://github.com/spyder-ide/spyder/issues/8159) - PATH problem since updating macOS ([PR 8351](https://github.com/spyder-ide/spyder/pull/8351))
+* [Issue 8153](https://github.com/spyder-ide/spyder/issues/8153) - Spyder crashes on launch with PyLS >=0.21 ([PR 8600](https://github.com/spyder-ide/spyder/pull/8600))
+* [Issue 8121](https://github.com/spyder-ide/spyder/issues/8121) - Option to show/hide code style analysis warnings does not work ([PR 9182](https://github.com/spyder-ide/spyder/pull/9182))
+* [Issue 8087](https://github.com/spyder-ide/spyder/issues/8087) - Add dark theme style to Help pane ([PR 8086](https://github.com/spyder-ide/spyder/pull/8086))
+* [Issue 8080](https://github.com/spyder-ide/spyder/issues/8080) - Consider making the dark theme (and corresponding Spyder Dark syntax scheme) the default in Spyder 4 ([PR 8266](https://github.com/spyder-ide/spyder/pull/8266))
+* [Issue 8072](https://github.com/spyder-ide/spyder/issues/8072) - Make internal console respect user's syntax highlighting theme ([PR 8251](https://github.com/spyder-ide/spyder/pull/8251))
+* [Issue 8071](https://github.com/spyder-ide/spyder/issues/8071) - Centralize remaining theme-related options (like Rstudio does) under a renamed "Themes" pref pane ([PR 8266](https://github.com/spyder-ide/spyder/pull/8266))
+* [Issue 8069](https://github.com/spyder-ide/spyder/issues/8069) - Spyder dark theme overrides background color set in syntax highlighting theme, except behind text ([PR 8081](https://github.com/spyder-ide/spyder/pull/8081))
+* [Issue 8066](https://github.com/spyder-ide/spyder/issues/8066) - The pyls process opens a black DOS windows under Windows10 ([PR 8360](https://github.com/spyder-ide/spyder/pull/8360))
+* [Issue 8056](https://github.com/spyder-ide/spyder/issues/8056) - Shift-Tab moves focus outside of current Editor pane in Spyder 4
+* [Issue 8043](https://github.com/spyder-ide/spyder/issues/8043) - Closing a Python file in Spyder cause a LSP error ([PR 8044](https://github.com/spyder-ide/spyder/pull/8044))
+* [Issue 8037](https://github.com/spyder-ide/spyder/issues/8037) - DataFrames in Variable Explorer: Missings should have distinctive background color ([PR 8059](https://github.com/spyder-ide/spyder/pull/8059))
+* [Issue 8022](https://github.com/spyder-ide/spyder/issues/8022) - KeyboardInterrupt shows up when Spyder starts ([PR 8600](https://github.com/spyder-ide/spyder/pull/8600))
+* [Issue 8013](https://github.com/spyder-ide/spyder/issues/8013) - Stop button in the IPython console is not working with Python 3.7 on Windows ([PR 8337](https://github.com/spyder-ide/spyder/pull/8337))
+* [Issue 8011](https://github.com/spyder-ide/spyder/issues/8011) - Restore option to open a new editor window ([PR 8192](https://github.com/spyder-ide/spyder/pull/8192))
+* [Issue 7996](https://github.com/spyder-ide/spyder/issues/7996) - Cog menu glitch during Spyder setup in master ([PR 8004](https://github.com/spyder-ide/spyder/pull/8004))
+* [Issue 7993](https://github.com/spyder-ide/spyder/issues/7993) - Order of root file items in the Outline Explorer should be synced with that of the current EditorStack ([PR 8015](https://github.com/spyder-ide/spyder/pull/8015))
+* [Issue 7982](https://github.com/spyder-ide/spyder/issues/7982) - Show files that are not Python files in the Outline Explorer ([PR 7984](https://github.com/spyder-ide/spyder/pull/7984))
+* [Issue 7963](https://github.com/spyder-ide/spyder/issues/7963) - TODO labels are missing in Spyder 4 ([PR 8004](https://github.com/spyder-ide/spyder/pull/8004))
+* [Issue 7930](https://github.com/spyder-ide/spyder/issues/7930) - UnicodeEncodeError in TextEditor ([PR 8342](https://github.com/spyder-ide/spyder/pull/8342))
+* [Issue 7905](https://github.com/spyder-ide/spyder/issues/7905) - Connect to remote kernel: Have a choice between password or keyfile ([PR 7914](https://github.com/spyder-ide/spyder/pull/7914))
+* [Issue 7885](https://github.com/spyder-ide/spyder/issues/7885) - numpy.set_printoptions formatter keyword has no effect on output
+* [Issue 7883](https://github.com/spyder-ide/spyder/issues/7883) - GNU Emacs Style Key Sequences do not work in master AND shortcut conflicts ([PR 7929](https://github.com/spyder-ide/spyder/pull/7929))
+* [Issue 7880](https://github.com/spyder-ide/spyder/issues/7880) - Error when closing dataframe while data is being fetched ([PR 8598](https://github.com/spyder-ide/spyder/pull/8598))
+* [Issue 7875](https://github.com/spyder-ide/spyder/issues/7875) - Config is resetted after a CONF_VERSION bump ([PR 8397](https://github.com/spyder-ide/spyder/pull/8397))
+* [Issue 7872](https://github.com/spyder-ide/spyder/issues/7872) - The "Next word" and " Previous word" shortcuts do not work as expected ([PR 7874](https://github.com/spyder-ide/spyder/pull/7874))
+* [Issue 7865](https://github.com/spyder-ide/spyder/issues/7865) - Multiple `History...` entries in Static Code Analysis context menu ([PR 7866](https://github.com/spyder-ide/spyder/pull/7866))
+* [Issue 7854](https://github.com/spyder-ide/spyder/issues/7854) - Problem with shortcuts using the "Shift" and another key ([PR 7929](https://github.com/spyder-ide/spyder/pull/7929))
+* [Issue 7845](https://github.com/spyder-ide/spyder/issues/7845) - Select the dark or light version of the Spyder icon in the "About Spyder" dialog window depending on the color of the window background ([PR 8541](https://github.com/spyder-ide/spyder/pull/8541))
+* [Issue 7833](https://github.com/spyder-ide/spyder/issues/7833) - Completion not working in Editor due to undeclared dependency on coloredlogs ([PR 7994](https://github.com/spyder-ide/spyder/pull/7994))
+* [Issue 7798](https://github.com/spyder-ide/spyder/issues/7798) - Outline explorer do not sync correctly when closing/re-opening a file in master ([PR 7799](https://github.com/spyder-ide/spyder/pull/7799))
+* [Issue 7760](https://github.com/spyder-ide/spyder/issues/7760) - Run unsaved file in Editor without needing to save ([PR 7310](https://github.com/spyder-ide/spyder/pull/7310))
+* [Issue 7754](https://github.com/spyder-ide/spyder/issues/7754) - Saving a new file or renaming an existing file in master is broken ([PR 7758](https://github.com/spyder-ide/spyder/pull/7758))
+* [Issue 7751](https://github.com/spyder-ide/spyder/issues/7751) - 'ClientWidget' object has no attribute 'show_time_action' ([PR 8062](https://github.com/spyder-ide/spyder/pull/8062))
+* [Issue 7744](https://github.com/spyder-ide/spyder/issues/7744) - Go to line is not working in the outline explorer when clicking on the last item of a file ([PR 7745](https://github.com/spyder-ide/spyder/pull/7745))
+* [Issue 7743](https://github.com/spyder-ide/spyder/issues/7743) - The "Redo" shortcut in the Editor is not working in Spyder4.0.0.dev0 ([PR 7768](https://github.com/spyder-ide/spyder/pull/7768))
+* [Issue 7736](https://github.com/spyder-ide/spyder/issues/7736) - Add the outline explorer option "Group code cells" to config and make it False by default ([PR 7738](https://github.com/spyder-ide/spyder/pull/7738))
+* [Issue 7729](https://github.com/spyder-ide/spyder/issues/7729) - The "Go to cursor position" feature of the outline explorer is broken in master ([PR 7730](https://github.com/spyder-ide/spyder/pull/7730))
+* [Issue 7726](https://github.com/spyder-ide/spyder/issues/7726) - Go to definition in the Editor stopped working after the introspection services migration to use the LSP ([PR 7975](https://github.com/spyder-ide/spyder/pull/7975))
+* [Issue 7704](https://github.com/spyder-ide/spyder/issues/7704) - No cog menu in variable explorer widget toolbar when more than one Ipython console is opened ([PR 7710](https://github.com/spyder-ide/spyder/pull/7710))
+* [Issue 7680](https://github.com/spyder-ide/spyder/issues/7680) - Use a separate configuration directory for beta and dev releases to avoid contaminating user settings ([PR 8837](https://github.com/spyder-ide/spyder/pull/8837))
+* [Issue 7629](https://github.com/spyder-ide/spyder/issues/7629) - DataFrame viewer resizes the index column wrongly ([PR 8550](https://github.com/spyder-ide/spyder/pull/8550))
+* [Issue 7518](https://github.com/spyder-ide/spyder/issues/7518) - Creating a new project makes the path with mixed slashes ([PR 7698](https://github.com/spyder-ide/spyder/pull/7698))
+* [Issue 7339](https://github.com/spyder-ide/spyder/issues/7339) - Indent guides going too far down ([PR 8469](https://github.com/spyder-ide/spyder/pull/8469))
+* [Issue 7338](https://github.com/spyder-ide/spyder/issues/7338) - Outline explorer not synchronized at startup ([PR 7968](https://github.com/spyder-ide/spyder/pull/7968))
+* [Issue 7235](https://github.com/spyder-ide/spyder/issues/7235) - Outliner has no options in the "gear" menu ([PR 7866](https://github.com/spyder-ide/spyder/pull/7866))
+* [Issue 7224](https://github.com/spyder-ide/spyder/issues/7224) - Clearing the variables in a console also clears Pylab and SymPy name spaces and variables ([PR 7876](https://github.com/spyder-ide/spyder/pull/7876))
+* [Issue 7214](https://github.com/spyder-ide/spyder/issues/7214) - Outline pane, clicking on file name should move to start of file ([PR 7962](https://github.com/spyder-ide/spyder/pull/7962))
+* [Issue 7146](https://github.com/spyder-ide/spyder/issues/7146) - MacOS displaying Windows icons and shortcuts ([PR 8212](https://github.com/spyder-ide/spyder/pull/8212))
+* [Issue 7113](https://github.com/spyder-ide/spyder/issues/7113) - Make a function that runs cell blocks instead of copying cell contents into the console ([PR 7310](https://github.com/spyder-ide/spyder/pull/7310))
+* [Issue 7111](https://github.com/spyder-ide/spyder/issues/7111) - Master: There is an area in the top left of spyder that is unclickable ([PR 8104](https://github.com/spyder-ide/spyder/pull/8104))
+* [Issue 7109](https://github.com/spyder-ide/spyder/issues/7109) - Allow keyboard shorcuts to be cleared in preferences ([PR 7929](https://github.com/spyder-ide/spyder/pull/7929))
+* [Issue 7091](https://github.com/spyder-ide/spyder/issues/7091) - QtWebEngineProcess stays open after closing ipython tab ([PR 8740](https://github.com/spyder-ide/spyder/pull/8740))
+* [Issue 6827](https://github.com/spyder-ide/spyder/issues/6827) - Enable automatic insertion of closing quotes inside function calls ([PR 8659](https://github.com/spyder-ide/spyder/pull/8659))
+* [Issue 5911](https://github.com/spyder-ide/spyder/issues/5911) - Feature Request: Sort tabs alphabetically
+* [Issue 5907](https://github.com/spyder-ide/spyder/issues/5907) - Buttons not displayed in mac OS ([PR 8364](https://github.com/spyder-ide/spyder/pull/8364))
+* [Issue 5543](https://github.com/spyder-ide/spyder/issues/5543) - Variable explorer column widths are re-generated in every console evaluation ([PR 5764](https://github.com/spyder-ide/spyder/pull/5764))
+* [Issue 5515](https://github.com/spyder-ide/spyder/issues/5515) - Enhancements proposal related to the undocking and docking of plugins in the Main Window ([PR 8192](https://github.com/spyder-ide/spyder/pull/8192))
+* [Issue 5326](https://github.com/spyder-ide/spyder/issues/5326) - Improve debug logging ([PR 7734](https://github.com/spyder-ide/spyder/pull/7734))
+* [Issue 5323](https://github.com/spyder-ide/spyder/issues/5323) - Ctrl+K does not kill to line end
+* [Issue 5005](https://github.com/spyder-ide/spyder/issues/5005) - Toggle breakpoints by single click
+* [Issue 4936](https://github.com/spyder-ide/spyder/issues/4936) - Feature request: automatic generation of docstring template ([PR 8700](https://github.com/spyder-ide/spyder/pull/8700))
+* [Issue 4742](https://github.com/spyder-ide/spyder/issues/4742) - Adapt code introspection, autocompletion and linting to comply with the Language Server Protocol ([PR 4751](https://github.com/spyder-ide/spyder/pull/4751))
+* [Issue 4591](https://github.com/spyder-ide/spyder/issues/4591) - Split all plugins to be in their own modules ([PR 7725](https://github.com/spyder-ide/spyder/pull/7725))
+* [Issue 4580](https://github.com/spyder-ide/spyder/issues/4580) - Missing "x" on tab for open files in editor ([PR 8363](https://github.com/spyder-ide/spyder/pull/8363))
+* [Issue 3689](https://github.com/spyder-ide/spyder/issues/3689) - How to remember the configurations of connecting to remote kernel? ([PR 8222](https://github.com/spyder-ide/spyder/pull/8222))
+* [Issue 3414](https://github.com/spyder-ide/spyder/issues/3414) - Add encapsulate with parentheses (quotes, brackets, braces) function ([PR 8637](https://github.com/spyder-ide/spyder/pull/8637))
+* [Issue 3064](https://github.com/spyder-ide/spyder/issues/3064) - Allow users to configure PEP8 options ([PR 8647](https://github.com/spyder-ide/spyder/pull/8647))
+* [Issue 2855](https://github.com/spyder-ide/spyder/issues/2855) - Hide the titlebar from panes/dockwidgets if locked ([PR 8192](https://github.com/spyder-ide/spyder/pull/8192))
+* [Issue 2854](https://github.com/spyder-ide/spyder/issues/2854) - Add custom title bar to dockwidgets/panes ([PR 8192](https://github.com/spyder-ide/spyder/pull/8192))
+* [Issue 2641](https://github.com/spyder-ide/spyder/issues/2641) - Enhancement: insert filename as compatible path ([PR 8606](https://github.com/spyder-ide/spyder/pull/8606))
+* [Issue 2550](https://github.com/spyder-ide/spyder/issues/2550) - Dock matplotlib figures ([PR 6430](https://github.com/spyder-ide/spyder/pull/6430))
+* [Issue 2350](https://github.com/spyder-ide/spyder/issues/2350) - Add a Spyder dark theme
+* [Issue 2264](https://github.com/spyder-ide/spyder/issues/2264) - "TODO" should not be labeled with checkmark ([PR 8058](https://github.com/spyder-ide/spyder/pull/8058))
+* [Issue 2111](https://github.com/spyder-ide/spyder/issues/2111) - Enhancement: Implement autosave of editor files every X minutes ([PR 7660](https://github.com/spyder-ide/spyder/pull/7660))
+* [Issue 1634](https://github.com/spyder-ide/spyder/issues/1634) - Support for current element highlighting when "." appears in selection ([PR 5676](https://github.com/spyder-ide/spyder/pull/5676))
+* [Issue 528](https://github.com/spyder-ide/spyder/issues/528) - Add an arrow to point to the current line being debugged in the Editor
+
+In this release 173 issues were closed.
+
+### Pull Requests Merged
+
+* [PR 9355](https://github.com/spyder-ide/spyder/pull/9355) - PR: Add fix for calltips with args and kwargs
+* [PR 9348](https://github.com/spyder-ide/spyder/pull/9348) - PR: Fix code editor background color ([9248](https://github.com/spyder-ide/spyder/issues/9248))
+* [PR 9345](https://github.com/spyder-ide/spyder/pull/9345) - PR: Remove CodeEditor instances from LSP client when split editor is closed ([9341](https://github.com/spyder-ide/spyder/issues/9341))
+* [PR 9334](https://github.com/spyder-ide/spyder/pull/9334) - PR: Fix showing signatures in the IPython console after an open paren
+* [PR 9333](https://github.com/spyder-ide/spyder/pull/9333) - PR: Fix fileswitcher search and improve tests ([9332](https://github.com/spyder-ide/spyder/issues/9332))
+* [PR 9330](https://github.com/spyder-ide/spyder/pull/9330) - PR: Fix about dialog missing breaks
+* [PR 9327](https://github.com/spyder-ide/spyder/pull/9327) - PR: Remove autosaves on successful file close to partially mitigate spurious creation bugs
+* [PR 9324](https://github.com/spyder-ide/spyder/pull/9324) - PR: Have LSP update after closequotes and closebrackets ([9323](https://github.com/spyder-ide/spyder/issues/9323))
+* [PR 9322](https://github.com/spyder-ide/spyder/pull/9322) - PR: Fix some hover and calltip issues ([9311](https://github.com/spyder-ide/spyder/issues/9311))
+* [PR 9310](https://github.com/spyder-ide/spyder/pull/9310) - PR: Restrict PyLS version to be less than 0.25
+* [PR 9309](https://github.com/spyder-ide/spyder/pull/9309) - PR: Mark test_update_warnings_after_delete_line as slow and second
+* [PR 9306](https://github.com/spyder-ide/spyder/pull/9306) - PR: Fix About dialog format on macOS ([9298](https://github.com/spyder-ide/spyder/issues/9298))
+* [PR 9301](https://github.com/spyder-ide/spyder/pull/9301) - PR: Fix hover/calltip for Python objects without signature ([9294](https://github.com/spyder-ide/spyder/issues/9294))
+* [PR 9300](https://github.com/spyder-ide/spyder/pull/9300) - PR: Request a didChange when deleting a line in the Editor ([9299](https://github.com/spyder-ide/spyder/issues/9299))
+* [PR 9293](https://github.com/spyder-ide/spyder/pull/9293) - PR: Fix window flags for linux calltips ([9287](https://github.com/spyder-ide/spyder/issues/9287))
+* [PR 9289](https://github.com/spyder-ide/spyder/pull/9289) - PR: Hide debugger panel for files that are not Python ones ([9208](https://github.com/spyder-ide/spyder/issues/9208))
+* [PR 9288](https://github.com/spyder-ide/spyder/pull/9288) - PR: Reorganize LSP server editor dialog
+* [PR 9282](https://github.com/spyder-ide/spyder/pull/9282) - PR: Fix update calls of status bars for new Editor windows ([9236](https://github.com/spyder-ide/spyder/issues/9236))
+* [PR 9280](https://github.com/spyder-ide/spyder/pull/9280) - PR: Avoid the possibility of duplicate preferences dialogs ([9281](https://github.com/spyder-ide/spyder/issues/9281))
+* [PR 9266](https://github.com/spyder-ide/spyder/pull/9266) - PR: Show PyLS server errors in Spyder's error report dialog ([9211](https://github.com/spyder-ide/spyder/issues/9211))
+* [PR 9260](https://github.com/spyder-ide/spyder/pull/9260) - PR: Improvements to autocompletion ([9273](https://github.com/spyder-ide/spyder/issues/9273), [9269](https://github.com/spyder-ide/spyder/issues/9269), [9268](https://github.com/spyder-ide/spyder/issues/9268), [9267](https://github.com/spyder-ide/spyder/issues/9267), [9257](https://github.com/spyder-ide/spyder/issues/9257))
+* [PR 9243](https://github.com/spyder-ide/spyder/pull/9243) - PR: Remove unused Pyflakes and Pep8 check functions ([9242](https://github.com/spyder-ide/spyder/issues/9242))
+* [PR 9237](https://github.com/spyder-ide/spyder/pull/9237) - PR: Rename plugins to have a simpler interface ([9207](https://github.com/spyder-ide/spyder/issues/9207))
+* [PR 9231](https://github.com/spyder-ide/spyder/pull/9231) - PR: Handle empty options in pycodestyle and pydocstyle preferences ([9209](https://github.com/spyder-ide/spyder/issues/9209))
+* [PR 9230](https://github.com/spyder-ide/spyder/pull/9230) - PR: Display extension type icons and create entry as files are opened in "Open recent" menu ([9150](https://github.com/spyder-ide/spyder/issues/9150))
+* [PR 9229](https://github.com/spyder-ide/spyder/pull/9229) - PR: Fix typo on PR template
+* [PR 9228](https://github.com/spyder-ide/spyder/pull/9228) - PR: Add icon for Latex files ([9151](https://github.com/spyder-ide/spyder/issues/9151))
+* [PR 9224](https://github.com/spyder-ide/spyder/pull/9224) - PR: Ask for animations in pull request template
+* [PR 9210](https://github.com/spyder-ide/spyder/pull/9210) - PR: Add a syntax highlighter for Python log files
+* [PR 9205](https://github.com/spyder-ide/spyder/pull/9205) - PR: Prevent rehighlight() from setting changed_since_autosave_flag ([8654](https://github.com/spyder-ide/spyder/issues/8654))
+* [PR 9203](https://github.com/spyder-ide/spyder/pull/9203) - PR: Add option to connect to external PyLS servers ([9195](https://github.com/spyder-ide/spyder/issues/9195))
+* [PR 9191](https://github.com/spyder-ide/spyder/pull/9191) - PR: Enable hover hints ([9187](https://github.com/spyder-ide/spyder/issues/9187))
+* [PR 9186](https://github.com/spyder-ide/spyder/pull/9186) - PR: Use a single LSP manager instance per module in our tests
+* [PR 9182](https://github.com/spyder-ide/spyder/pull/9182) - PR: Fix Source menu entry to show code style warnings ([8121](https://github.com/spyder-ide/spyder/issues/8121))
+* [PR 9176](https://github.com/spyder-ide/spyder/pull/9176) - PR: Avoid running introspection in tests unless we require it
+* [PR 9175](https://github.com/spyder-ide/spyder/pull/9175) - PR: Remove sig_lsp_notification and improve introspection tests ([9173](https://github.com/spyder-ide/spyder/issues/9173))
+* [PR 9174](https://github.com/spyder-ide/spyder/pull/9174) - PR: Apply dark theme to help icon of arraybuilder
+* [PR 9155](https://github.com/spyder-ide/spyder/pull/9155) - PR: Simplify custom layout definition with the new features in Qt 5.6 ([8613](https://github.com/spyder-ide/spyder/issues/8613))
+* [PR 9154](https://github.com/spyder-ide/spyder/pull/9154) - PR: Reorganize preferences entry for the Editor
+* [PR 9152](https://github.com/spyder-ide/spyder/pull/9152) - PR: Scroll to the selected item after go next thumbnail in Plots plugin
+* [PR 9142](https://github.com/spyder-ide/spyder/pull/9142) - PR: Correctly log errors when handling LSP responses for Python 2
+* [PR 9140](https://github.com/spyder-ide/spyder/pull/9140) - PR: Use calltip widget to display calltips and tooltips
+* [PR 9138](https://github.com/spyder-ide/spyder/pull/9138) - PR: Catch errors generated when handling LSP responses in CodeEditor ([8213](https://github.com/spyder-ide/spyder/issues/8213))
+* [PR 9121](https://github.com/spyder-ide/spyder/pull/9121) - PR: Force darkstyle style on status bar ([9120](https://github.com/spyder-ide/spyder/issues/9120))
+* [PR 9109](https://github.com/spyder-ide/spyder/pull/9109) - PR: Add an option to sort editor tabs alphabetically
+* [PR 9104](https://github.com/spyder-ide/spyder/pull/9104) - PR: Remove "Code Introspection/Analysis" tab of Editor Preferences ([8815](https://github.com/spyder-ide/spyder/issues/8815), [8609](https://github.com/spyder-ide/spyder/issues/8609))
+* [PR 9088](https://github.com/spyder-ide/spyder/pull/9088) - PR: Update simplified chinese translation
+* [PR 9075](https://github.com/spyder-ide/spyder/pull/9075) - PR: Make completion work in split panels again ([8865](https://github.com/spyder-ide/spyder/issues/8865))
+* [PR 9057](https://github.com/spyder-ide/spyder/pull/9057) - PR: Fix completion popup dismissed after typing delimeters or operators ([8859](https://github.com/spyder-ide/spyder/issues/8859))
+* [PR 9054](https://github.com/spyder-ide/spyder/pull/9054) - PR: Add an "Fit plots to window" option to the plots pane
+* [PR 9048](https://github.com/spyder-ide/spyder/pull/9048) - PR: Add basic active git branch display on status bar
+* [PR 9046](https://github.com/spyder-ide/spyder/pull/9046) - PR: Fix bold editor issues when setting bold status widgets ([9044](https://github.com/spyder-ide/spyder/issues/9044))
+* [PR 9040](https://github.com/spyder-ide/spyder/pull/9040) - PR: Fix getting Rope completions from the latest PyLS
+* [PR 9036](https://github.com/spyder-ide/spyder/pull/9036) - PR: Add Ctrl+Shift+G to switch to plots plugin ([8640](https://github.com/spyder-ide/spyder/issues/8640))
+* [PR 9034](https://github.com/spyder-ide/spyder/pull/9034) - PR: Disable status timers if widget is not visible
+* [PR 9033](https://github.com/spyder-ide/spyder/pull/9033) - PR: Fix error when PyLS completions response is None
+* [PR 9031](https://github.com/spyder-ide/spyder/pull/9031) - PR: Automatically unbind conflicting shortcuts when pressing okay in shortcut manager ([8293](https://github.com/spyder-ide/spyder/issues/8293))
+* [PR 9029](https://github.com/spyder-ide/spyder/pull/9029) - PR: Fix error at startup when updating warnings menu
+* [PR 9024](https://github.com/spyder-ide/spyder/pull/9024) - PR: Add single click to open files on file and project explorer ([8930](https://github.com/spyder-ide/spyder/issues/8930))
+* [PR 9011](https://github.com/spyder-ide/spyder/pull/9011) - PR: Reconnect warning menu with PyLS output ([8985](https://github.com/spyder-ide/spyder/issues/8985))
+* [PR 9010](https://github.com/spyder-ide/spyder/pull/9010) - PR: Simplify status bar content and reorganize code ([9006](https://github.com/spyder-ide/spyder/issues/9006))
+* [PR 8972](https://github.com/spyder-ide/spyder/pull/8972) - PR: Disable parameter inclusion in the PyLS ([8828](https://github.com/spyder-ide/spyder/issues/8828))
+* [PR 8932](https://github.com/spyder-ide/spyder/pull/8932) - PR: Catch error in Outline explorer when renaming file ([8813](https://github.com/spyder-ide/spyder/issues/8813))
+* [PR 8911](https://github.com/spyder-ide/spyder/pull/8911) - PR: Fix Windows tests with pip
+* [PR 8877](https://github.com/spyder-ide/spyder/pull/8877) - PR: Adjust font sizes to look better for Linux and Windows
+* [PR 8854](https://github.com/spyder-ide/spyder/pull/8854) - PR: Fix stuck arrow and conditional breakpoints in the debugger panel ([8846](https://github.com/spyder-ide/spyder/issues/8846))
+* [PR 8842](https://github.com/spyder-ide/spyder/pull/8842) - PR: Change default root_path for PyLS and refactor LSP related code
+* [PR 8839](https://github.com/spyder-ide/spyder/pull/8839) - PR: Improve logging of PyLS server and our client in debug mode
+* [PR 8837](https://github.com/spyder-ide/spyder/pull/8837) - PR: Automatically use a separate but persistent configuration directory for non-stable releases ([7680](https://github.com/spyder-ide/spyder/issues/7680))
+* [PR 8836](https://github.com/spyder-ide/spyder/pull/8836) - PR: Don't show a file in the Editor immediately after it's selected in the switcher.
+* [PR 8821](https://github.com/spyder-ide/spyder/pull/8821) - PR: Handle async functions and methods properly in Outline Explorer ([8556](https://github.com/spyder-ide/spyder/issues/8556))
+* [PR 8810](https://github.com/spyder-ide/spyder/pull/8810) - PR: Fix failing Sympy test
+* [PR 8782](https://github.com/spyder-ide/spyder/pull/8782) - PR: Enclose logger.debug call in a try/except ([8749](https://github.com/spyder-ide/spyder/issues/8749))
+* [PR 8769](https://github.com/spyder-ide/spyder/pull/8769) - PR: Add new font size for file switcher according to the OS
+* [PR 8754](https://github.com/spyder-ide/spyder/pull/8754) - PR: Fix spelling errors in test_mainwindow.py comments
+* [PR 8740](https://github.com/spyder-ide/spyder/pull/8740) - PR: Use a single infowidget in the IPython console ([7091](https://github.com/spyder-ide/spyder/issues/7091))
+* [PR 8733](https://github.com/spyder-ide/spyder/pull/8733) - PR: Remove autosave file if user chooses not to save when asked ([8655](https://github.com/spyder-ide/spyder/issues/8655))
+* [PR 8724](https://github.com/spyder-ide/spyder/pull/8724) - PR: Add position to text completion ([8727](https://github.com/spyder-ide/spyder/issues/8727), [8723](https://github.com/spyder-ide/spyder/issues/8723))
+* [PR 8719](https://github.com/spyder-ide/spyder/pull/8719) - PR: Show a place holder text in the file switcher
+* [PR 8717](https://github.com/spyder-ide/spyder/pull/8717) - PR: Change the max number of files in the file switcher to 15
+* [PR 8716](https://github.com/spyder-ide/spyder/pull/8716) - PR: Put section header rows in the file switcher at item level
+* [PR 8704](https://github.com/spyder-ide/spyder/pull/8704) - PR: Update README's sponsors section
+* [PR 8700](https://github.com/spyder-ide/spyder/pull/8700) - PR: Automatic docstring generation for functions ([4936](https://github.com/spyder-ide/spyder/issues/4936))
+* [PR 8691](https://github.com/spyder-ide/spyder/pull/8691) - PR: Improve appearance of breakpoint icon
+* [PR 8678](https://github.com/spyder-ide/spyder/pull/8678) - PR: Use file type icons in the File Switcher
+* [PR 8665](https://github.com/spyder-ide/spyder/pull/8665) - PR: Move config pages of missing plugins to their own modules
+* [PR 8664](https://github.com/spyder-ide/spyder/pull/8664) - PR: Move ConsoleBaseWidget to the console plugin from the editor
+* [PR 8661](https://github.com/spyder-ide/spyder/pull/8661) - PR: Simplify the way to import Editor extensions and panels
+* [PR 8659](https://github.com/spyder-ide/spyder/pull/8659) - PR: Close quotes inside brackets and before commas, colons and semi-colons ([6827](https://github.com/spyder-ide/spyder/issues/6827))
+* [PR 8657](https://github.com/spyder-ide/spyder/pull/8657) - PR: Change font size for file name and path in the file switcher
+* [PR 8653](https://github.com/spyder-ide/spyder/pull/8653) - PR: Move some preferences entries to their own modules
+* [PR 8650](https://github.com/spyder-ide/spyder/pull/8650) - PR: Fall back to copy and delete if replace fails when restoring autosave ([8631](https://github.com/spyder-ide/spyder/issues/8631))
+* [PR 8648](https://github.com/spyder-ide/spyder/pull/8648) - PR: Add validation for blank spaces while doing completion ([8628](https://github.com/spyder-ide/spyder/issues/8628))
+* [PR 8647](https://github.com/spyder-ide/spyder/pull/8647) - PR: Provide graphical options to configure the PyLS ([8816](https://github.com/spyder-ide/spyder/issues/8816), [3064](https://github.com/spyder-ide/spyder/issues/3064))
+* [PR 8644](https://github.com/spyder-ide/spyder/pull/8644) - PR: Add ability to paste auto-formatted file paths into the Editor from the system file manager
+* [PR 8643](https://github.com/spyder-ide/spyder/pull/8643) - PR: Assign a keyboard shortcut for "next figure" and "previous figure" of the Plots pane ([8641](https://github.com/spyder-ide/spyder/issues/8641))
+* [PR 8642](https://github.com/spyder-ide/spyder/pull/8642) - PR: Rewrite LSPManager to inherit from QObject instead of SpyderPluginWidget
+* [PR 8637](https://github.com/spyder-ide/spyder/pull/8637) - PR: Make a closebrackets extension for smarter brackets ([3414](https://github.com/spyder-ide/spyder/issues/3414))
+* [PR 8627](https://github.com/spyder-ide/spyder/pull/8627) - PR: Fix printing warning about rendering of plots below the new prompt ([8626](https://github.com/spyder-ide/spyder/issues/8626))
+* [PR 8616](https://github.com/spyder-ide/spyder/pull/8616) - PR: Use single row for file name and path and use gray for paths in file switcher
+* [PR 8606](https://github.com/spyder-ide/spyder/pull/8606) - PR: Add the ability to copy/paste files and their paths in the File/Project Explorers ([8321](https://github.com/spyder-ide/spyder/issues/8321), [2641](https://github.com/spyder-ide/spyder/issues/2641))
+* [PR 8604](https://github.com/spyder-ide/spyder/pull/8604) - PR: Fix missing IPython prompt ([8603](https://github.com/spyder-ide/spyder/issues/8603))
+* [PR 8600](https://github.com/spyder-ide/spyder/pull/8600) - PR: Fix LSP consumer reading block on Windows ([8565](https://github.com/spyder-ide/spyder/issues/8565), [8153](https://github.com/spyder-ide/spyder/issues/8153), [8022](https://github.com/spyder-ide/spyder/issues/8022))
+* [PR 8599](https://github.com/spyder-ide/spyder/pull/8599) - PR: Add ability to delete long nested directories on Windows from File/Project Explorers ([8567](https://github.com/spyder-ide/spyder/issues/8567))
+* [PR 8598](https://github.com/spyder-ide/spyder/pull/8598) - PR: Enclose contents of load_more_data method in try/except NameError Block ([7880](https://github.com/spyder-ide/spyder/issues/7880))
+* [PR 8593](https://github.com/spyder-ide/spyder/pull/8593) - PR: Fix code completion in the Internal Console ([8579](https://github.com/spyder-ide/spyder/issues/8579))
+* [PR 8590](https://github.com/spyder-ide/spyder/pull/8590) - PR: Adjust attribute icons size on Linux and Windows
+* [PR 8584](https://github.com/spyder-ide/spyder/pull/8584) - PR: Enclose console warning about rendering of plots ([8520](https://github.com/spyder-ide/spyder/issues/8520))
+* [PR 8578](https://github.com/spyder-ide/spyder/pull/8578) - PR: Restructure console menus ([8478](https://github.com/spyder-ide/spyder/issues/8478))
+* [PR 8571](https://github.com/spyder-ide/spyder/pull/8571) - PR: Remove test np_threshold from test_mainwindow.py
+* [PR 8569](https://github.com/spyder-ide/spyder/pull/8569) - PR: Prevent pasting non-text data from clipboard into the editor ([8566](https://github.com/spyder-ide/spyder/issues/8566))
+* [PR 8559](https://github.com/spyder-ide/spyder/pull/8559) - PR: Avoid KeyError when closing Variable Explorer editors ([8557](https://github.com/spyder-ide/spyder/issues/8557))
+* [PR 8558](https://github.com/spyder-ide/spyder/pull/8558) - PR: Add parent reference to QLineEdit of EditTabNamePopup
+* [PR 8552](https://github.com/spyder-ide/spyder/pull/8552) - PR: Improve layout of Appearance entry in Preferences (2)
+* [PR 8550](https://github.com/spyder-ide/spyder/pull/8550) - PR: Improve index column resize in dataframe editor ([7629](https://github.com/spyder-ide/spyder/issues/7629))
+* [PR 8548](https://github.com/spyder-ide/spyder/pull/8548) - PR: Improve layout of Appearance entry in Preferences
+* [PR 8546](https://github.com/spyder-ide/spyder/pull/8546) - PR : Fix full screen action in dual monitor enviroment for Windows ([8545](https://github.com/spyder-ide/spyder/issues/8545))
+* [PR 8541](https://github.com/spyder-ide/spyder/pull/8541) - PR: Use dark logo for the light theme ([7845](https://github.com/spyder-ide/spyder/issues/7845))
+* [PR 8529](https://github.com/spyder-ide/spyder/pull/8529) - PR: Pin pytest to a version less than 4.1
+* [PR 8528](https://github.com/spyder-ide/spyder/pull/8528) - PR: Make the directory tree view proxy model case insensitive on Windows
+* [PR 8525](https://github.com/spyder-ide/spyder/pull/8525) - PR: Add tests for the Plots plugin
+* [PR 8524](https://github.com/spyder-ide/spyder/pull/8524) - PR: Fix bad context menu stylesheet and figure blinking in the Plots plugin ([8523](https://github.com/spyder-ide/spyder/issues/8523))
+* [PR 8517](https://github.com/spyder-ide/spyder/pull/8517) - PR: Fix go to cursor position in Outline for newly created files ([8510](https://github.com/spyder-ide/spyder/issues/8510))
+* [PR 8516](https://github.com/spyder-ide/spyder/pull/8516) - PR: Fix delete project by moving the code from the project explorer to the plugin ([8515](https://github.com/spyder-ide/spyder/issues/8515))
+* [PR 8512](https://github.com/spyder-ide/spyder/pull/8512) - PR: Fix the "Copy Figure" shortcut of Plots pane with multiple consoles ([8511](https://github.com/spyder-ide/spyder/issues/8511))
+* [PR 8508](https://github.com/spyder-ide/spyder/pull/8508) - PR: Fix handling background color of Webview when using QWebView ([8506](https://github.com/spyder-ide/spyder/issues/8506))
+* [PR 8497](https://github.com/spyder-ide/spyder/pull/8497) - PR: Set dark background color for webview in the Help and IPython Console plugins ([8477](https://github.com/spyder-ide/spyder/issues/8477))
+* [PR 8489](https://github.com/spyder-ide/spyder/pull/8489) - PR: Fix actions shown on the Editor Options menu for undocked and new windows ([8486](https://github.com/spyder-ide/spyder/issues/8486))
+* [PR 8481](https://github.com/spyder-ide/spyder/pull/8481) - PR: Add cursor position bookmarks in Editor
+* [PR 8471](https://github.com/spyder-ide/spyder/pull/8471) - PR: Show tests for plugins that use a mocked main window
+* [PR 8470](https://github.com/spyder-ide/spyder/pull/8470) - PR: Add the ability to copy a figure from the plot widget ([8468](https://github.com/spyder-ide/spyder/issues/8468))
+* [PR 8469](https://github.com/spyder-ide/spyder/pull/8469) - PR: Make indentation guides to go up to last line with text ([7339](https://github.com/spyder-ide/spyder/issues/7339))
+* [PR 8460](https://github.com/spyder-ide/spyder/pull/8460) - PR: Handle non-existing saved editor layout when loading projects ([8458](https://github.com/spyder-ide/spyder/issues/8458))
+* [PR 8456](https://github.com/spyder-ide/spyder/pull/8456) - PR: Setup proxy filter before setting the root index ([8455](https://github.com/spyder-ide/spyder/issues/8455))
+* [PR 8452](https://github.com/spyder-ide/spyder/pull/8452) - PR: Fix Recent Project submenu actions in Projects menu. ([8450](https://github.com/spyder-ide/spyder/issues/8450))
+* [PR 8446](https://github.com/spyder-ide/spyder/pull/8446) - PR: Add kwarg for FigureCanvas background color ([8443](https://github.com/spyder-ide/spyder/issues/8443))
+* [PR 8441](https://github.com/spyder-ide/spyder/pull/8441) - PR: Fix translation error in the Brazilian Portuguese translation ([8309](https://github.com/spyder-ide/spyder/issues/8309))
+* [PR 8440](https://github.com/spyder-ide/spyder/pull/8440) - PR: Change image logos for several programming language type files ([8388](https://github.com/spyder-ide/spyder/issues/8388))
+* [PR 8434](https://github.com/spyder-ide/spyder/pull/8434) - PR: Fix completion insertion in the Editor ([8297](https://github.com/spyder-ide/spyder/issues/8297))
+* [PR 8431](https://github.com/spyder-ide/spyder/pull/8431) - PR: Fix macOS tests by pinning to Qt 5.9.6 for now
+* [PR 8429](https://github.com/spyder-ide/spyder/pull/8429) - PR: Set projet filenames correctly when closing a project ([8375](https://github.com/spyder-ide/spyder/issues/8375))
+* [PR 8419](https://github.com/spyder-ide/spyder/pull/8419) - PR: Increase width of the ThumbnailScrollBar and add render message ([8320](https://github.com/spyder-ide/spyder/issues/8320))
+* [PR 8416](https://github.com/spyder-ide/spyder/pull/8416) - PR: Fix error when Editor's dockwidget is not yet initialized
+* [PR 8403](https://github.com/spyder-ide/spyder/pull/8403) - PR: Fix dark CSS for tables and add custom dark scrollbar for the Help plugin
+* [PR 8402](https://github.com/spyder-ide/spyder/pull/8402) - PR: Run Windows tests on Azure
+* [PR 8399](https://github.com/spyder-ide/spyder/pull/8399) - PR: Disable Qt windows style if using the dark UI theme
+* [PR 8397](https://github.com/spyder-ide/spyder/pull/8397) - PR: Change handling of server host and port config placeholders ([7875](https://github.com/spyder-ide/spyder/issues/7875))
+* [PR 8396](https://github.com/spyder-ide/spyder/pull/8396) - PR: Start testing with Azure pipelines
+* [PR 8390](https://github.com/spyder-ide/spyder/pull/8390) - PR: Change method/function/class icons ([8386](https://github.com/spyder-ide/spyder/issues/8386))
+* [PR 8387](https://github.com/spyder-ide/spyder/pull/8387) - PR: Modify test_introspection to test module completion
+* [PR 8378](https://github.com/spyder-ide/spyder/pull/8378) - PR: Set right size of error dialog title field in macOS ([8344](https://github.com/spyder-ide/spyder/issues/8344))
+* [PR 8364](https://github.com/spyder-ide/spyder/pull/8364) - PR: Add dark background to the light theme buttons on macOS ([5907](https://github.com/spyder-ide/spyder/issues/5907))
+* [PR 8363](https://github.com/spyder-ide/spyder/pull/8363) - PR: Add close tab buttons to the light theme on macOS ([4580](https://github.com/spyder-ide/spyder/issues/4580))
+* [PR 8360](https://github.com/spyder-ide/spyder/pull/8360) - PR: Change creationflags to prevent showing a cmd for pyls ([8066](https://github.com/spyder-ide/spyder/issues/8066))
+* [PR 8357](https://github.com/spyder-ide/spyder/pull/8357) - PR: Improve Spyder Dark syntax highlighting theme ([8284](https://github.com/spyder-ide/spyder/issues/8284))
+* [PR 8351](https://github.com/spyder-ide/spyder/pull/8351) - PR: Improve robustness when starting pyls ([8159](https://github.com/spyder-ide/spyder/issues/8159))
+* [PR 8349](https://github.com/spyder-ide/spyder/pull/8349) - PR: Validation of dockwidget existence before raising it ([8283](https://github.com/spyder-ide/spyder/issues/8283))
+* [PR 8348](https://github.com/spyder-ide/spyder/pull/8348) - PR: Stop using ci-helpers to simplify testing
+* [PR 8347](https://github.com/spyder-ide/spyder/pull/8347) - PR: Do atomic writes when saving files ([8237](https://github.com/spyder-ide/spyder/issues/8237))
+* [PR 8342](https://github.com/spyder-ide/spyder/pull/8342) - PR: Transform texteditor title to unicode ([7930](https://github.com/spyder-ide/spyder/issues/7930))
+* [PR 8340](https://github.com/spyder-ide/spyder/pull/8340) - PR: Increase minimal QtAwesome version to 0.5.2 ([8330](https://github.com/spyder-ide/spyder/issues/8330))
+* [PR 8337](https://github.com/spyder-ide/spyder/pull/8337) - PR: Specify close_fds=False on Windows ([8013](https://github.com/spyder-ide/spyder/issues/8013))
+* [PR 8300](https://github.com/spyder-ide/spyder/pull/8300) - PR: Add qdarkstyle to dependencies dialog ([8291](https://github.com/spyder-ide/spyder/issues/8291))
+* [PR 8299](https://github.com/spyder-ide/spyder/pull/8299) - PR: Improve contributing guide
+* [PR 8276](https://github.com/spyder-ide/spyder/pull/8276) - PR: Add additional escape slashes instead of a raw string in runcell ([8267](https://github.com/spyder-ide/spyder/issues/8267))
+* [PR 8272](https://github.com/spyder-ide/spyder/pull/8272) - PR: Greatly simplify and clarify Github pull request template ([8270](https://github.com/spyder-ide/spyder/issues/8270))
+* [PR 8266](https://github.com/spyder-ide/spyder/pull/8266) - PR: Centralize theme-related preferences under an 'Appearance' entry ([8080](https://github.com/spyder-ide/spyder/issues/8080), [8071](https://github.com/spyder-ide/spyder/issues/8071))
+* [PR 8265](https://github.com/spyder-ide/spyder/pull/8265) - PR: Close scrollflag tests after they run
+* [PR 8257](https://github.com/spyder-ide/spyder/pull/8257) - PR: LSP fixes, debugging, and minor code cleanup ([8172](https://github.com/spyder-ide/spyder/issues/8172))
+* [PR 8251](https://github.com/spyder-ide/spyder/pull/8251) - PR: Make the internal console use the same theme as the other widgets ([8072](https://github.com/spyder-ide/spyder/issues/8072))
+* [PR 8245](https://github.com/spyder-ide/spyder/pull/8245) - PR: Fix quotes and traceback lines in runcell ([8244](https://github.com/spyder-ide/spyder/issues/8244), [8242](https://github.com/spyder-ide/spyder/issues/8242))
+* [PR 8243](https://github.com/spyder-ide/spyder/pull/8243) - PR : Fix for escaped string in runcell ([8241](https://github.com/spyder-ide/spyder/issues/8241))
+* [PR 8222](https://github.com/spyder-ide/spyder/pull/8222) - PR: Save last accepted kernel settings in config ([3689](https://github.com/spyder-ide/spyder/issues/3689))
+* [PR 8212](https://github.com/spyder-ide/spyder/pull/8212) - PR: Add system-specific shortcut names on macOS to the Shortcuts summary dialog ([7146](https://github.com/spyder-ide/spyder/issues/7146))
+* [PR 8202](https://github.com/spyder-ide/spyder/pull/8202) - PR: Mark some tests as slow and skip others that are failing locally
+* [PR 8201](https://github.com/spyder-ide/spyder/pull/8201) - PR: Missing dark style for QMenus, Tour, Pylint, Profiler and DataFrameEditor
+* [PR 8197](https://github.com/spyder-ide/spyder/pull/8197) - PR: Add parent reference to dialogs to ensure correct setup of the dark theme
+* [PR 8192](https://github.com/spyder-ide/spyder/pull/8192) - PR: Remove dockwidget title bars by default and improve dock/undock behavior ([8171](https://github.com/spyder-ide/spyder/issues/8171), [8011](https://github.com/spyder-ide/spyder/issues/8011), [5515](https://github.com/spyder-ide/spyder/issues/5515), [2855](https://github.com/spyder-ide/spyder/issues/2855), [2854](https://github.com/spyder-ide/spyder/issues/2854))
+* [PR 8158](https://github.com/spyder-ide/spyder/pull/8158) - PR: Fix font color in dark theme for several widgets
+* [PR 8104](https://github.com/spyder-ide/spyder/pull/8104) - PR: Hide plugins that do not have a layout ([7111](https://github.com/spyder-ide/spyder/issues/7111))
+* [PR 8086](https://github.com/spyder-ide/spyder/pull/8086) - PR: Add dark css for the Help and IPython Console plugins ([8087](https://github.com/spyder-ide/spyder/issues/8087))
+* [PR 8081](https://github.com/spyder-ide/spyder/pull/8081) - PR: Make all editor's background color to be applied correctly ([8069](https://github.com/spyder-ide/spyder/issues/8069))
+* [PR 8079](https://github.com/spyder-ide/spyder/pull/8079) - PR: Accept event if Shift+Tab is pressed in the CodeEditor keyPressEvent to avoid losing focus
+* [PR 8062](https://github.com/spyder-ide/spyder/pull/8062) - PR: Fix setting elapsed time for all consoles ([7751](https://github.com/spyder-ide/spyder/issues/7751))
+* [PR 8059](https://github.com/spyder-ide/spyder/pull/8059) - Variable Explorer: Use distinctive background for missings in DataFrames ([8037](https://github.com/spyder-ide/spyder/issues/8037))
+* [PR 8058](https://github.com/spyder-ide/spyder/pull/8058) - PR: Change the TODO checkmark ([2264](https://github.com/spyder-ide/spyder/issues/2264))
+* [PR 8044](https://github.com/spyder-ide/spyder/pull/8044) - PR: Fix error in LSP when closing file ([8043](https://github.com/spyder-ide/spyder/issues/8043))
+* [PR 8020](https://github.com/spyder-ide/spyder/pull/8020) - PR: Initial support for Spyder's dark theme
+* [PR 8015](https://github.com/spyder-ide/spyder/pull/8015) - PR: Add the option to sync file order between the Outline Explorer and the current EditorStack ([7993](https://github.com/spyder-ide/spyder/issues/7993))
+* [PR 8004](https://github.com/spyder-ide/spyder/pull/8004) - PR: Remove old code completion architecture ([7996](https://github.com/spyder-ide/spyder/issues/7996), [7963](https://github.com/spyder-ide/spyder/issues/7963))
+* [PR 7994](https://github.com/spyder-ide/spyder/pull/7994) - PR: Refactor LSP response callback communication ([7833](https://github.com/spyder-ide/spyder/issues/7833))
+* [PR 7992](https://github.com/spyder-ide/spyder/pull/7992) - PR: Add LSP client tests
+* [PR 7984](https://github.com/spyder-ide/spyder/pull/7984) - PR: Show the root file item of files that are not Python files in the Outline Explorer ([7982](https://github.com/spyder-ide/spyder/issues/7982))
+* [PR 7975](https://github.com/spyder-ide/spyder/pull/7975) - PR: Fix Go to definition feature in the Editor in Windows after the changes introduced with the new LSP ([7726](https://github.com/spyder-ide/spyder/issues/7726))
+* [PR 7968](https://github.com/spyder-ide/spyder/pull/7968) - PR: Sync Outline Explorer at startup and preserve the file order in the tabbar ([7338](https://github.com/spyder-ide/spyder/issues/7338))
+* [PR 7962](https://github.com/spyder-ide/spyder/pull/7962) - PR: Improvement to navigation and file switching in the Outline Explorer ([7214](https://github.com/spyder-ide/spyder/issues/7214))
+* [PR 7954](https://github.com/spyder-ide/spyder/pull/7954) - PR: Improve how keyboard shortcuts are handled in the Editor (Take 2) ([7883](https://github.com/spyder-ide/spyder/issues/7883))
+* [PR 7929](https://github.com/spyder-ide/spyder/pull/7929) - PR: Improve the Shortcut Editor and fix and extend emacs shortcut support ([7883](https://github.com/spyder-ide/spyder/issues/7883), [7854](https://github.com/spyder-ide/spyder/issues/7854), [7109](https://github.com/spyder-ide/spyder/issues/7109))
+* [PR 7927](https://github.com/spyder-ide/spyder/pull/7927) - PR: Convert and optimize tutorial PNGs and profiler/pylint icons
+* [PR 7914](https://github.com/spyder-ide/spyder/pull/7914) - PR: Have a choice between password or keyfile in "Connect to remote kernel" dialog ([7905](https://github.com/spyder-ide/spyder/issues/7905))
+* [PR 7876](https://github.com/spyder-ide/spyder/pull/7876) - PR: Reinitialize Pylab, Sympy and Cython after clearing all variables ([7224](https://github.com/spyder-ide/spyder/issues/7224))
+* [PR 7874](https://github.com/spyder-ide/spyder/pull/7874) - PR: Correct next/previous word shortcut callback in Spyder 4 ([7872](https://github.com/spyder-ide/spyder/issues/7872))
+* [PR 7866](https://github.com/spyder-ide/spyder/pull/7866) - PR: Add OneColumnTree context menu item to the plugins that use it in their Options menu ([7865](https://github.com/spyder-ide/spyder/issues/7865), [7865](https://github.com/spyder-ide/spyder/issues/7865), [7235](https://github.com/spyder-ide/spyder/issues/7235))
+* [PR 7852](https://github.com/spyder-ide/spyder/pull/7852) - PR: Remove '--cov-report=term-missing' from pytest args
+* [PR 7835](https://github.com/spyder-ide/spyder/pull/7835) - PR: Refactor test_autoindent.py to make the pytest logs cleaner
+* [PR 7827](https://github.com/spyder-ide/spyder/pull/7827) - PR: Legal, standards conformance and consistency modifications to headers and EOF/EOL
+* [PR 7826](https://github.com/spyder-ide/spyder/pull/7826) - PR: Conform short dates dates to be properly ISO 8601
+* [PR 7822](https://github.com/spyder-ide/spyder/pull/7822) - PR: Add pyls as a new dependency
+* [PR 7799](https://github.com/spyder-ide/spyder/pull/7799) - PR: Remove file from the outline explorer when it is closed ([7798](https://github.com/spyder-ide/spyder/issues/7798))
+* [PR 7789](https://github.com/spyder-ide/spyder/pull/7789) - PR: Add "find_replace" widget to qtbot in fixtures of "test_editor.py"
+* [PR 7768](https://github.com/spyder-ide/spyder/pull/7768) - PR: Improve how keyboard shortcuts are handled in the Editor ([7743](https://github.com/spyder-ide/spyder/issues/7743))
+* [PR 7758](https://github.com/spyder-ide/spyder/pull/7758) - PR: Fix saving a new file or renaming an existing file in master ([7754](https://github.com/spyder-ide/spyder/issues/7754))
+* [PR 7745](https://github.com/spyder-ide/spyder/pull/7745) - PR: Make the "Go to cursor position" button of the outline explorer work also when the cursor is in the last item of the Editor ([7744](https://github.com/spyder-ide/spyder/issues/7744))
+* [PR 7738](https://github.com/spyder-ide/spyder/pull/7738) - PR: Make Group cells setting persistent when restarting spyder ([7736](https://github.com/spyder-ide/spyder/issues/7736))
+* [PR 7734](https://github.com/spyder-ide/spyder/pull/7734) - PR: Replace debug_print for the logging module and deprecate its use ([5326](https://github.com/spyder-ide/spyder/issues/5326))
+* [PR 7730](https://github.com/spyder-ide/spyder/pull/7730) - PR: Add a "get_cursor_line_number" method to OutlineExplorerProxyEditor ([7729](https://github.com/spyder-ide/spyder/issues/7729))
+* [PR 7725](https://github.com/spyder-ide/spyder/pull/7725) - PR: Split all plugins into their own modules ([4591](https://github.com/spyder-ide/spyder/issues/4591))
+* [PR 7714](https://github.com/spyder-ide/spyder/pull/7714) - PR: Fix variable explorer actions are disabled when undocked in a new window
+* [PR 7710](https://github.com/spyder-ide/spyder/pull/7710) - PR: Fix cog menu not showing in the variable explorer when more than one IPython console is opened ([7704](https://github.com/spyder-ide/spyder/issues/7704))
+* [PR 7698](https://github.com/spyder-ide/spyder/pull/7698) - PR: Show normalized paths in "Create Project" dialog ([7518](https://github.com/spyder-ide/spyder/issues/7518))
+* [PR 7660](https://github.com/spyder-ide/spyder/pull/7660) - PR: Implement an autosave and recover system in the Editor ([2111](https://github.com/spyder-ide/spyder/issues/2111))
+* [PR 7310](https://github.com/spyder-ide/spyder/pull/7310) - PR: Run cells through a function instead of pasting their contents to the console ([7760](https://github.com/spyder-ide/spyder/issues/7760), [7113](https://github.com/spyder-ide/spyder/issues/7113))
+* [PR 6791](https://github.com/spyder-ide/spyder/pull/6791) - PR: Final update to split-plugins
+* [PR 6679](https://github.com/spyder-ide/spyder/pull/6679) - PR: Update split-plugins branch with master (take 3)
+* [PR 6430](https://github.com/spyder-ide/spyder/pull/6430) - PR: Add a Plots plugin to browse figures generated by the IPython console ([2550](https://github.com/spyder-ide/spyder/issues/2550))
+* [PR 5764](https://github.com/spyder-ide/spyder/pull/5764) - PR: Handle namespace browser column width ([5543](https://github.com/spyder-ide/spyder/issues/5543))
+* [PR 5676](https://github.com/spyder-ide/spyder/pull/5676) - PR: Change word highlighting to support dot notation ([1634](https://github.com/spyder-ide/spyder/issues/1634))
+* [PR 5438](https://github.com/spyder-ide/spyder/pull/5438) - PR: Merge translations from former external plugins
+* [PR 5283](https://github.com/spyder-ide/spyder/pull/5283) - PR: Add a debugger panel ([8560](https://github.com/spyder-ide/spyder/issues/8560))
+* [PR 5276](https://github.com/spyder-ide/spyder/pull/5276) - PR: Move external plugins inside the main package again
+* [PR 5263](https://github.com/spyder-ide/spyder/pull/5263) - PR: Revert change of name for Variable Explorer editors
+* [PR 5219](https://github.com/spyder-ide/spyder/pull/5219) - PR: Split Working Directory module
+* [PR 5216](https://github.com/spyder-ide/spyder/pull/5216) - PR: Move preferences out of the plugins module
+* [PR 5214](https://github.com/spyder-ide/spyder/pull/5214) - PR: Split Projects module
+* [PR 5207](https://github.com/spyder-ide/spyder/pull/5207) - PR: Split Internal Console module
+* [PR 5206](https://github.com/spyder-ide/spyder/pull/5206) - PR: Split IPython Console module
+* [PR 4975](https://github.com/spyder-ide/spyder/pull/4975) - PR: Split Editor module
+* [PR 4974](https://github.com/spyder-ide/spyder/pull/4974) - PR: Split Explorer module
+* [PR 4812](https://github.com/spyder-ide/spyder/pull/4812) - PR: Split Outline explorer module
+* [PR 4772](https://github.com/spyder-ide/spyder/pull/4772) - PR: Merge master into split-plugins
+* [PR 4751](https://github.com/spyder-ide/spyder/pull/4751) - PR: Migrate introspection services to use the Language Server Protocol (LSP) ([4742](https://github.com/spyder-ide/spyder/issues/4742))
+* [PR 4593](https://github.com/spyder-ide/spyder/pull/4593) - PR: Split History module
+* [PR 4569](https://github.com/spyder-ide/spyder/pull/4569) - PR: Split Find in Files module
+* [PR 4565](https://github.com/spyder-ide/spyder/pull/4565) - PR: Split Online Help module
+* [PR 4557](https://github.com/spyder-ide/spyder/pull/4557) - PR: Split Variable Explorer module
+* [PR 4548](https://github.com/spyder-ide/spyder/pull/4548) - PR: Split Help plugin
+
+In this release 246 pull requests were closed.
+
+
+----
+
+
+## Version 4.0beta1 (2018-08-12)
+
+### Issues Closed
+
+* [Issue 7078](https://github.com/spyder-ide/spyder/issues/7078) - Shortcuts to open pylab and sympy consoles ([PR 7099](https://github.com/spyder-ide/spyder/pull/7099))
+* [Issue 6516](https://github.com/spyder-ide/spyder/issues/6516) - AttributeError in jedi_plugin.py:102 ([PR 6523](https://github.com/spyder-ide/spyder/pull/6523))
+* [Issue 6474](https://github.com/spyder-ide/spyder/issues/6474) - test_completions_custom_path fails with jedi 0.9.0 (Spyder 4) ([PR 6497](https://github.com/spyder-ide/spyder/pull/6497))
+* [Issue 5821](https://github.com/spyder-ide/spyder/issues/5821) - Outline Explorer: disable `if/else/try/for` statements ([PR 5842](https://github.com/spyder-ide/spyder/pull/5842))
+* [Issue 5763](https://github.com/spyder-ide/spyder/issues/5763) - Make arrow-key selection in multiple-option tab-completion dialogs "roll over" ([PR 5771](https://github.com/spyder-ide/spyder/pull/5771))
+* [Issue 5756](https://github.com/spyder-ide/spyder/issues/5756) - Ctrl-PageUp/Down does not go through tabs in Spyder 4.x
+* [Issue 5721](https://github.com/spyder-ide/spyder/issues/5721) - Update obsolete QMessageBox Standard Button values ([PR 5722](https://github.com/spyder-ide/spyder/pull/5722))
+* [Issue 5711](https://github.com/spyder-ide/spyder/issues/5711) - "Show blank spaces" with split view editor
+* [Issue 5678](https://github.com/spyder-ide/spyder/issues/5678) - Fix Indentation always uses 4 spaces instead of the selected number of spaces ([PR 6063](https://github.com/spyder-ide/spyder/pull/6063))
+* [Issue 5667](https://github.com/spyder-ide/spyder/issues/5667) - Strange font rendering in the splash ([PR 5706](https://github.com/spyder-ide/spyder/pull/5706))
+* [Issue 5652](https://github.com/spyder-ide/spyder/issues/5652) - Improved dependency dialog ([PR 5691](https://github.com/spyder-ide/spyder/pull/5691))
+* [Issue 5639](https://github.com/spyder-ide/spyder/issues/5639) - Use argparse instead of optparse ([PR 5689](https://github.com/spyder-ide/spyder/pull/5689))
+* [Issue 5594](https://github.com/spyder-ide/spyder/issues/5594) - Right-clicking in empty Project Explorer shows error ([PR 5603](https://github.com/spyder-ide/spyder/pull/5603))
+* [Issue 5488](https://github.com/spyder-ide/spyder/issues/5488) - Code style (pep8) toggle in source menu ([PR 5497](https://github.com/spyder-ide/spyder/pull/5497))
+* [Issue 5486](https://github.com/spyder-ide/spyder/issues/5486) - Spyder crash when dragging a plugin with the mouse ([PR 5487](https://github.com/spyder-ide/spyder/pull/5487))
+* [Issue 5458](https://github.com/spyder-ide/spyder/issues/5458) - Can't indent code blocks more than once (using tab) on Spyder 4 ([PR 5468](https://github.com/spyder-ide/spyder/pull/5468))
+* [Issue 5454](https://github.com/spyder-ide/spyder/issues/5454) - Toggle comment (ctrl+1) does not always preserve indentation with 2 spaces ([PR 5470](https://github.com/spyder-ide/spyder/pull/5470))
+* [Issue 5365](https://github.com/spyder-ide/spyder/issues/5365) - Add "Save all files with
+[](https://github.com/spyder-ide/spyder)
[](https://travis-ci.org/spyder-ide/spyder)
-[](https://ci.appveyor.com/project/spyder-ide/spyder/branch/master)
[](https://circleci.com/gh/spyder-ide/spyder)
+[](https://dev.azure.com/spyder-ide/spyder/_build/latest?definitionId=1?branchName=master)
[](https://coveralls.io/github/spyder-ide/spyder?branch=master)
[](https://codecov.io/gh/spyder-ide/spyder)
-[](https://github.com/spyder-ide/spyder)
-
+
----
-## Important Announcement: Spyder needs your support!
+## Help support Spyder, the community-developed scientific IDE!
-Since mid-November 2017, [Anaconda, Inc](https://www.anaconda.com/) has
-stopped funding Spyder development, after doing so for the past 18
-months. Therefore, without additional funds, development will shift to
-maintaining Spyder 3 at a slower pace than before, while working
-toward an eventual Spyder 4 feature release sometime in the future.
+Thanks to your continuing support, we are on track for a
+Spyder 4 release in early 2019 with all of your most-requested features
+(a new debugger and completion architecture, better Projects, new Editor
+functionality, full Variable Explorer object support, a built-in dark theme
+and [much more](https://github.com/spyder-ide/spyder/wiki/Roadmap))!
-However, with your contribution of effort and funding, we will be able to
-both continue to maintain Spyder 3 at a faster pace, and fund development of
-new features for Spyder 4 (such as a major overhaul to improve
-code completion, and a much-improved new debugger, both of which you've been
-requesting) at a greatly accelerated rate.
-
-There are many ways to [help with development](
+Spyder development is made possible by contributions from our global user
+community, along with organizations like [NumFOCUS](https://www.numfocus.org)
+and [Quansight](https://www.quansight.com).
+There are numerous [ways you can help](
https://github.com/spyder-ide/spyder/wiki/Contributing-to-Spyder), many of
-which don't require any programming, and if you're able to make a
-financial contribution to help support your favorite community IDE, you can
-donate through our [OpenCollective](https://opencollective.com/spyder).
+which don't require any programming. If you'd like to make a [donation](
+https://opencollective.com/spyder/donate) to help fund further improvements,
+we're on [OpenCollective](https://opencollective.com/spyder).
-We appreciate all the help you can provide us and can't thank you enough for
-supporting the work of the Spyder devs and Spyder development! To learn more
-about the current situation and our future plans, please read this [page](
-https://github.com/spyder-ide/spyder/wiki/Anaconda-stopped-funding-Spyder).
+Thanks for all you do to make the Spyder project thrive! [More details](
+https://github.com/spyder-ide/spyder/wiki/Current-Funding-and-Development-Status)
----
@@ -107,14 +104,14 @@ https://www.spyder-ide.org/).
## Documentation
-You can read the Spyder documentation online at [PythonHosted](
-http://pythonhosted.org/spyder/).
+You can read the Spyder documentation online on [the Spyder Docs website](
+https://docs.spyder-ide.org/).
## Installation
For a detailed guide to installing Spyder, please refer to our
-[installation instructions](http://pythonhosted.org/spyder/installation.html).
+[installation instructions](https://docs.spyder-ide.org/installation.html).
The easiest way to install Spyder on any of our supported platforms
is to download it as part of the [Anaconda](https://www.anaconda.com/download/)
@@ -129,7 +126,7 @@ able to provide limited assistance if you do run into trouble.
Other install options exist, including:
* The [WinPython](https://winpython.github.io/) distribution for Windows
-* The [MacPorts](http://www.macports.org/) project for macOS
+* The [MacPorts](https://www.macports.org/) project for macOS
* Your distribution's package manager (i.e. `apt-get`, `yum`, etc) on Linux
* The `pip` package manager, included with most Python installations
@@ -148,13 +145,33 @@ are either duplicates, or can be fixed on the user side with a few easy steps.
Thanks!
-## Contributing
+## Contributing and Credits
+
+Spyder was originally created by [Pierre Raybaut](
+https://github.com/PierreRaybaut), and is currently maintained by
+[Carlos Córdoba](https://github.com/ccordoba12) and an international
+community of volunteers.
-Everyone is welcome to help with Spyder. Please read our
-[contributing instructions](
+You can join us—everyone is welcome to help with Spyder!
+Please read our [contributing instructions](
https://github.com/spyder-ide/spyder/blob/master/CONTRIBUTING.md)
to get started!
+Certain source files are distributed under other compatible permissive licenses
+and/or originally by other authors.
+The icons for the Spyder 3 theme are derived from [Font Awesome](
+https://fontawesome.com/) 4.7 (© 2016 David Gandy; SIL OFL 1.1).
+Most Spyder 2 theme icons are sourced from the [Crystal Project icon set](
+https://www.everaldo.com) (© 2006-2007 Everaldo Coelho; LGPL 2.1+).
+Other Spyder 2 icons are from [Yusuke Kamiyamane](
+http://p.yusukekamiyamane.com/) (© 2013 Yusuke Kamiyamane; CC-BY 3.0),
+the [FamFamFam Silk icon set](http://www.famfamfam.com/lab/icons/silk/)
+(© 2006 Mark James; CC-BY 2.5), and the [KDE Oxygen icons](
+https://www.kde.org/) (© 2007 KDE Artists; LGPL 3.0+).
+
+See [NOTICE.txt](https://github.com/spyder-ide/spyder/blob/master/NOTICE.txt)
+for full legal information.
+
## Running from a Github clone
@@ -167,7 +184,7 @@ they are officially released.
If using `conda` (strongly recommended), this can be done by running the
following from the command line (the Anaconda Prompt, if on Windows):
-```
+```bash
conda install spyder
conda remove spyder
git clone https://github.com/spyder-ide/spyder.git
@@ -175,19 +192,29 @@ cd spyder
python bootstrap.py
```
-Alternatively, you can use `pip` to install PyQt5 separately and
-the other *runtime dependencies* listed below. However, beware:
+You also need to make sure the correct `spyder-kernels` version is installed
+for the version of Spyder you are testing. The above procedure will give you
+`spyder-kernels` 0.x for the `3.x` branch (Spyder 3),
+so to run the `master` branch (Spyder 4) you need to additionally execute:
+
+```bash
+conda install -c spyder-ide spyder-kernels=1.*
+```
+
+Alternatively, you can use `pip` to install PyQt5 and the other
+*runtime dependencies* listed below. However, beware:
this method is recommended for experts only, and you'll need to solve any
-problems on your own. See the
-[installation instructions](http://pythonhosted.org/spyder/installation.html)
-for more details.
+problems on your own.
+
+See the [installation instructions](
+https://docs.spyder-ide.org/installation.html) for more details on all of this.
## Dependencies
**Important Note**: Most or all of the dependencies listed below come
with *Anaconda* and other scientific Python distributions, so you don't need
-to install them seperatly in those cases.
+to install them separately in those cases.
### Build dependencies
@@ -197,29 +224,32 @@ a Python version greater than 2.7 or 3.4 (Python <=3.3 is no longer supported).
### Runtime dependencies
* **Python** 2.7 or 3.4+: The core language Spyder is written in and for.
-* **PyQt5** 5.2+: Python bindings for Qt, used for Spyder's GUI.
+* **PyQt5** 5.6+: Python bindings for Qt, used for Spyder's GUI.
* **qtconsole** 4.2.0+: Enhanced Python interpreter.
-* **Rope** 0.9.4+ and **Jedi** 0.11.0+: Editor code completion, calltips
- and go-to-definition.
-* **Pyflakes**: Real-time code analysis.
+* **Python-language-server**: Editor code completion, calltips
+ go-to-definition and real-time code analysis
* **Sphinx**: Rich text mode for the Help pane.
* **Pygments** 2.0+: Syntax highlighting for all file types it supports.
* **Pylint**: Static code analysis.
-* **Pycodestyle**: Real-time code style analysis.
* **Psutil**: CPU and memory usage on the status bar.
* **Nbconvert**: Manipulation of notebooks in the Editor.
-* **Qtawesome** 0.4.1+: To have an icon theme based on FontAwesome.
+* **Qtawesome** 0.5.7+: To have an icon theme based on FontAwesome.
* **Pickleshare**: Show import completions on the Python consoles.
-* **PyZMQ**: Run introspection services asynchronously.
-* **QtPy** 1.2.0+: Abstraction layer for Python Qt bindings so that Spyder
+* **PyZMQ**: Client for the language server protocol (LSP).
+* **QtPy** 1.5.0+: Abstraction layer for Python Qt bindings so that Spyder
can run on multiple Qt bindings and versions.
* **Chardet**: Character encoding auto-detection in Python.
* **Numpydoc**: Used by Jedi to get function return types from Numpydocstrings.
* **Cloudpickle**: Serialize variables in the IPython kernel to send to Spyder.
+* **spyder-kernels** 1.2.0+: Jupyter kernels for the Spyder console.
+* **keyring**: Save Github credentials to report errors securely.
+* **QDarkStyle** 2.6.4+: A dark stylesheet for Qt applications, used for Spyder's dark theme.
+* **atomicwrites**: Atomic file writes.
+* **pexpect**/**paramiko**: Connect to remote kernels through SSH.
### Optional dependencies
-* **Matplotlib**: 2D/3D plotting in the Python and IPython consoles.
+* **Matplotlib**: 2D/3D plotting in the IPython console.
* **Pandas**: View and edit DataFrames and Series in the Variable Explorer.
* **Numpy**: View and edit 2- or 3-dimensional arrays in the Variable Explorer.
* **SymPy**: Symbolic mathematics in the IPython console.
@@ -227,16 +257,15 @@ a Python version greater than 2.7 or 3.4 (Python <=3.3 is no longer supported).
* **Cython**: Run Cython files in the IPython console.
-## Backers
+## Sponsors
-Support us with a monthly donation and help us continue our activities.
+Spyder is funded thanks to the generous support of
-[](https://opencollective.com/spyder#support)
+[](https://www.quansight.com/)[](https://numfocus.org/)
-## Sponsors
-Become a sponsor to get your logo on our README on Github.
+and the donations we have received from our users around the world through [Open Collective](https://opencollective.com/spyder/):
[](https://opencollective.com/spyder#support)
@@ -247,6 +276,8 @@ Become a sponsor to get your logo on our README on Github.
[Download Spyder (with Anaconda)](https://www.anaconda.com/download/)
+[Online Documentation](https://docs.spyder-ide.org/)
+
[Spyder Github](https://github.com/spyder-ide/spyder)
[Troubleshooting Guide and FAQ](
@@ -256,7 +287,7 @@ https://github.com/spyder-ide/spyder/wiki/Troubleshooting-Guide-and-FAQ)
[Gitter Chatroom](https://gitter.im/spyder-ide/public)
-[Google Group](http://groups.google.com/group/spyderlib)
+[Google Group](https://groups.google.com/group/spyderlib)
[@Spyder_IDE on Twitter](https://twitter.com/spyder_ide)
diff --git a/RELEASE.md b/RELEASE.md
index 63e8eb94a33..8a21599632e 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -4,21 +4,23 @@ To release a new version of Spyder you need to follow these steps:
* git pull or git fetch/merge
-* git clean -xfdi
-
* Update CHANGELOG.md
* Update Announcements.md
+* git clean -xfdi
+
* Update version in `__init__.py` (set release version, remove 'dev0')
* git add and git commit with `Release X.X.X`
-* python setup.py sdist upload
+* python setup.py sdist
-* activate py2env-with-latest-setuptools && python2 setup.py bdist_wheel upload
+* activate py2env-with-latest-setuptools && python2 setup.py bdist_wheel
-* activate py3env-with-latest-setuptools && python3 setup.py bdist_wheel upload
+* activate py3env-with-latest-setuptools && python3 setup.py bdist_wheel
+
+* twine upload dist/*
* git tag -a vX.X.X -m 'Release X.X.X'
@@ -38,13 +40,6 @@ To release a new version of Spyder you need to follow these steps:
* git push upstream --tags
-* Optional: Create conda packages
- - conda build conda.recipe
- - anaconda upload spyder-*.tar.bz2 -u spyder-ide
-
* Publish release announcements to our list and the SciPy list
-* Publish list of bugs and merged pull requests to our Github Releases page
-
-* Create DMGs, upload them to our Bitbucket Downloads page and link them
- in our Github Releases page.
+* Publish release in our Github Releases page
diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md
index e8556cb4a7f..707bdd3f7f1 100644
--- a/TROUBLESHOOTING.md
+++ b/TROUBLESHOOTING.md
@@ -3,7 +3,7 @@ Spyder Troubleshooting Guide
For an up to date, more comprehensive version of this guide, covering
solutions to specific commonly reported issues along with these more general
-troubleshooting strategies, please refer to:
+troubleshooting strategies, please refer to
The Scientific PYthon Development EnviRonment
-
Copyright © The Spyder Project Contributors
-
Licensed under the terms of the MIT License
-
Developed and maintained by the
- Spyder Project Contributors.
-
Many thanks to all the Spyder beta testers and regular users.
+
+ # Get current font properties
+ font = self.font()
+ font_family = font.family()
+ font_size = font.pointSize()
+ if sys.platform == 'darwin':
+ font_size -= 2
+
+ msgBox = QMessageBox(self)
+ msgBox.setText(
+ """
+
+ The Scientific Python Development Environment |
+ Spyder-IDE.org
+
+ Copyright © 2009-2019 Spyder Project Contributors and
+ others.
+
+ Distributed under the terms of the
+ MIT License.
+
"
"For that, please close this window and start Spyder again.")
- CONF.set('main', 'icon_theme', 'spyder 2')
+ CONF.set('appearance', 'icon_theme', 'spyder 2')
except BaseException:
CONF.set('main', 'crash', True)
import traceback
diff --git a/spyder/app/start.py b/spyder/app/start.py
index bde5380354a..477a1ce8e1f 100644
--- a/spyder/app/start.py
+++ b/spyder/app/start.py
@@ -1,6 +1,13 @@
# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
-# Std imports
+
+# Standard library imports
import ctypes
import os
import os.path as osp
@@ -31,7 +38,7 @@
def send_args_to_spyder(args):
"""
- Simple socket client used to send the args passed to the Spyder
+ Simple socket client used to send the args passed to the Spyder
executable to an already running instance.
Args can be Python scripts or files with these extensions: .spydata, .mat,
@@ -40,7 +47,7 @@ def send_args_to_spyder(args):
port = CONF.get('main', 'open_files_port')
# Wait ~50 secs for the server to be up
- # Taken from http://stackoverflow.com/a/4766598/438386
+ # Taken from https://stackoverflow.com/a/4766598/438386
for _x in range(200):
try:
for arg in args:
@@ -75,6 +82,7 @@ def main():
options = Mock()
options.new_instance = False
options.reset_config_files = False
+ options.debug_info = None
args = None
else:
options, args = get_options()
@@ -97,8 +105,8 @@ def main():
os.environ['QT_SCALE_FACTOR'] = ''
os.environ['QT_SCREEN_SCALE_FACTORS'] = ''
- # Prevent Spyder from crashing in macOS if locale is not defined
if sys.platform == 'darwin':
+ # Prevent Spyder from crashing in macOS if locale is not defined
LANG = os.environ.get('LANG')
LC_ALL = os.environ.get('LC_ALL')
if bool(LANG) and not bool(LC_ALL):
@@ -111,6 +119,29 @@ def main():
os.environ['LANG'] = LANG
os.environ['LC_ALL'] = LC_ALL
+ # Don't show useless warning in the terminal where Spyder
+ # was started
+ # See issue 3730
+ os.environ['EVENT_NOKQUEUE'] = '1'
+ else:
+ # Prevent our kernels to crash when Python fails to identify
+ # the system locale.
+ # Fixes issue 7051.
+ try:
+ from locale import getlocale
+ getlocale()
+ except ValueError:
+ # This can fail on Windows. See issue 6886
+ try:
+ os.environ['LANG'] = 'C'
+ os.environ['LC_ALL'] = 'C'
+ except Exception:
+ pass
+
+ if options.debug_info:
+ levels = {'minimal': '2', 'verbose': '3'}
+ os.environ['SPYDER_DEBUG'] = levels[options.debug_info]
+
if CONF.get('main', 'single_instance') and not options.new_instance \
and not options.reset_config_files and not running_in_mac_app():
# Minimal delay (0.1-0.2 secs) to avoid that several
diff --git a/spyder/app/tests/script.py b/spyder/app/tests/script.py
index 1807cb5183d..b23a7a9e78b 100644
--- a/spyder/app/tests/script.py
+++ b/spyder/app/tests/script.py
@@ -1,10 +1,14 @@
-#%%
+# %% first Code Cell's name
a = 10
+"Hello"
-
-#%%
+# In[23]
li = [1, 2, 3]
-#%%
+#
pip
to "
"update it as that will probably break your installation.conda
to perform the update.conda"
+"code> to perform the update.
"
msgstr ""
-"
WICHTIGER HINWEIS: Es scheint, dass Sie Spyder mit "
-"Anaconda/Miniconda verwenden. Bitte verwenden Sie nicht "
-"pip
, um es zu aktualisieren, da es wahrscheinlich Ihre "
-"Installation zerreißen wird.
Stattdessen warten Sie bitte, bis neue "
-"conda-Pakete verfügbar sind und verwenden Sie conda
, um die "
-"Aktualisierung durchzuführen.
"
+"
WICHTIGER HINWEIS: Es scheint, dass Sie Spyder mit Anaconda/"
+"Miniconda verwenden. Bitte verwenden Sie nicht pip
, "
+"um es zu aktualisieren, da es wahrscheinlich Ihre Installation zerreißen "
+"wird.
Stattdessen warten Sie bitte, bis neue conda-Pakete verfügbar "
+"sind und verwenden Sie conda
, um die Aktualisierung "
+"durchzuführen.
"
-#: spyder/app/mainwindow.py:2771
+#: spyder/app/mainwindow.py:3003
msgid ""
"Spyder %s is available!
Please use your package manager to "
"update Spyder or go to our Releases page to download this "
@@ -589,13 +636,13 @@ msgid ""
"please refer to our Installation instructions."
msgstr ""
"Spyder %s ist verfügbar!
Bitte benutzen Sie Ihren "
-"Paketmanager, um Spyder zu aktualisieren oder gehen Sie auf unsere Veröffentlichungsseite, um diese neue Version "
-"herunterzuladen.
Wenn Sie sich nicht sicher sind, wie Sie Spyder "
-"aktualisieren sollen, verweisen wir Sie auf unsere Installationsanweisungen."
+"Paketmanager, um Spyder zu aktualisieren oder gehen Sie auf unsere Veröffentlichungsseite, um diese neue Version herunterzuladen. "
+"
Wenn Sie sich nicht sicher sind, wie Sie Spyder aktualisieren "
+"sollen, verweisen wir Sie auf unsere Installationsanweisungen."
-#: spyder/app/mainwindow.py:2784
+#: spyder/app/mainwindow.py:3016
msgid "Spyder is up to date."
msgstr "Spyder ist auf dem neuesten Stand."
@@ -636,15 +683,15 @@ msgstr "Spyder Zurücksetzungsfehler"
msgid "Spyder restart error"
msgstr "Spyder-Neustartfehler"
-#: spyder/app/restart.py:176
+#: spyder/app/restart.py:183
msgid "Closing Spyder"
msgstr "Spyder wird geschlossen"
-#: spyder/app/restart.py:250
+#: spyder/app/restart.py:257
msgid "Resetting Spyder to defaults"
msgstr "Spyder wird auf die Standardeinstellungen zurückgesetzt"
-#: spyder/app/restart.py:282
+#: spyder/app/restart.py:289
msgid "Restarting"
msgstr "Neustartvorgang"
@@ -684,9 +731,9 @@ msgstr ""
"eingegebenen Text drücken
Der Editor kommt mit einem "
"Zeilennummernbereich (hier rot markiert), wo Spyder Warnungen und "
"Syntaxfehler anzeigt. Diese können Ihnen helfen, potenzielle Probleme zu "
-"erkennen, bevor Sie den Code ausführen.
Sie können auch "
-"Debug-Haltepunkte im Zeilennummernbereich festlegen, indem Sie einen "
-"Doppelklick neben einer nicht leeren Zeile machen."
+"erkennen, bevor Sie den Code ausführen.
Sie können auch Debug-"
+"Haltepunkte im Zeilennummernbereich festlegen, indem Sie einen Doppelklick "
+"neben einer nicht leeren Zeile machen."
#: spyder/app/tour.py:149
msgid "The IPython console"
@@ -718,11 +765,11 @@ msgstr "Der Variablenmanager"
#: spyder/app/tour.py:167
msgid ""
"In this pane you can view and edit the variables generated during the "
-"execution of a program, or those entered directly in one of Spyder "
-"consoles.
As you can see, the Variable Explorer is showing the "
-"variables generated during the last step of this tour. By doing a "
-"double-click on any of them, a new window will be opened, where you can "
-"inspect and modify their contents."
+"execution of a program, or those entered directly in one of Spyder consoles."
+"
As you can see, the Variable Explorer is showing the variables "
+"generated during the last step of this tour. By doing a double-click on any "
+"of them, a new window will be opened, where you can inspect and modify their "
+"contents."
msgstr ""
"In diesem Bereich können Sie die bei der Ausführung eines Programms "
"erzeugten Variablen oder die direkt in einer der Spyder-Konsolen "
@@ -732,8 +779,8 @@ msgstr ""
"von diesen machen, wird ein neues Fenster geöffnet, in dem Sie den Inhalt "
"überprüfen und ändern können."
-#: spyder/app/tour.py:179 spyder/plugins/help.py:476
-#: spyder/plugins/help.py:916 spyder/widgets/internalshell.py:270
+#: spyder/app/tour.py:179 spyder/plugins/help.py:482 spyder/plugins/help.py:931
+#: spyder/widgets/internalshell.py:271
msgid "Help"
msgstr "Hilfe"
@@ -745,10 +792,10 @@ msgid ""
"has some documentation associated with it, it will be displayed here."
msgstr ""
"In diesem Bereich wird die Dokumentation der Funktionen, Klassen, Methoden "
-"oder Module angezeigt, die Sie derzeit im Editor oder den Konsolen "
-"verwenden.
Um es zu benutzen, müssen Sie Strg+I vor einem "
-"Objekt drücken. Wenn dieses Objekt mit einer Dokumentation verknüpft ist, "
-"wird diese hier angezeigt."
+"oder Module angezeigt, die Sie derzeit im Editor oder den Konsolen verwenden."
+"
Um es zu benutzen, müssen Sie Strg+I vor einem Objekt "
+"drücken. Wenn dieses Objekt mit einer Dokumentation verknüpft ist, wird "
+"diese hier angezeigt."
#: spyder/app/tour.py:190
msgid "The File Explorer"
@@ -765,8 +812,8 @@ msgstr ""
"In diesem Bereich können Sie durch die auf Ihrem Computer vorhandenen "
"Verzeichnisse und Dateien navigieren.
Sie können auch eine dieser "
"Dateien mit der zugehörigen Anwendung öffnen, indem Sie einen Doppelklick "
-"darauf machen.
Es gibt eine Ausnahme von dieser Regel: "
-"Klartext-Dateien werden immer im Spyder-Editor geöffnet."
+"darauf machen.
Es gibt eine Ausnahme von dieser Regel: Klartext-"
+"Dateien werden immer im Spyder-Editor geöffnet."
#: spyder/app/tour.py:201
msgid "The History Log"
@@ -800,220 +847,216 @@ msgstr "Einführungstour"
msgid "New features in version 3.0"
msgstr "Neue Funktionen in Version 3.0"
-#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:445
+#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:474
msgid "Run code"
msgstr "Code ausführen"
#: spyder/app/tour.py:830
msgid "Go to step: "
-msgstr "Gehe zu Schritt:"
-
-#: spyder/config/base.py:260
-msgid ""
-"Update LANGUAGE_CODES (inside config/base.py) if a new translation has been "
-"added to Spyder"
-msgstr ""
-"Aktualisieren Sie die LANGUAGE_CODES (in config/base.py), wenn eine neue "
-"Übersetzung zu Spyder hinzugefügt wurde"
+msgstr "Gehe zu Schritt: "
-#: spyder/config/utils.py:24
+#: spyder/config/utils.py:24 spyder/plugins/pylint/widgets/pylintgui.py:289
msgid "Python files"
msgstr "Python-Dateien"
-#: spyder/config/utils.py:25
+#: spyder/config/utils.py:26
msgid "Cython/Pyrex files"
msgstr "Cython/Pyrex-Dateien"
-#: spyder/config/utils.py:26
+#: spyder/config/utils.py:27
msgid "C files"
msgstr "C-Dateien"
-#: spyder/config/utils.py:27
+#: spyder/config/utils.py:28
msgid "C++ files"
msgstr "C++-Dateien"
-#: spyder/config/utils.py:28
+#: spyder/config/utils.py:29
msgid "OpenCL files"
msgstr "OpenCL-Dateien"
-#: spyder/config/utils.py:29
+#: spyder/config/utils.py:30
msgid "Fortran files"
msgstr "Fortran-Dateien"
-#: spyder/config/utils.py:30
+#: spyder/config/utils.py:31
msgid "IDL files"
msgstr "IDL-Dateien"
-#: spyder/config/utils.py:31
+#: spyder/config/utils.py:32
msgid "MATLAB files"
msgstr "MATLAB-Dateien"
-#: spyder/config/utils.py:32
+#: spyder/config/utils.py:33
msgid "Julia files"
msgstr "Julia-Dateien"
-#: spyder/config/utils.py:33
+#: spyder/config/utils.py:34
msgid "Yaml files"
msgstr "Yaml-Dateien"
-#: spyder/config/utils.py:34
+#: spyder/config/utils.py:35
msgid "Patch and diff files"
msgstr "Patch- und diff-Dateien"
-#: spyder/config/utils.py:35
+#: spyder/config/utils.py:36
msgid "Batch files"
msgstr "Stapelverarbeitungsdateien"
-#: spyder/config/utils.py:36 spyder/utils/iofuncs.py:425
+#: spyder/config/utils.py:37
msgid "Text files"
msgstr "Textdateien"
# The official name is "reStructuredText" without any space.
-#: spyder/config/utils.py:37
+#: spyder/config/utils.py:38
msgid "reStructuredText files"
msgstr "reStructuredText-Dateien"
-#: spyder/config/utils.py:38
+#: spyder/config/utils.py:39
msgid "gettext files"
msgstr "gettext-Dateien"
-#: spyder/config/utils.py:39
+#: spyder/config/utils.py:40
msgid "NSIS files"
msgstr "NSIS-Dateien"
-#: spyder/config/utils.py:40
+#: spyder/config/utils.py:41
msgid "Web page files"
msgstr "Webseitendateien"
-#: spyder/config/utils.py:41
+#: spyder/config/utils.py:42
msgid "XML files"
msgstr "XML-Dateien"
-#: spyder/config/utils.py:42
+#: spyder/config/utils.py:43
msgid "Javascript files"
msgstr "Javascript-Dateien"
-#: spyder/config/utils.py:43
+#: spyder/config/utils.py:44
msgid "Json files"
msgstr "Json-Dateien"
-#: spyder/config/utils.py:44
+#: spyder/config/utils.py:45
msgid "IPython notebooks"
msgstr "IPython-Notebooks"
-#: spyder/config/utils.py:45
+#: spyder/config/utils.py:46
msgid "Enaml files"
msgstr "Enaml-Dateien"
-#: spyder/config/utils.py:46
+#: spyder/config/utils.py:47
msgid "Configuration files"
msgstr "Konfigurationsdateien"
-#: spyder/config/utils.py:48
+#: spyder/config/utils.py:49
msgid "Markdown files"
msgstr "Markdown-Dateien"
-#: spyder/config/utils.py:52 spyder/widgets/explorer.py:749
+#: spyder/config/utils.py:53 spyder/widgets/explorer.py:796
msgid "All files"
msgstr "Alle Dateien"
-#: spyder/config/utils.py:123
+#: spyder/config/utils.py:138
msgid "Supported text files"
msgstr "Unterstützte Textdateien"
-#: spyder/plugins/base.py:152 spyder/plugins/editor.py:104
-#: spyder/plugins/editor.py:566 spyder/plugins/editor.py:1825
-#: spyder/plugins/help.py:116 spyder/plugins/help.py:376
-#: spyder/widgets/editor.py:507 spyder/widgets/sourcecode/codeeditor.py:105
-#: spyder/widgets/sourcecode/codeeditor.py:2835
+#: spyder/plugins/__init__.py:512 spyder/plugins/editor.py:105
+#: spyder/plugins/editor.py:568 spyder/plugins/editor.py:1830
+#: spyder/plugins/help.py:117 spyder/plugins/help.py:383
+#: spyder/widgets/editor.py:544 spyder/widgets/sourcecode/codeeditor.py:98
+#: spyder/widgets/sourcecode/codeeditor.py:3229
msgid "Editor"
msgstr "Editor"
-#: spyder/plugins/configdialog.py:139
+#: spyder/plugins/configdialog.py:146
msgid "Reset to defaults"
msgstr "Auf Standardeinstellungen zurücksetzen"
-#: spyder/plugins/configdialog.py:151
+#: spyder/plugins/configdialog.py:158
msgid "Preferences"
msgstr "Voreinstellungen"
-#: spyder/plugins/configdialog.py:503
+#: spyder/plugins/configdialog.py:514
msgid "Invalid directory path"
msgstr "Ungültiger Verzeichnispfad"
-#: spyder/plugins/configdialog.py:506 spyder/plugins/configdialog.py:521
-#: spyder/plugins/runconfig.py:185 spyder/plugins/runconfig.py:251
-#: spyder/plugins/workingdirectory.py:288 spyder/widgets/explorer.py:663
-#: spyder/widgets/externalshell/pythonshell.py:609
-#: spyder/widgets/findinfiles.py:433 spyder/widgets/pathmanager.py:224
+#: spyder/plugins/configdialog.py:517 spyder/plugins/configdialog.py:532
+#: spyder/plugins/runconfig.py:220 spyder/plugins/runconfig.py:268
+#: spyder/plugins/workingdirectory.py:241 spyder/widgets/explorer.py:707
+#: spyder/widgets/findinfiles.py:347 spyder/widgets/pathmanager.py:259
#: spyder/widgets/projects/projectdialog.py:155
msgid "Select directory"
msgstr "Verzeichnis auswählen"
-#: spyder/plugins/configdialog.py:533
+#: spyder/plugins/configdialog.py:544 spyder/plugins/configdialog.py:704
msgid "Invalid file path"
msgstr "Ungültiger Dateipfad"
-#: spyder/plugins/configdialog.py:536 spyder/plugins/configdialog.py:553
+#: spyder/plugins/configdialog.py:547 spyder/plugins/configdialog.py:564
+#: spyder/plugins/configdialog.py:707
msgid "Select file"
msgstr "Datei auswählen"
-#: spyder/plugins/configdialog.py:552
+#: spyder/plugins/configdialog.py:563
msgid "All files (*)"
msgstr "Alle Dateien (*)"
-#: spyder/plugins/configdialog.py:625
+#: spyder/plugins/configdialog.py:636
msgid "Bold"
msgstr "Fett"
-#: spyder/plugins/configdialog.py:628
+#: spyder/plugins/configdialog.py:639
msgid "Italic"
msgstr "Kursiv"
-#: spyder/plugins/configdialog.py:682
+#: spyder/plugins/configdialog.py:728
msgid "Font: "
-msgstr "Schriftart:"
+msgstr "Schriftart: "
-#: spyder/plugins/configdialog.py:688
+#: spyder/plugins/configdialog.py:734
msgid "Size: "
-msgstr "Größe:"
+msgstr "Größe: "
-#: spyder/plugins/configdialog.py:707
+#: spyder/plugins/configdialog.py:753
msgid "Font style"
msgstr "Schriftstil"
-#: spyder/plugins/configdialog.py:767
+#: spyder/plugins/configdialog.py:830
msgid "Spyder needs to restart to change the following setting:"
msgstr ""
"Spyder muss neu gestartet werden, um die folgende Einstellung zu ändern:"
-#: spyder/plugins/configdialog.py:770
+#: spyder/plugins/configdialog.py:833
msgid "Spyder needs to restart to change the following settings:"
msgstr ""
"Spyder muss neu gestartet werden, um die folgenden Einstellungen zu ändern:"
-#: spyder/plugins/configdialog.py:772
+#: spyder/plugins/configdialog.py:835
msgid "Do you wish to restart now?"
msgstr "Möchten Sie jetzt neu starten?"
-#: spyder/plugins/configdialog.py:778
+#: spyder/plugins/configdialog.py:841
msgid "Information"
msgstr "Information"
-#: spyder/plugins/configdialog.py:792 spyder/plugins/configdialog.py:799
+#: spyder/plugins/configdialog.py:855 spyder/plugins/configdialog.py:862
#: spyder/widgets/projects/configdialog.py:74
msgid "General"
msgstr "Allgemein"
-#: spyder/plugins/configdialog.py:802
-msgid "Language"
-msgstr "Sprache"
+#: spyder/plugins/configdialog.py:866
+msgid "Language:"
+msgstr "Sprache:"
-#: spyder/plugins/configdialog.py:805
+#: spyder/plugins/configdialog.py:874
+msgid "Rendering engine:"
+msgstr "Rendering-Engine:"
+
+#: spyder/plugins/configdialog.py:879
msgid "Use a single instance"
msgstr "Einzelne Instanz verwenden"
-#: spyder/plugins/configdialog.py:807
+#: spyder/plugins/configdialog.py:881
msgid ""
"Set this to open external
Python files in an already running instance "
"(Requires a restart)"
@@ -1021,121 +1064,123 @@ msgstr ""
"Stellen Sie dies ein, um externe
Python-Dateien in einer bereits "
"laufenden Instanz zu öffnen (erfordert einen Neustart)"
-#: spyder/plugins/configdialog.py:810
+#: spyder/plugins/configdialog.py:885
msgid "Prompt when exiting"
msgstr "Eingabeaufforderung beim Beenden"
-#: spyder/plugins/configdialog.py:811
-msgid "Pop up internal console when internal errors appear"
-msgstr "Interne Konsole aufpoppen lassen, wenn interne Fehler erscheinen"
+#: spyder/plugins/configdialog.py:886
+msgid "Show internal Spyder errors to report them to Github"
+msgstr "Zeige Spyder-interne Fehler um Sie an Github zu melden"
-#: spyder/plugins/configdialog.py:831 spyder/plugins/editor.py:113
-#: spyder/plugins/externalconsole.py:56 spyder/plugins/ipythonconsole.py:287
+#: spyder/plugins/configdialog.py:914 spyder/plugins/editor.py:114
+#: spyder/plugins/ipythonconsole.py:301
#: spyder/widgets/projects/configdialog.py:81
msgid "Interface"
msgstr "Oberfläche"
-#: spyder/plugins/configdialog.py:839
+#: spyder/plugins/configdialog.py:922
msgid "Qt windows style"
msgstr "Qt-Fensterstil"
-#: spyder/plugins/configdialog.py:845
+#: spyder/plugins/configdialog.py:928
msgid "Icon theme"
msgstr "Symbolthema"
-#: spyder/plugins/configdialog.py:849
+#: spyder/plugins/configdialog.py:932
msgid "Vertical title bars in panes"
msgstr "Vertikale Titelleisten in Bereichen"
-#: spyder/plugins/configdialog.py:851
+#: spyder/plugins/configdialog.py:934
msgid "Vertical tabs in panes"
msgstr "Vertikale Registerkarten in Bereichen"
-#: spyder/plugins/configdialog.py:853
+#: spyder/plugins/configdialog.py:936
msgid "Animated toolbars and panes"
msgstr "Animierte Werkzeugleisten und Bereiche"
-#: spyder/plugins/configdialog.py:855
+#: spyder/plugins/configdialog.py:938
msgid "Tear off menus"
msgstr "Menüs abtrennen"
-#: spyder/plugins/configdialog.py:856
+#: spyder/plugins/configdialog.py:939
msgid "Set this to detach any
menu from the main window"
msgstr ""
"Stellen Sie dies ein, um ein beliebiges
Menü aus dem Hauptfenster zu "
"entfernen"
-#: spyder/plugins/configdialog.py:858
-msgid "Enable high DPI scaling"
-msgstr "Hohe DPI-Skalierung aktivieren"
-
-#: spyder/plugins/configdialog.py:860 spyder/plugins/configdialog.py:952
-msgid "Set this for high DPI displays"
-msgstr "Stellen Sie dies für Hoch-DPI-Bildschirme ein"
-
-#: spyder/plugins/configdialog.py:861
+#: spyder/plugins/configdialog.py:941
msgid "Custom margin for panes:"
msgstr "Benutzerdefinierter Rand für Bereiche:"
-#: spyder/plugins/configdialog.py:863
+#: spyder/plugins/configdialog.py:943
msgid "pixels"
msgstr "Pixel"
-#: spyder/plugins/configdialog.py:892
+#: spyder/plugins/configdialog.py:950
+msgid "Cursor blinking:"
+msgstr "Blinkender Cursor:"
+
+#: spyder/plugins/configdialog.py:952
+msgid "ms"
+msgstr "ms"
+
+#: spyder/plugins/configdialog.py:991
msgid "Status bar"
msgstr "Statusleiste"
-#: spyder/plugins/configdialog.py:893
+#: spyder/plugins/configdialog.py:992
msgid "Show status bar"
msgstr "Statusleiste anzeigen"
-#: spyder/plugins/configdialog.py:895
+#: spyder/plugins/configdialog.py:994
msgid "Show memory usage every"
msgstr "Speichernutzung anzeigen alle"
-#: spyder/plugins/configdialog.py:897 spyder/plugins/configdialog.py:906
-#: spyder/plugins/editor.py:143 spyder/plugins/editor.py:282
+#: spyder/plugins/configdialog.py:996 spyder/plugins/configdialog.py:1005
+#: spyder/plugins/editor.py:139 spyder/plugins/editor.py:283
msgid " ms"
msgstr " ms"
-#: spyder/plugins/configdialog.py:904
+#: spyder/plugins/configdialog.py:1003
msgid "Show CPU usage every"
msgstr "CPU-Auslastung anzeigen alle"
-#: spyder/plugins/configdialog.py:937
+#: spyder/plugins/configdialog.py:1036
msgid "Screen resolution"
msgstr "Bildschirmauflösung"
-# TYPO in source: No blank space in 'highdpi'
-#: spyder/plugins/configdialog.py:939
+#: spyder/plugins/configdialog.py:1038
msgid ""
-"Configurations for highdpi screens, See: http://doc.qt.io/qt-5/highdpi.html<> "
-"for more information"
+"Configuration for high DPI screens
Please see {0}"
+"a><> for more information about these options (in English)."
msgstr ""
-"Konfigurationen für Hoch-DPI-Bildschirme, siehe: http://doc.qt.io/qt-5/highdpi.html<> "
-"für mehr Informationen"
+"Konfiguration für Bildschirme mit hohen DPI
Schauen Sie in {0}<> für weitere Informationen über diese Optionen (in "
+"Englisch)."
-#: spyder/plugins/configdialog.py:945
+#: spyder/plugins/configdialog.py:1048
msgid "Normal"
msgstr "Normal"
-#: spyder/plugins/configdialog.py:949
+#: spyder/plugins/configdialog.py:1052
msgid "Enable auto high DPI scaling"
msgstr "Automatische hohe DPI-Skalierung aktivieren"
-#: spyder/plugins/configdialog.py:956
+#: spyder/plugins/configdialog.py:1055
+msgid "Set this for high DPI displays"
+msgstr "Stellen Sie dies für Hoch-DPI-Bildschirme ein"
+
+#: spyder/plugins/configdialog.py:1059
msgid "Set a custom high DPI scaling"
msgstr "Benutzerdefinierte hohe DPI-Skalierung festlegen"
-#: spyder/plugins/configdialog.py:959
+#: spyder/plugins/configdialog.py:1062
msgid "Set this for high DPI displays when auto scaling does not work"
msgstr ""
"Stellen Sie dies für Hoch-DPI-Bildschirme ein, wenn die automatische "
"Skalierung nicht funktioniert"
-#: spyder/plugins/configdialog.py:965
+#: spyder/plugins/configdialog.py:1068
msgid ""
"Enter values for different screens separated by semicolons ';', float values "
"are supported"
@@ -1143,31 +1188,39 @@ msgstr ""
"Geben Sie Werte für verschiedene Bildschirme ein, die durch Strichpunkte "
"getrennt sind ';', Fließkommawerte werden unterstützt"
-#: spyder/plugins/configdialog.py:992
+#: spyder/plugins/configdialog.py:1095
msgid "Plain text font"
msgstr "Klartext-Schriftart"
-#: spyder/plugins/configdialog.py:998
+#: spyder/plugins/configdialog.py:1101
msgid "Rich text font"
msgstr "Rich-Text-Schriftart"
-#: spyder/plugins/configdialog.py:1001
+#: spyder/plugins/configdialog.py:1104
msgid "Fonts"
msgstr "Schriftarten"
-#: spyder/plugins/configdialog.py:1015
+#: spyder/plugins/configdialog.py:1118
msgid "Appearance"
msgstr "Erscheinungsbild"
-#: spyder/plugins/configdialog.py:1017 spyder/plugins/ipythonconsole.py:578
+#: spyder/plugins/configdialog.py:1120 spyder/plugins/ipythonconsole.py:633
msgid "Advanced Settings"
msgstr "Erweiterte Einstellungen"
-#: spyder/plugins/configdialog.py:1053
+#: spyder/plugins/configdialog.py:1155
+msgid ""
+"We're sorry but the following error occurred while trying to set your "
+"selected language:
{}"
+msgstr ""
+"Es tut uns leid, aber der folgende Fehler ist, bei dem Versuch die von Ihnen "
+"gewählte Sprache einzustellen, aufgetreten:
{}"
+
+#: spyder/plugins/configdialog.py:1164
msgid "Syntax coloring"
msgstr "Syntaxeinfärbung"
-#: spyder/plugins/configdialog.py:1066
+#: spyder/plugins/configdialog.py:1177
msgid ""
"Here you can select the color scheme used in the Editor and all other Spyder "
"plugins.
You can also edit the color schemes provided by Spyder or "
@@ -1178,199 +1231,190 @@ msgstr ""
"bereitgestellten Farbschemata bearbeiten oder eigene erstellen, indem Sie "
"die unten aufgeführten Optionen verwenden.
"
-#: spyder/plugins/configdialog.py:1071
+#: spyder/plugins/configdialog.py:1182
msgid "Edit selected"
msgstr "Auswahl bearbeiten"
-#: spyder/plugins/configdialog.py:1072
+#: spyder/plugins/configdialog.py:1183
msgid "Create new scheme"
msgstr "Neues Schema erstellen"
-#: spyder/plugins/configdialog.py:1073 spyder/widgets/explorer.py:542
-#: spyder/widgets/projects/explorer.py:235 spyder/widgets/shell.py:136
+#: spyder/plugins/configdialog.py:1184 spyder/widgets/explorer.py:582
+#: spyder/widgets/projects/explorer.py:243 spyder/widgets/shell.py:136
msgid "Delete"
msgstr "Löschen"
-#: spyder/plugins/configdialog.py:1076
+#: spyder/plugins/configdialog.py:1187
msgid "Reset"
msgstr "Zurücksetzen"
-#: spyder/plugins/configdialog.py:1083
+#: spyder/plugins/configdialog.py:1194
msgid "Scheme:"
msgstr "Schema:"
-#: spyder/plugins/configdialog.py:1114
+#: spyder/plugins/configdialog.py:1225
msgid "Manage color schemes"
msgstr "Farbschemen verwalten"
-#: spyder/plugins/configdialog.py:1303
+#: spyder/plugins/configdialog.py:1416
msgid "Are you sure you want to delete this scheme?"
msgstr "Sind Sie sicher, dass Sie dieses Schema löschen möchten?"
-#: spyder/plugins/configdialog.py:1420
+#: spyder/plugins/configdialog.py:1533
msgid "Text"
msgstr "Text"
-#: spyder/plugins/configdialog.py:1422
+#: spyder/plugins/configdialog.py:1535
msgid "Highlight"
msgstr "Hervorheben"
-#: spyder/plugins/configdialog.py:1424
+#: spyder/plugins/configdialog.py:1537
msgid "Background"
msgstr "Hintergrund"
-#: spyder/plugins/configdialog.py:1428
+#: spyder/plugins/configdialog.py:1541
msgid "Scheme name:"
msgstr "Schemaname:"
-#: spyder/plugins/configdialog.py:1435
+#: spyder/plugins/configdialog.py:1548
msgid "Color scheme editor"
msgstr "Farbschema-Editor"
-#: spyder/plugins/console.py:105
+#: spyder/plugins/console.py:116
msgid "Internal console"
msgstr "Interne Konsole"
-#: spyder/plugins/console.py:135 spyder/plugins/externalconsole.py:736
+#: spyder/plugins/console.py:146
msgid "&Run..."
msgstr "Ausfüh&ren..."
-#: spyder/plugins/console.py:137 spyder/plugins/externalconsole.py:737
+#: spyder/plugins/console.py:148
msgid "Run a Python script"
msgstr "Python-Skript ausführen"
-#: spyder/plugins/console.py:140
+#: spyder/plugins/console.py:151
msgid "Environment variables..."
msgstr "Umgebungsvariablen..."
-#: spyder/plugins/console.py:142
+#: spyder/plugins/console.py:153
msgid "Show and edit environment variables (for current session)"
msgstr "Umgebungsvariablen anzeigen und bearbeiten (für die aktuelle Sitzung)"
-#: spyder/plugins/console.py:146
+#: spyder/plugins/console.py:157
msgid "Show sys.path contents..."
msgstr "sys.path-Inhalt anzeigen..."
-#: spyder/plugins/console.py:148
+#: spyder/plugins/console.py:159
msgid "Show (read-only) sys.path"
msgstr "(Schreibgeschützte) sys.path anzeigen"
-#: spyder/plugins/console.py:151
+#: spyder/plugins/console.py:162
msgid "Buffer..."
msgstr "Puffer..."
-#: spyder/plugins/console.py:152 spyder/plugins/externalconsole.py:74
-#: spyder/plugins/history.py:42
+#: spyder/plugins/console.py:163 spyder/plugins/history.py:45
msgid "Set maximum line count"
msgstr "Maximale Zeilenanzahl festlegen"
-#: spyder/plugins/console.py:155
+#: spyder/plugins/console.py:166
msgid "External editor path..."
msgstr "Pfad zum externen Editor..."
-#: spyder/plugins/console.py:156
+#: spyder/plugins/console.py:167
msgid "Set external editor executable path"
msgstr "Pfad zur ausführbaren Datei des externen Editors festlegen"
-#: spyder/plugins/console.py:159 spyder/plugins/editor.py:149
-#: spyder/plugins/externalconsole.py:75 spyder/plugins/help.py:151
-#: spyder/plugins/help.py:351 spyder/plugins/history.py:45
-#: spyder/plugins/history.py:154
+#: spyder/plugins/console.py:170 spyder/plugins/editor.py:149
+#: spyder/plugins/help.py:152 spyder/plugins/help.py:358
+#: spyder/plugins/history.py:48 spyder/plugins/history.py:159
msgid "Wrap lines"
msgstr "Zeilen umbrechen"
-#: spyder/plugins/console.py:162 spyder/plugins/editor.py:185
-#: spyder/plugins/externalconsole.py:120 spyder/plugins/ipythonconsole.py:297
+#: spyder/plugins/console.py:173 spyder/plugins/editor.py:185
+#: spyder/plugins/ipythonconsole.py:311
msgid "Display balloon tips"
msgstr "Sprechblasentipps anzeigen"
-#: spyder/plugins/console.py:166 spyder/plugins/editor.py:179
-#: spyder/plugins/externalconsole.py:114
+#: spyder/plugins/console.py:177 spyder/plugins/editor.py:179
msgid "Automatic code completion"
msgstr "Automatische Codevervollständigung"
-#: spyder/plugins/console.py:170 spyder/plugins/editor.py:183
-#: spyder/plugins/externalconsole.py:118
+#: spyder/plugins/console.py:181 spyder/plugins/editor.py:183
msgid "Enter key selects completion"
msgstr "Eingabe-Taste wählt Vervollständigung aus"
-#: spyder/plugins/console.py:175
+#: spyder/plugins/console.py:186
msgid "Internal console settings"
msgstr "Interne Konsoleneinstellungen"
-#: spyder/plugins/console.py:228 spyder/plugins/externalconsole.py:895
+#: spyder/plugins/console.py:265
msgid "Run Python script"
msgstr "Python-Skript ausführen"
-#: spyder/plugins/console.py:229 spyder/plugins/externalconsole.py:145
-#: spyder/plugins/externalconsole.py:896 spyder/widgets/explorer.py:764
+#: spyder/plugins/console.py:266 spyder/widgets/explorer.py:811
+#: spyder/plugins/profiler/widgets/profilergui.py:220
msgid "Python scripts"
msgstr "Python-Skripte"
-#: spyder/plugins/console.py:274
+#: spyder/plugins/console.py:311
msgid "Buffer"
msgstr "Puffer"
-#: spyder/plugins/console.py:275
+#: spyder/plugins/console.py:312
msgid "Maximum line count"
msgstr "Maximale Zeilenanzahl"
-#: spyder/plugins/console.py:285
+#: spyder/plugins/console.py:322
msgid "External editor"
msgstr "Externer Editor"
-#: spyder/plugins/console.py:286
+#: spyder/plugins/console.py:323
msgid "External editor executable path:"
msgstr "Pfad zur ausführbaren Datei des externen Editors:"
-#: spyder/plugins/editor.py:58
+#: spyder/plugins/editor.py:59
msgid "Manipulate Jupyter notebooks on the Editor"
msgstr "Jupyter-Notebooks im Editor manipulieren"
-#: spyder/plugins/editor.py:110
+#: spyder/plugins/editor.py:111
msgid "Edit template for new modules"
msgstr "Vorlage für neue Module bearbeiten"
-#: spyder/plugins/editor.py:115
+#: spyder/plugins/editor.py:116
msgid "Show tab bar"
msgstr "Registerkartenleiste anzeigen"
-#: spyder/plugins/editor.py:116
-msgid "Show Class/Function Dropdown"
-msgstr "Dropdown Klasse/Funktion anzeigen"
-
-#: spyder/plugins/editor.py:125 spyder/plugins/editor.py:199
-#: spyder/plugins/externalconsole.py:70 spyder/plugins/externalconsole.py:113
-#: spyder/plugins/help.py:150 spyder/plugins/history.py:44
-#: spyder/plugins/ipythonconsole.py:331
+#: spyder/plugins/editor.py:122 spyder/plugins/editor.py:199
+#: spyder/plugins/help.py:151 spyder/plugins/history.py:47
+#: spyder/plugins/ipythonconsole.py:349
msgid "Source code"
msgstr "Quellcode"
-#: spyder/plugins/editor.py:126
+#: spyder/plugins/editor.py:123
msgid "Show line numbers"
msgstr "Zeilennummern anzeigen"
-#: spyder/plugins/editor.py:127 spyder/plugins/editor.py:999
+#: spyder/plugins/editor.py:124 spyder/plugins/editor.py:985
msgid "Show blank spaces"
msgstr "Leerzeichen anzeigen"
-#: spyder/plugins/editor.py:128
-msgid "Show vertical lines after"
-msgstr "Vertikale Linien anzeigen nach"
+#: spyder/plugins/editor.py:125
+msgid "Show vertical line after"
+msgstr "Vertikale Linie anzeigen nach"
-#: spyder/plugins/editor.py:133
+#: spyder/plugins/editor.py:126
msgid "characters"
msgstr "Zeichen"
-#: spyder/plugins/editor.py:137
+#: spyder/plugins/editor.py:133
msgid "Highlight current line"
msgstr "Aktuelle Zeile hervorheben"
-#: spyder/plugins/editor.py:139
+#: spyder/plugins/editor.py:135
msgid "Highlight current cell"
msgstr "Aktuelle Zelle hervorheben"
-#: spyder/plugins/editor.py:141
+#: spyder/plugins/editor.py:137
msgid "Highlight occurrences after"
msgstr "Vorkommen hervorheben nach"
@@ -1388,11 +1432,11 @@ msgstr ""
"Behalten Sie, nach dem Ausführen von Zellen oder Auswahlen, den Fokus im "
"Editor"
-#: spyder/plugins/editor.py:176 spyder/plugins/externalconsole.py:251
+#: spyder/plugins/editor.py:176
msgid "Introspection"
msgstr "Introspektion"
-#: spyder/plugins/editor.py:181 spyder/plugins/externalconsole.py:116
+#: spyder/plugins/editor.py:181
msgid "Case sensitive code completion"
msgstr "Groß-/Kleinschreibung-beachtende Codevervollständigung"
@@ -1417,8 +1461,8 @@ msgid ""
"available."
msgstr ""
"Warnung:
Das Python-Modul rope ist auf diesem Computer "
-"nicht installiert: Aufrufhinweise, Codevervollständigung und "
-"Gehe-zu-Definitionsfunktionen sind nicht verfügbar."
+"nicht installiert: Aufrufhinweise, Codevervollständigung und Gehe-zu-"
+"Definitionsfunktionen sind nicht verfügbar."
#: spyder/plugins/editor.py:200
msgid "Automatic insertion of parentheses, braces and brackets"
@@ -1432,7 +1476,7 @@ msgstr "Automatisches Einfügen von Anführungszeichen Ende"
#: spyder/plugins/editor.py:205
msgid "Automatic insertion of colons after 'for', 'if', 'def', etc"
-msgstr "Automatische Einfügung von Doppelpunkten nach 'for', 'if', 'def', usw."
+msgstr "Automatisches Einfügen von Doppelpunkten nach 'for', 'if', 'def', usw."
#: spyder/plugins/editor.py:208
msgid "Automatic indentation after 'else', 'elif', etc."
@@ -1519,11 +1563,11 @@ msgstr "Analyse"
msgid "(Refer to the {} page)"
msgstr "(Siehe Seite {})"
-#: spyder/plugins/editor.py:250
+#: spyder/plugins/editor.py:251
msgid "Real-time code analysis"
msgstr "Echtzeit-Codeanalyse"
-#: spyder/plugins/editor.py:252
+#: spyder/plugins/editor.py:253
msgid ""
"If enabled, Python source code will be analyzed using pyflakes, lines "
"containing errors or warnings will be highlighted.
Note: add "
@@ -1534,47 +1578,47 @@ msgstr ""
"Sie analysis:ignore einem Kommentar hinzu, um Codeanalyse-Warnungen "
"zu ignorieren.
"
-#: spyder/plugins/editor.py:260
+#: spyder/plugins/editor.py:261
msgid "Code analysis requires pyflakes %s+"
msgstr "Codeanalyse erfordert pyflakes %s+"
-#: spyder/plugins/editor.py:262
+#: spyder/plugins/editor.py:263
msgid "Real-time code style analysis"
msgstr "Echtzeit-Codestilanalyse"
-#: spyder/plugins/editor.py:264
+#: spyder/plugins/editor.py:265
msgid ""
"If enabled, Python source code will be analyzed using pycodestyle, lines "
-"that are not following PEP8 style guide will be "
-"highlighted.
Note: add analysis:ignore in a comment to "
-"ignore style analysis warnings.
"
+"that are not following PEP8 style guide will be highlighted.Note"
+"u>: add analysis:ignore in a comment to ignore style analysis "
+"warnings.
"
msgstr ""
"Wenn aktiviert, wird Python-Quellcode mit pycodestyle analysiert. Zeilen, "
-"die nicht dem PEP8-Stilhandbuch folgen, werden "
-"hervorgehoben.
Hinweis: Fügen Sie analysis:ignore einem "
-"Kommentar hinzu, um Stilanalyse-Warnungen zu ignorieren.
"
+"die nicht dem PEP8-Stilhandbuch folgen, werden hervorgehoben."
+"p>Hinweis: Fügen Sie analysis:ignore einem Kommentar hinzu, "
+"um Stilanalyse-Warnungen zu ignorieren.
"
-#: spyder/plugins/editor.py:271
+#: spyder/plugins/editor.py:272
msgid ""
-"Code annotations (TODO, FIXME, XXX, HINT, TIP, @todo, HACK, BUG, OPTIMIZE, "
-"!!!, ???)"
+"Code annotations (TODO, FIXME, XXX, HINT, TIP, @todo, HACK, BUG, "
+"OPTIMIZE, !!!, ???)"
msgstr ""
-"Code-Annotationen (TODO, FIXME, XXX, HINT, TIP, @todo, HACK, BUG, OPTIMIZE, "
-"!!!, ???)"
+"Code-Annotationen (TODO, FIXME, XXX, HINT, TIP, @todo, HACK, BUG, "
+"OPTIMIZE, !!!, ???)"
-#: spyder/plugins/editor.py:275
+#: spyder/plugins/editor.py:276
msgid "Perform analysis when saving file and every"
msgstr "Analyse beim Speichern der Datei durchführen und alle"
-#: spyder/plugins/editor.py:279
+#: spyder/plugins/editor.py:280
msgid "Perform analysis only when saving file"
msgstr "Analyse nur beim Speichern der Datei durchführen"
-#: spyder/plugins/editor.py:338
+#: spyder/plugins/editor.py:339
msgid "End-of-line characters"
msgstr "Zeilenendezeichen"
-#: spyder/plugins/editor.py:339
+#: spyder/plugins/editor.py:340
msgid ""
"When opening a text file containing mixed end-of-line characters (this may "
"raise syntax errors in the consoles on Windows platforms), Spyder may fix "
@@ -1584,243 +1628,230 @@ msgstr ""
"Syntaxfehler in den Konsolen auf Windows-Plattformen verursachen) kann "
"Spyder die Datei automatisch korrigieren."
-#: spyder/plugins/editor.py:345
+#: spyder/plugins/editor.py:346
msgid "Fix automatically and show warning message box"
msgstr "Automatisch korrigieren und Warnmeldung anzeigen"
-#: spyder/plugins/editor.py:356 spyder/plugins/externalconsole.py:249
-#: spyder/plugins/ipythonconsole.py:572 spyder/plugins/variableexplorer.py:35
+#: spyder/plugins/editor.py:357 spyder/plugins/ipythonconsole.py:627
+#: spyder/plugins/variableexplorer.py:47
msgid "Display"
msgstr "Anzeige"
-#: spyder/plugins/editor.py:358
+#: spyder/plugins/editor.py:359
msgid "Code Introspection/Analysis"
msgstr "Codeintrospektion/Analyse"
-#: spyder/plugins/editor.py:361 spyder/plugins/externalconsole.py:252
+#: spyder/plugins/editor.py:362
msgid "Advanced settings"
msgstr "Erweiterte Einstellungen"
-#: spyder/plugins/editor.py:642
+#: spyder/plugins/editor.py:644
msgid "&New file..."
msgstr "&Neue Datei..."
-#: spyder/plugins/editor.py:643 spyder/plugins/workingdirectory.py:82
-#: spyder/widgets/explorer.py:741 spyder/widgets/explorer.py:748
+#: spyder/plugins/editor.py:645 spyder/widgets/explorer.py:788
+#: spyder/widgets/explorer.py:795
msgid "New file"
msgstr "Neue Datei"
-#: spyder/plugins/editor.py:652
+#: spyder/plugins/editor.py:654
msgid "O&pen last closed"
msgstr "Zuletzt Geschlossene &öffnen"
-#: spyder/plugins/editor.py:653
+#: spyder/plugins/editor.py:655
msgid "Open last closed"
msgstr "Zuletzt Geschlossene öffnen"
-#: spyder/plugins/editor.py:659
+#: spyder/plugins/editor.py:661
msgid "&Open..."
msgstr "&Öffnen..."
-#: spyder/plugins/editor.py:660 spyder/plugins/editor.py:1876
-#: spyder/plugins/editor.py:1882 spyder/plugins/workingdirectory.py:69
+#: spyder/plugins/editor.py:662 spyder/plugins/editor.py:1881
+#: spyder/plugins/editor.py:1887
msgid "Open file"
msgstr "Datei öffnen"
-#: spyder/plugins/editor.py:666 spyder/widgets/editor.py:469
-msgid "File switcher..."
-msgstr "Dateiwechseler..."
-
#: spyder/plugins/editor.py:668
-msgid "Fast switch between files"
-msgstr "Schneller Wechsel zwischen Dateien"
-
-#: spyder/plugins/editor.py:674
-msgid "Symbol finder..."
-msgstr "Symbolsucher..."
-
-#: spyder/plugins/editor.py:676
-msgid "Fast symbol search in file"
-msgstr "Schnelle Symbolsuche in Datei"
-
-#: spyder/plugins/editor.py:682
msgid "&Revert"
msgstr "Zu&rücksetzen"
-#: spyder/plugins/editor.py:683
+#: spyder/plugins/editor.py:669
msgid "Revert file from disk"
msgstr "Zurücksetzen auf Datei vom Datenträger"
-#: spyder/plugins/editor.py:686
+#: spyder/plugins/editor.py:672
msgid "&Save"
msgstr "&Speichern"
-#: spyder/plugins/editor.py:687 spyder/widgets/editor.py:1520
+#: spyder/plugins/editor.py:673 spyder/widgets/editor.py:1675
msgid "Save file"
msgstr "Datei speichern"
-#: spyder/plugins/editor.py:693
+#: spyder/plugins/editor.py:679
msgid "Sav&e all"
msgstr "All&es speichern"
-#: spyder/plugins/editor.py:694
+#: spyder/plugins/editor.py:680
msgid "Save all files"
msgstr "Alle Dateien speichern"
-#: spyder/plugins/editor.py:700
+#: spyder/plugins/editor.py:686
msgid "Save &as..."
msgstr "Speichern &als..."
-#: spyder/plugins/editor.py:701
+#: spyder/plugins/editor.py:687
msgid "Save current file as..."
msgstr "Aktuelle Datei speichern als..."
-#: spyder/plugins/editor.py:706
+#: spyder/plugins/editor.py:692
msgid "Save copy as..."
msgstr "Kopie speichern als..."
-#: spyder/plugins/editor.py:707
+#: spyder/plugins/editor.py:693
msgid "Save copy of current file as..."
msgstr "Kopie der aktuellen Datei speichern als..."
-#: spyder/plugins/editor.py:710 spyder/plugins/editor.py:711
+#: spyder/plugins/editor.py:696 spyder/plugins/editor.py:697
msgid "Print preview..."
msgstr "Druckvorschau..."
-#: spyder/plugins/editor.py:712
+#: spyder/plugins/editor.py:698
msgid "&Print..."
msgstr "&Drucken..."
-#: spyder/plugins/editor.py:713
+#: spyder/plugins/editor.py:699
msgid "Print current file..."
msgstr "Aktuelle Datei drucken..."
-#: spyder/plugins/editor.py:716
+#: spyder/plugins/editor.py:702
msgid "&Close"
msgstr "S&chließen"
-#: spyder/plugins/editor.py:717
+#: spyder/plugins/editor.py:703
msgid "Close current file"
msgstr "Aktuelle Datei schließen"
-#: spyder/plugins/editor.py:720
+#: spyder/plugins/editor.py:706
msgid "C&lose all"
msgstr "A&lles schließen"
-#: spyder/plugins/editor.py:721
+#: spyder/plugins/editor.py:707
msgid "Close all opened files"
msgstr "Alle geöffneten Dateien schließen"
-#: spyder/plugins/editor.py:728
+#: spyder/plugins/editor.py:714
msgid "&Find text"
msgstr "Text &suchen"
-#: spyder/plugins/editor.py:734
+#: spyder/plugins/editor.py:720
msgid "Find &next"
msgstr "&Weitersuchen"
-#: spyder/plugins/editor.py:740
+#: spyder/plugins/editor.py:726
msgid "Find &previous"
msgstr "&Vorheriges suchen"
-#: spyder/plugins/editor.py:746
+#: spyder/plugins/editor.py:732
msgid "&Replace text"
msgstr "Text e&rsetzen"
-#: spyder/plugins/editor.py:755
+#: spyder/plugins/editor.py:741
msgid "Set/Clear breakpoint"
msgstr "Haltepunkt festlegen/löschen"
-#: spyder/plugins/editor.py:762
+#: spyder/plugins/editor.py:748
msgid "Set/Edit conditional breakpoint"
msgstr "Bedingten Haltepunkt festlegen/bearbeiten"
-#: spyder/plugins/editor.py:769
+#: spyder/plugins/editor.py:755
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:180
msgid "Clear breakpoints in all files"
msgstr "Haltepunkte in allen Dateien löschen"
-#: spyder/plugins/editor.py:771
+#: spyder/plugins/editor.py:757
msgid "Debug with winpdb"
msgstr "Debug mit winpdb"
-#: spyder/plugins/editor.py:778
+#: spyder/plugins/editor.py:764
msgid "Debug file"
msgstr "Debugdatei"
-#: spyder/plugins/editor.py:783
+#: spyder/plugins/editor.py:769
msgid "Step"
msgstr "Schritt"
-#: spyder/plugins/editor.py:784
+#: spyder/plugins/editor.py:770
msgid "Run current line"
msgstr "Aktuelle Zeile ausführen"
-#: spyder/plugins/editor.py:789
+#: spyder/plugins/editor.py:775
msgid "Continue"
msgstr "Fortsetzen"
-#: spyder/plugins/editor.py:791
+#: spyder/plugins/editor.py:777
msgid "Continue execution until next breakpoint"
msgstr "Ausführung bis zum nächsten Haltepunkt fortsetzen"
-#: spyder/plugins/editor.py:796
+#: spyder/plugins/editor.py:782
msgid "Step Into"
msgstr "Schritt hinein"
-#: spyder/plugins/editor.py:798
+#: spyder/plugins/editor.py:784
msgid "Step into function or method of current line"
msgstr "Schritt in die Funktion oder Methode der aktuellen Zeile"
-#: spyder/plugins/editor.py:803
+#: spyder/plugins/editor.py:789
msgid "Step Return"
msgstr "Schritt zurück"
-#: spyder/plugins/editor.py:805
+#: spyder/plugins/editor.py:791
msgid "Run until current function or method returns"
msgstr "Ausführen bis aktuelle Funktion oder Methode zurückgibt"
-#: spyder/plugins/editor.py:810 spyder/widgets/findinfiles.py:272
-#: spyder/widgets/ipythonconsole/client.py:291
+#: spyder/plugins/editor.py:796 spyder/widgets/findinfiles.py:450
+#: spyder/widgets/ipythonconsole/client.py:393
+#: spyder/plugins/profiler/widgets/profilergui.py:87
+#: spyder/plugins/pylint/widgets/pylintgui.py:211
msgid "Stop"
msgstr "Stopp"
-#: spyder/plugins/editor.py:811
+#: spyder/plugins/editor.py:797
msgid "Stop debugging"
msgstr "Debugging stoppen"
-#: spyder/plugins/editor.py:818
+#: spyder/plugins/editor.py:804
msgid "Run file"
msgstr "Datei ausführen"
-#: spyder/plugins/editor.py:823
-msgid "&Configure..."
-msgstr "&Konfigurieren..."
+#: spyder/plugins/editor.py:809
+msgid "&Configuration per file..."
+msgstr "&Dateiweise Konfiguration..."
-#: spyder/plugins/editor.py:825 spyder/widgets/externalshell/pythonshell.py:299
+#: spyder/plugins/editor.py:811
msgid "Run settings"
msgstr "Ausführungseinstellungen"
-#: spyder/plugins/editor.py:831
+#: spyder/plugins/editor.py:817
msgid "Re-run &last script"
msgstr "&Letztes Skript erneut ausführen"
-#: spyder/plugins/editor.py:833
+#: spyder/plugins/editor.py:819
msgid "Run again last file"
msgstr "Letzte Datei erneut ausführen"
-#: spyder/plugins/editor.py:839 spyder/widgets/sourcecode/codeeditor.py:2353
+#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2727
msgid "Run &selection or current line"
msgstr "Au&swahl oder aktuelle Zeile ausführen"
-#: spyder/plugins/editor.py:842
+#: spyder/plugins/editor.py:828
msgid "Run selection or current line"
msgstr "Auswahl oder aktuelle Zeile ausführen"
-#: spyder/plugins/editor.py:850 spyder/widgets/sourcecode/codeeditor.py:2341
+#: spyder/plugins/editor.py:836 spyder/widgets/sourcecode/codeeditor.py:2715
msgid "Run cell"
msgstr "Zelle ausführen"
-#: spyder/plugins/editor.py:853
+#: spyder/plugins/editor.py:839
msgid ""
"Run current cell (Ctrl+Enter)\n"
"[Use #%% to create cells]"
@@ -1828,178 +1859,178 @@ msgstr ""
"Aktuelle Zelle ausführen (Strg+Eingabe)\n"
"[Verwenden Sie #%%, um Zellen zu erstellen]"
-#: spyder/plugins/editor.py:859 spyder/widgets/sourcecode/codeeditor.py:2345
+#: spyder/plugins/editor.py:845 spyder/widgets/sourcecode/codeeditor.py:2719
msgid "Run cell and advance"
msgstr "Zelle ausführen und vorgehen"
-#: spyder/plugins/editor.py:862
+#: spyder/plugins/editor.py:848
msgid "Run current cell and go to the next one (Shift+Enter)"
msgstr "Aktuelle Zelle ausführen und zur nächsten gehen (Umschalt+Eingabe)"
-#: spyder/plugins/editor.py:868 spyder/widgets/sourcecode/codeeditor.py:2349
+#: spyder/plugins/editor.py:854 spyder/widgets/sourcecode/codeeditor.py:2723
msgid "Re-run last cell"
msgstr "Letzte Zelle erneut ausführen"
-#: spyder/plugins/editor.py:869
+#: spyder/plugins/editor.py:855
msgid "Re run last cell "
-msgstr "Letzte Zelle erneut ausführen"
+msgstr "Letzte Zelle erneut ausführen "
-#: spyder/plugins/editor.py:879
+#: spyder/plugins/editor.py:865
msgid "Show todo list"
msgstr "Aufgabenliste anzeigen"
-#: spyder/plugins/editor.py:880
+#: spyder/plugins/editor.py:866
msgid ""
"Show comments list (TODO/FIXME/XXX/HINT/TIP/@todo/HACK/BUG/OPTIMIZE/!!!/???)"
msgstr ""
-"Kommentarliste anzeigen "
-"(TODO/FIXME/XXX/HINT/TIP/@todo/HACK/BUG/OPTIMIZE/!!!/???)"
+"Kommentarliste anzeigen (TODO/FIXME/XXX/HINT/TIP/@todo/HACK/BUG/"
+"OPTIMIZE/!!!/???)"
-#: spyder/plugins/editor.py:888
+#: spyder/plugins/editor.py:874
msgid "Show warning/error list"
msgstr "Warnungs-/Fehlerliste anzeigen"
-#: spyder/plugins/editor.py:889
+#: spyder/plugins/editor.py:875
msgid "Show code analysis warnings/errors"
msgstr "Codeanalyse-Warnungen/Fehler anzeigen"
-#: spyder/plugins/editor.py:895
+#: spyder/plugins/editor.py:881
msgid "Previous warning/error"
msgstr "Vorherige(r) Warnung/Fehler"
-#: spyder/plugins/editor.py:896
+#: spyder/plugins/editor.py:882
msgid "Go to previous code analysis warning/error"
msgstr "Zur vorherigen Codeanalyse-Warnung/Fehler gehen"
-#: spyder/plugins/editor.py:899
+#: spyder/plugins/editor.py:885
msgid "Next warning/error"
msgstr "Nächste(r) Warnung/Fehler"
-#: spyder/plugins/editor.py:900
+#: spyder/plugins/editor.py:886
msgid "Go to next code analysis warning/error"
msgstr "Zur nächsten Codeanalyse-Warnung/Fehler gehen"
-#: spyder/plugins/editor.py:904
+#: spyder/plugins/editor.py:890
msgid "Last edit location"
msgstr "Letzter Bearbeitungsort"
-#: spyder/plugins/editor.py:905
+#: spyder/plugins/editor.py:891
msgid "Go to last edit location"
msgstr "Gehe zum letzten Bearbeitungsort"
-#: spyder/plugins/editor.py:913
+#: spyder/plugins/editor.py:899
msgid "Previous cursor position"
msgstr "Vorherige Cursorposition"
-#: spyder/plugins/editor.py:914
+#: spyder/plugins/editor.py:900
msgid "Go to previous cursor position"
msgstr "Gehe zur vorherigen Cursorposition"
-#: spyder/plugins/editor.py:922
+#: spyder/plugins/editor.py:908
msgid "Next cursor position"
msgstr "Nächste Cursorposition"
-#: spyder/plugins/editor.py:923
+#: spyder/plugins/editor.py:909
msgid "Go to next cursor position"
msgstr "Gehe zur nächsten Cursorposition"
-#: spyder/plugins/editor.py:933 spyder/widgets/sourcecode/codeeditor.py:2325
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Comment"
msgstr "Kommentieren"
-#: spyder/plugins/editor.py:933 spyder/widgets/sourcecode/codeeditor.py:2325
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Uncomment"
msgstr "Unkommentieren"
-#: spyder/plugins/editor.py:934
+#: spyder/plugins/editor.py:920
msgid "Comment current line or selection"
msgstr "Aktuelle Zeile oder Auswahl kommentieren"
-#: spyder/plugins/editor.py:938
+#: spyder/plugins/editor.py:924
msgid "Add &block comment"
msgstr "&Blockkommentar hinzufügen"
-#: spyder/plugins/editor.py:939
+#: spyder/plugins/editor.py:925
msgid "Add block comment around current line or selection"
msgstr "Blockkommentar um aktuelle Zeile oder Auswahl hinzufügen"
-#: spyder/plugins/editor.py:945
+#: spyder/plugins/editor.py:931
msgid "R&emove block comment"
msgstr "Blockkommentar &entfernen"
-#: spyder/plugins/editor.py:946
+#: spyder/plugins/editor.py:932
msgid "Remove comment block around current line or selection"
msgstr "Blockkommentar um aktuelle Zeile oder Auswahl entfernen"
-#: spyder/plugins/editor.py:957
+#: spyder/plugins/editor.py:943
msgid "Indent"
msgstr "Einrücken"
-#: spyder/plugins/editor.py:958
+#: spyder/plugins/editor.py:944
msgid "Indent current line or selection"
msgstr "Aktuelle Zeile oder Auswahl einrücken"
-#: spyder/plugins/editor.py:961
+#: spyder/plugins/editor.py:947
msgid "Unindent"
msgstr "Ausrücken"
-#: spyder/plugins/editor.py:962
+#: spyder/plugins/editor.py:948
msgid "Unindent current line or selection"
msgstr "Aktuelle Zeile oder Auswahl ausrücken"
-#: spyder/plugins/editor.py:966
+#: spyder/plugins/editor.py:952
msgid "Toggle Uppercase"
msgstr "Großbuchstaben umschalten"
-#: spyder/plugins/editor.py:967
+#: spyder/plugins/editor.py:953
msgid "Change to uppercase current line or selection"
msgstr "Aktuelle Zeile oder Auswahl in Großbuchstaben ändern"
-#: spyder/plugins/editor.py:973
+#: spyder/plugins/editor.py:959
msgid "Toggle Lowercase"
msgstr "Kleinbuchstaben umschalten"
-#: spyder/plugins/editor.py:974
+#: spyder/plugins/editor.py:960
msgid "Change to lowercase current line or selection"
msgstr "Aktuelle Zeile oder Auswahl in Kleinbuchstaben ändern"
-#: spyder/plugins/editor.py:981
+#: spyder/plugins/editor.py:967
msgid "Carriage return and line feed (Windows)"
msgstr "Wagenrücklauf und Zeilenvorschub (Windows)"
-#: spyder/plugins/editor.py:984
+#: spyder/plugins/editor.py:970
msgid "Line feed (UNIX)"
msgstr "Zeilenvorschub (UNIX)"
-#: spyder/plugins/editor.py:987
+#: spyder/plugins/editor.py:973
msgid "Carriage return (Mac)"
msgstr "Wagenrücklauf (Mac)"
-#: spyder/plugins/editor.py:993
+#: spyder/plugins/editor.py:979
msgid "Convert end-of-line characters"
msgstr "Zeilenendezeichen konvertieren"
-#: spyder/plugins/editor.py:997
+#: spyder/plugins/editor.py:983
msgid "Remove trailing spaces"
msgstr "Abschließende Leerzeichen entfernen"
-#: spyder/plugins/editor.py:1001
+#: spyder/plugins/editor.py:987
msgid "Fix indentation"
msgstr "Einrückung reparieren"
-#: spyder/plugins/editor.py:1002
+#: spyder/plugins/editor.py:988
msgid "Replace tab characters by space characters"
msgstr "Tabulatorzeichen durch Leerzeichen ersetzen"
-#: spyder/plugins/editor.py:1005
+#: spyder/plugins/editor.py:991
msgid "Go to line..."
msgstr "Gehe zu Zeile..."
-#: spyder/plugins/editor.py:1013
+#: spyder/plugins/editor.py:999
msgid "Set console working directory"
msgstr "Konsolen-Arbeitsverzeichnis festlegen"
-#: spyder/plugins/editor.py:1015
+#: spyder/plugins/editor.py:1001
msgid ""
"Set current console (and file explorer) working directory to current script "
"directory"
@@ -2007,389 +2038,153 @@ msgstr ""
"Arbeitsverzeichnis der aktuellen Konsole (und des Dateimanagers) auf das "
"aktuelle Skriptverzeichnis festlegen"
-#: spyder/plugins/editor.py:1020
+#: spyder/plugins/editor.py:1006
msgid "Maximum number of recent files..."
msgstr "Maximale Anzahl der letzten Dateien..."
-#: spyder/plugins/editor.py:1023
+#: spyder/plugins/editor.py:1009
msgid "Clear recent files list"
msgstr "Liste der letzten Dateien löschen"
-#: spyder/plugins/editor.py:1023 spyder/plugins/projects.py:94
+#: spyder/plugins/editor.py:1009 spyder/plugins/projects.py:101
+#: spyder/widgets/findinfiles.py:261
msgid "Clear this list"
msgstr "Diese Liste leeren"
-#: spyder/plugins/editor.py:1027
+#: spyder/plugins/editor.py:1013
msgid "Open &recent"
msgstr "&Letzte öffnen"
-#: spyder/plugins/editor.py:1677
+#: spyder/plugins/editor.py:1674
msgid "Spyder Editor"
msgstr "Spyder Editor"
-#: spyder/plugins/editor.py:1678
+#: spyder/plugins/editor.py:1675
msgid "This is a temporary script file."
msgstr "Dies ist eine temporäre Skriptdatei."
-#: spyder/plugins/editor.py:1747
+#: spyder/plugins/editor.py:1758
msgid "untitled"
msgstr "unbenannt"
-#: spyder/plugins/editor.py:1826
+#: spyder/plugins/editor.py:1831
msgid "Maximum number of recent files"
msgstr "Maximale Anzahl der letzten Dateien"
-#: spyder/plugins/editor.py:1972
+#: spyder/plugins/editor.py:1977
msgid "Printing..."
msgstr "Druckvorgang..."
-#: spyder/plugins/explorer.py:52
+#: spyder/plugins/explorer.py:55
msgid "File explorer"
msgstr "Dateimanager"
-#: spyder/plugins/externalconsole.py:45
-msgid "Interactive data plotting in the consoles"
-msgstr "Interaktives Plotten von Daten in den Konsolen"
-
-#: spyder/plugins/externalconsole.py:53 spyder/plugins/externalconsole.py:710
-msgid "Python console"
-msgstr "Python-Konsole"
-
-#: spyder/plugins/externalconsole.py:58
-msgid "One tab per script"
-msgstr "Eine Registerkarte pro Skript"
-
-#: spyder/plugins/externalconsole.py:59
-#: spyder/widgets/externalshell/baseshell.py:160
-msgid "Show elapsed time"
-msgstr "Verstrichene Zeit anzeigen"
-
-#: spyder/plugins/externalconsole.py:60 spyder/widgets/explorer.py:1134
-msgid "Show icons and text"
-msgstr "Symbole und Text anzeigen"
-
-#: spyder/plugins/externalconsole.py:72
-msgid "Buffer: "
-msgstr "Puffer: "
+#: spyder/plugins/findinfiles.py:117 spyder/widgets/findinfiles.py:949
+msgid "Find in files"
+msgstr "In Dateien suchen"
-#: spyder/plugins/externalconsole.py:72 spyder/plugins/ipythonconsole.py:333
-msgid " lines"
-msgstr " Zeilen"
+#: spyder/plugins/findinfiles.py:141
+msgid "&Find in files"
+msgstr "In Dateien &suchen"
-#: spyder/plugins/externalconsole.py:77
-msgid "Merge process standard output/error channels"
-msgstr "Prozess-Standardausgabe-/Fehlerkanäle zusammenführen"
+#: spyder/plugins/findinfiles.py:146
+msgid "Search text in multiple files"
+msgstr "Text in mehreren Dateien suchen"
-#: spyder/plugins/externalconsole.py:79
-msgid ""
-"Merging the output channels of the process means that\n"
-"the standard error won't be written in red anymore,\n"
-"but this has the effect of speeding up display."
+#: spyder/plugins/help.py:43
+msgid "Show help for objects in the Editor and Consoles in a dedicated pane"
msgstr ""
-"Das Zusammenführen der Ausgangskanäle des Prozesses\n"
-"bedeutet, dass der Standardfehler nicht mehr in Rot\n"
-"geschrieben wird, aber dies hat zur Folge, dass die\n"
-"Anzeige schneller wird."
+"Hilfe für Objekte im Editor und in Konsolen in einem dedizierten Bereich "
+"anzeigen"
-#: spyder/plugins/externalconsole.py:83
-msgid "Colorize standard error channel using ANSI escape codes"
-msgstr "Standardfehlerkanal mit ANSI-Escape-Codes einfärben"
+#: spyder/plugins/help.py:109
+msgid "Automatic connections"
+msgstr "Automatische Verbindungen"
-#: spyder/plugins/externalconsole.py:85
+#: spyder/plugins/help.py:110
msgid ""
-"This method is the only way to have colorized standard\n"
-"error channel when the output channels have been merged."
+"This pane can automatically show an object's help information after a left "
+"parenthesis is written next to it. Below you can decide to which plugin you "
+"want to connect it to turn on this feature."
msgstr ""
-"Diese Methode ist die einzige Möglichkeit, den\n"
-"Standard-Fehlerkanal einzufärben, wenn die\n"
-"Ausgangskanäle zusammengeführt wurden."
-
-#: spyder/plugins/externalconsole.py:101 spyder/plugins/ipythonconsole.py:320
-#: spyder/widgets/variableexplorer/arrayeditor.py:541
-#: spyder/widgets/variableexplorer/dataframeeditor.py:697
-msgid "Background color"
-msgstr "Hintergrundfarbe"
+"Dieser Bereich kann automatisch die Hilfeinformationen eines Objekts "
+"anzeigen, nachdem eine linke Klammer daneben geschrieben wurde. Unten können "
+"Sie entscheiden, mit welchem Plugin Sie ihn verbinden möchten, um diese "
+"Funktion einzuschalten."
-#: spyder/plugins/externalconsole.py:102
+#: spyder/plugins/help.py:122
msgid ""
-"This option will be applied the next time a Python console or a terminal is "
-"opened."
+"This feature requires the Rope or Jedi libraries.\n"
+"It seems you don't have either installed."
msgstr ""
-"Diese Option wird beim nächsten Öffnen einer Python-Konsole oder eines "
-"Terminals angewendet."
+"Dieses Merkmal erfordert die Rope- oder Jedi-Bibliotheken.\n"
+"Es scheint, Sie haben Keines von beiden installiert."
-#: spyder/plugins/externalconsole.py:105
-msgid "Light background (white color)"
-msgstr "Heller Hintergrund (weiße Farbe)"
+#: spyder/plugins/help.py:125
+msgid "IPython Console"
+msgstr "IPython-Konsole"
-#: spyder/plugins/externalconsole.py:130
-msgid "PYTHONSTARTUP replacement"
-msgstr "PYTHONSTARTUP-Ersetzung"
+#: spyder/plugins/help.py:135
+msgid "Additional features"
+msgstr "Zusätzliche Funktionen"
-#: spyder/plugins/externalconsole.py:132
-msgid ""
-"This option will override the PYTHONSTARTUP environment variable which\n"
-"defines the script to be executed during the Python console startup."
-msgstr ""
-"Diese Option überschreibt die Umgebungsvariable PYTHONSTARTUP, die das\n"
-"Skript definiert, das während des Python-Konsolenstarts ausgeführt werden "
-"soll."
+#: spyder/plugins/help.py:136
+msgid "Render mathematical equations"
+msgstr "Mathematische Gleichungen rendern"
-#: spyder/plugins/externalconsole.py:137
-msgid "Default PYTHONSTARTUP script"
-msgstr "Voreingestelltes PYTHONSTARTUP-Skript"
+#: spyder/plugins/help.py:142
+msgid "This feature requires Sphinx 1.1 or superior."
+msgstr "Dieses Merkmal erfordert Sphinx 1.1 oder höher."
-#: spyder/plugins/externalconsole.py:141
-msgid "Use the following startup script:"
-msgstr "Folgendes Startskript verwenden:"
+#: spyder/plugins/help.py:143
+msgid "Sphinx %s is currently installed."
+msgstr "Sphinx %s ist derzeit installiert."
-#: spyder/plugins/externalconsole.py:158
-msgid "Monitor"
-msgstr "Monitor"
+#: spyder/plugins/help.py:304
+msgid "No further documentation available"
+msgstr "Keine weitere Dokumentation verfügbar"
-#: spyder/plugins/externalconsole.py:159
-msgid ""
-"The monitor provides introspection features to console: code completion, "
-"calltips and variable explorer. Because it relies on several modules, "
-"disabling the monitor may be useful to accelerate console startup."
-msgstr ""
-"Der Monitor stellt der Konsole Introspektionsfähigkeiten bereit: "
-"Codevervollständigung, Aufrufhinweise und Variablenmanager. Um das Öffnen "
-"der Konsole zu beschleunigen, kann die Deaktivierung des Monitors nützlich "
-"sein, weil er auf mehreren Modulen beruht."
+#: spyder/plugins/help.py:307 spyder/plugins/help.py:345
+msgid "No documentation available"
+msgstr "Keine Dokumentation verfügbar"
-#: spyder/plugins/externalconsole.py:166
-msgid "Enable monitor"
-msgstr "Monitor aktivieren"
+#: spyder/plugins/help.py:376
+msgid "Source"
+msgstr "Quelle"
-#: spyder/plugins/externalconsole.py:179
-msgid "Default library"
-msgstr "Standardbibliothek"
+#: spyder/plugins/help.py:383 spyder/plugins/runconfig.py:170
+#: spyder/plugins/runconfig.py:486 spyder/widgets/ipythonconsole/client.py:327
+msgid "Console"
+msgstr "Konsole"
-#: spyder/plugins/externalconsole.py:184
-msgid "Qt-Python Bindings"
-msgstr "Qt-Python-Anbindungen"
+#: spyder/plugins/help.py:391
+msgid "Object"
+msgstr "Objekt"
-#: spyder/plugins/externalconsole.py:186
-msgid "Library:"
-msgstr "Bibliothek:"
+#: spyder/plugins/help.py:405
+msgid "Plain Text"
+msgstr "Klartext"
-#: spyder/plugins/externalconsole.py:188
-msgid ""
-"This option will act on
libraries such as Matplotlib, guidata or ETS"
-msgstr ""
-"Diese Option wird auf
Bibliotheken wie Matplotlib, guidata oder ETS "
-"wirken"
+#: spyder/plugins/help.py:409
+msgid "Show Source"
+msgstr "Quelle anzeigen"
-#: spyder/plugins/externalconsole.py:197 spyder/plugins/ipythonconsole.py:574
-msgid "Graphics"
-msgstr "Grafik"
-
-#: spyder/plugins/externalconsole.py:198
-msgid ""
-"Decide which backend to use to display graphics. If unsure, please select "
-"the Automatic backend.
Note: We support a very limited "
-"number of backends in our Python consoles. If you prefer to work with a "
-"different one, please use an IPython console."
-msgstr ""
-"Entscheiden Sie, welches Backend für die Anzeige von Grafik verwendet werden "
-"soll. Wenn Sie unsicher sind, wählen Sie bitte das Backend "
-"Automatisch aus.
Hinweis: Wir unterstützen eine sehr "
-"begrenzte Anzahl an Backends in unseren Python-Konsolen. Wenn Sie es "
-"vorziehen, mit einem anderen zu arbeiten, verwenden Sie bitte eine "
-"IPython-Konsole."
-
-#: spyder/plugins/externalconsole.py:207
-msgid "None"
-msgstr "Kein"
-
-#: spyder/plugins/externalconsole.py:207 spyder/plugins/ipythonconsole.py:365
-msgid "Automatic"
-msgstr "Automatisch"
-
-# 'Backend' könnte man theoretisch mit 'Unterbau' übersetzen, aber geläufig ist das nicht.
-#: spyder/plugins/externalconsole.py:212 spyder/plugins/ipythonconsole.py:387
-msgid "Backend:"
-msgstr "Backend:"
-
-#: spyder/plugins/externalconsole.py:214 spyder/plugins/ipythonconsole.py:389
-msgid "This option will be applied the next time a console is opened."
-msgstr "Diese Option wird beim nächsten Öffnen einer Konsole angewendet."
-
-#: spyder/plugins/externalconsole.py:225
-msgid "Enthought Tool Suite"
-msgstr "Enthought Tool Suite"
-
-#: spyder/plugins/externalconsole.py:226
-msgid ""
-"Enthought Tool Suite (ETS) supports PyQt4 (qt4) and wxPython (wx) graphical "
-"user interfaces."
-msgstr ""
-"Enthought Tool Suite (ETS) unterstützt PyQt4 (qt4) und wxPython (wx) für "
-"grafische Benutzeroberflächen."
-
-#: spyder/plugins/externalconsole.py:230
-msgid "ETS_TOOLKIT:"
-msgstr "ETS_TOOLKIT:"
-
-#: spyder/plugins/externalconsole.py:254
-msgid "External modules"
-msgstr "Externe Module"
-
-#: spyder/plugins/externalconsole.py:439
-msgid ""
-"No Python console is currently selected to run %s.
Please "
-"select or open a new Python console and try again."
-msgstr ""
-"Zurzeit ist keine IPython-Konsole ausgewählt, um %s "
-"auszuführen.
Bitte wählen oder öffnen Sie eine neue "
-"Python-Konsole und versuchen Sie es erneut."
-
-#: spyder/plugins/externalconsole.py:511 spyder/plugins/externalconsole.py:518
-msgid ""
-"%s is already running in a separate process.\n"
-"Do you want to kill the process before starting a new one?"
-msgstr ""
-"%s läuft bereits in einem separaten Prozess.\n"
-"Möchten Sie den Prozess vor dem Start eines neuen töten?"
-
-#: spyder/plugins/externalconsole.py:642
-msgid "Command Window"
-msgstr "Befehlsfenster"
-
-#: spyder/plugins/externalconsole.py:644 spyder/plugins/ipythonconsole.py:311
-msgid "Terminal"
-msgstr "Terminal"
-
-#: spyder/plugins/externalconsole.py:724
-msgid "Open a &Python console"
-msgstr "&Python-Konsole öffnen"
-
-#: spyder/plugins/externalconsole.py:728
-msgid "Open &command prompt"
-msgstr "&Eingabeaufforderung öffnen"
-
-#: spyder/plugins/externalconsole.py:729
-msgid "Open a Windows command prompt"
-msgstr "Windows-Eingabeaufforderung öffnen"
-
-#: spyder/plugins/externalconsole.py:731
-msgid "Open a &terminal"
-msgstr "&Terminal öffnen"
-
-#: spyder/plugins/externalconsole.py:732
-msgid "Open a terminal window"
-msgstr "Terminalfenster öffnen"
-
-#: spyder/plugins/findinfiles.py:121 spyder/widgets/findinfiles.py:678
-msgid "Find in files"
-msgstr "In Dateien suchen"
-
-#: spyder/plugins/findinfiles.py:148
-msgid "&Find in files"
-msgstr "In Dateien &suchen"
-
-#: spyder/plugins/findinfiles.py:151
-msgid "Search text in multiple files"
-msgstr "Text in mehreren Dateien suchen"
-
-#: spyder/plugins/help.py:42
-msgid "Show help for objects in the Editor and Consoles in a dedicated pane"
-msgstr ""
-"Hilfe für Objekte im Editor und in Konsolen in einem dedizierten Bereich "
-"anzeigen"
-
-#: spyder/plugins/help.py:108
-msgid "Automatic connections"
-msgstr "Automatische Verbindungen"
-
-#: spyder/plugins/help.py:109
-msgid ""
-"This pane can automatically show an object's help information after a left "
-"parenthesis is written next to it. Below you can decide to which plugin you "
-"want to connect it to turn on this feature."
-msgstr ""
-"Dieser Bereich kann automatisch die Hilfeinformationen eines Objekts "
-"anzeigen, nachdem eine linke Klammer daneben geschrieben wurde. Unten können "
-"Sie entscheiden, mit welchem Plugin Sie ihn verbinden möchten, um diese "
-"Funktion einzuschalten."
-
-#: spyder/plugins/help.py:121
-msgid ""
-"This feature requires the Rope or Jedi libraries.\n"
-"It seems you don't have either installed."
-msgstr ""
-"Dieses Merkmal erfordert die Rope- oder Jedi-Bibliotheken.\n"
-"Es scheint, Sie haben Keines von beiden installiert."
-
-#: spyder/plugins/help.py:124
-msgid "IPython Console"
-msgstr "IPython-Konsole"
-
-#: spyder/plugins/help.py:134
-msgid "Additional features"
-msgstr "Zusätzliche Funktionen"
-
-#: spyder/plugins/help.py:135
-msgid "Render mathematical equations"
-msgstr "Mathematische Gleichungen rendern"
-
-#: spyder/plugins/help.py:141
-msgid "This feature requires Sphinx 1.1 or superior."
-msgstr "Dieses Merkmal erfordert Sphinx 1.1 oder höher."
-
-#: spyder/plugins/help.py:142
-msgid "Sphinx %s is currently installed."
-msgstr "Sphinx %s ist derzeit installiert."
-
-#: spyder/plugins/help.py:303
-msgid "No further documentation available"
-msgstr "Keine weitere Dokumentation verfügbar"
-
-#: spyder/plugins/help.py:338
-msgid "No documentation available"
-msgstr "Keine Dokumentation verfügbar"
-
-#: spyder/plugins/help.py:369
-msgid "Source"
-msgstr "Quelle"
-
-#: spyder/plugins/help.py:376 spyder/plugins/runconfig.py:196
-#: spyder/plugins/runconfig.py:468
-#: spyder/widgets/externalshell/baseshell.py:94
-#: spyder/widgets/ipythonconsole/client.py:246
-msgid "Console"
-msgstr "Konsole"
-
-#: spyder/plugins/help.py:384
-msgid "Object"
-msgstr "Objekt"
-
-#: spyder/plugins/help.py:398
-msgid "Plain Text"
-msgstr "Klartext"
-
-#: spyder/plugins/help.py:402
-msgid "Show Source"
-msgstr "Quelle anzeigen"
-
-#: spyder/plugins/help.py:406
+#: spyder/plugins/help.py:413
msgid "Rich Text"
msgstr "Rich Text"
-#: spyder/plugins/help.py:416
+#: spyder/plugins/help.py:423
msgid "Automatic import"
msgstr "Automatischer Import"
-#: spyder/plugins/help.py:428 spyder/plugins/history.py:103
-#: spyder/widgets/editor.py:687 spyder/widgets/explorer.py:1145
-#: spyder/widgets/externalshell/baseshell.py:140
-#: spyder/widgets/ipythonconsole/client.py:304
-#: spyder/widgets/variableexplorer/namespacebrowser.py:125
+#: spyder/plugins/help.py:435 spyder/plugins/history.py:108
+#: spyder/widgets/editor.py:738 spyder/widgets/explorer.py:1205
+#: spyder/widgets/ipythonconsole/client.py:417
+#: spyder/widgets/variableexplorer/namespacebrowser.py:151
msgid "Options"
msgstr "Optionen"
-#: spyder/plugins/help.py:684
+#: spyder/plugins/help.py:692
msgid ""
"Here you can get help of any object by pressing %s in front of it, either on "
"the Editor or the Console.%sHelp can also be shown automatically after "
@@ -2401,38 +2196,38 @@ msgstr ""
"linken Klammer neben einem Objekt automatisch angezeigt werden. Sie können "
"dieses Verhalten in %s aktivieren."
-#: spyder/plugins/help.py:690
+#: spyder/plugins/help.py:698
msgid "Preferences > Help"
msgstr "Voreinstellungen > Hilfe"
-#: spyder/plugins/help.py:697
+#: spyder/plugins/help.py:705
msgid "Usage"
msgstr "Gebrauch"
-#: spyder/plugins/help.py:698
+#: spyder/plugins/help.py:706
msgid "New to Spyder? Read our"
msgstr "Neu bei Spyder? Lesen Sie unser"
-#: spyder/plugins/help.py:699
+#: spyder/plugins/help.py:707
msgid "tutorial"
msgstr "Tutorial"
-#: spyder/plugins/help.py:706
+#: spyder/plugins/help.py:714
msgid ""
"Please consider installing Sphinx to get documentation rendered in rich text."
msgstr ""
"Bitte erwägen Sie die Installation von Sphinx, um die Dokumentation in Rich "
"Text zu erhalten."
-#: spyder/plugins/help.py:875
+#: spyder/plugins/help.py:885
msgid "Lock"
msgstr "Sperren"
-#: spyder/plugins/help.py:875
+#: spyder/plugins/help.py:885
msgid "Unlock"
msgstr "Entsperren"
-#: spyder/plugins/help.py:917
+#: spyder/plugins/help.py:932
msgid ""
"The following error occured when calling Sphinx %s.
Incompatible "
"Sphinx version or doc string decoding failed.
Error message:
%s"
@@ -2441,59 +2236,68 @@ msgstr ""
"
Inkompatible Sphinx-Version oder doc-Zeichenketten-Dekodierung "
"fehlgeschlagen.
Fehlermeldung:
%s"
-#: spyder/plugins/help.py:961
+#: spyder/plugins/help.py:976
msgid "No source code available."
msgstr "Kein Quellcode verfügbar."
-#: spyder/plugins/history.py:38
+#: spyder/plugins/history.py:39 spyder/plugins/pylint/plugin.py:35
msgid "Settings"
msgstr "Einstellungen"
-#: spyder/plugins/history.py:40
+#: spyder/plugins/history.py:43
msgid " entries"
msgstr " Einträge"
-#: spyder/plugins/history.py:40
+#: spyder/plugins/history.py:43
msgid "History depth: "
-msgstr "Chroniktiefe:"
+msgstr "Chroniktiefe: "
-#: spyder/plugins/history.py:47
+#: spyder/plugins/history.py:50
msgid "Scroll automatically to last entry"
msgstr "Automatisch zum letzten Eintrag rollen"
-#: spyder/plugins/history.py:123
+#: spyder/plugins/history.py:128
msgid "History log"
msgstr "Chronikprotokoll"
-#: spyder/plugins/history.py:150
+#: spyder/plugins/history.py:153 spyder/plugins/pylint/plugin.py:115
msgid "History..."
msgstr "Chronik..."
-#: spyder/plugins/history.py:152
+#: spyder/plugins/history.py:155 spyder/plugins/pylint/plugin.py:117
msgid "Set history maximum entries"
msgstr "Maximale Chronikeinträge festlegen"
-#: spyder/plugins/history.py:258
+#: spyder/plugins/history.py:260 spyder/plugins/pylint/plugin.py:39
+#: spyder/plugins/pylint/plugin.py:160
msgid "History"
msgstr "Chronik"
-#: spyder/plugins/history.py:259
+#: spyder/plugins/history.py:261 spyder/plugins/pylint/plugin.py:161
msgid "Maximum entries"
msgstr "Maximale Einträge"
-#: spyder/plugins/ipythonconsole.py:65
+#: spyder/plugins/ipythonconsole.py:64
msgid "Symbolic mathematics in the IPython Console"
msgstr "Symbolische Mathematik in der IPython-Konsole"
-#: spyder/plugins/ipythonconsole.py:69
+#: spyder/plugins/ipythonconsole.py:68
msgid "Run Cython files in the IPython Console"
msgstr "Cython-Dateien in der IPython-Konsole ausführen"
-#: spyder/plugins/ipythonconsole.py:73
+#: spyder/plugins/ipythonconsole.py:72
msgid "Integrate the IPython console"
msgstr "IPython-Konsole integrieren"
-#: spyder/plugins/ipythonconsole.py:125
+#: spyder/plugins/ipythonconsole.py:76
+msgid "IPython interactive python environment"
+msgstr "IPython interaktive Python-Umgebung"
+
+#: spyder/plugins/ipythonconsole.py:80
+msgid "Display 2D graphics in the IPython Console"
+msgstr "2D-Grafiken in der IPython-Konsole anzeigen"
+
+#: spyder/plugins/ipythonconsole.py:131
msgid ""
"The authenticity of host %s can't be established. Are you sure you "
"want to continue connecting?"
@@ -2501,92 +2305,101 @@ msgstr ""
"Die Echtheit des Rechners %s kann nicht festgestellt werden. Sind Sie "
"sicher, dass Sie das Verbinden fortsetzen möchten?"
-#: spyder/plugins/ipythonconsole.py:137
+#: spyder/plugins/ipythonconsole.py:143
msgid "The authenticity of the host can't be established"
msgstr "Die Echtheit des Rechners kann nicht festgestellt werden"
-#: spyder/plugins/ipythonconsole.py:144
+#: spyder/plugins/ipythonconsole.py:150
msgid "Tunnel '%s' failed to start"
msgstr "Der Tunnel '%s' konnte nicht gestartet werden"
-#: spyder/plugins/ipythonconsole.py:149
+#: spyder/plugins/ipythonconsole.py:155
msgid "Could not connect to remote host"
msgstr "Konnte keine Verbindung zum entfernten Rechner herstellen"
-#: spyder/plugins/ipythonconsole.py:166 spyder/plugins/ipythonconsole.py:763
+#: spyder/plugins/ipythonconsole.py:172 spyder/plugins/ipythonconsole.py:846
msgid "Connect to an existing kernel"
msgstr "Mit einem vorhandenen Kernel verbinden"
-#: spyder/plugins/ipythonconsole.py:168
+#: spyder/plugins/ipythonconsole.py:174
msgid ""
-"Please enter the connection info of the kernel you want to connect to. For "
-"that you can either select its JSON connection file using the "
-"Browse button, or write directly its id, in case it's a local "
-"kernel (for example kernel-3764.json or just 3764)."
+"Please select the JSON connection file (e.g. kernel-3764.json"
+"tt>) or enter the 4-digit ID (e.g. 3764) of the existing "
+"kernel to connect to, and enter the SSH host name and credentials if a "
+"remote kernel."
msgstr ""
-"Bitte geben Sie die Verbindungsinformationen des Kernels ein, mit dem Sie "
-"eine Verbindung herstellen möchten. Dazu können Sie entweder die "
-"JSON-Verbindungsdatei mit der Schaltfläche Durchsuchen auswählen "
-"oder direkt ihre Kennung schreiben, falls es sich um einen lokalen Kernel "
-"handelt (zum Beispiel kernel-3764.json oder einfach 3764)."
+"Bitte wählen Sie die JSON Verbindungs-Datei (z.B. kernel-3764."
+"json) oder geben Sie die 4-stellige ID (z.B. 3764) des "
+"Kernels mit dem sich verbinden wollen ein. Geben Sie dann den SSH-Host-Namen "
+"und die Anmeldedaten für den Remote-Kernel an."
-#: spyder/plugins/ipythonconsole.py:179
-msgid "Connection info:"
-msgstr "Verbindungsinformation:"
+#: spyder/plugins/ipythonconsole.py:183
+msgid "Kernel ID/Connection file:"
+msgstr "Kernel-Verbindungsdatei:"
-#: spyder/plugins/ipythonconsole.py:181
-msgid "Path to connection file or kernel id"
-msgstr "Pfad zur Verbindungsdatei oder Kernel-Kennung"
+#: spyder/plugins/ipythonconsole.py:185
+msgid "ID number or path to connection file"
+msgstr "Pfad zur Verbindungsdatei oder Kernel-Kennung (ID)"
-#: spyder/plugins/ipythonconsole.py:183 spyder/plugins/ipythonconsole.py:200
+#: spyder/plugins/ipythonconsole.py:187 spyder/plugins/ipythonconsole.py:216
msgid "Browse"
msgstr "Durchsuchen"
-#: spyder/plugins/ipythonconsole.py:192
-msgid "This is a remote kernel"
-msgstr "Dies ist ein rechnerferner Kernel"
-
#: spyder/plugins/ipythonconsole.py:196
+msgid "This is a remote kernel (via SSH)"
+msgstr "Dies ist ein rechnerferner Kernel (über SSH)"
+
+#: spyder/plugins/ipythonconsole.py:199
+msgid ""
+"Note: If connecting to a remote kernel, only the SSH keyfile or"
+"i> the Password field need to be completed, unless the keyfile is protected "
+"with a passphrase."
+msgstr ""
+"Hinweis: Bei Verbindung mit einem rechnerfernen Kernel muss nur die "
+"SSH-Schlüsseldatei oder das Passwort gesetzt werden, außer die "
+"Schlüsseldatei ist mit einem Passwort geschützt."
+
+#: spyder/plugins/ipythonconsole.py:207
msgid "username@hostname:port"
msgstr "Benutzername@Rechnername:Port"
-#: spyder/plugins/ipythonconsole.py:199
-msgid "Path to ssh key file"
-msgstr "Pfad zur SSH-Schlüsseldatei"
+#: spyder/plugins/ipythonconsole.py:210
+msgid "Remote user password or SSH keyfile passphrase"
+msgstr "Remote-Passwort oder SSH-Schlüsselpassphrase"
-#: spyder/plugins/ipythonconsole.py:208
-msgid "Password or ssh key passphrase"
-msgstr "Passwort oder SSH-Schlüsselpassphrase"
+#: spyder/plugins/ipythonconsole.py:215
+msgid "Path to SSH keyfile (optional)"
+msgstr "Pfad zur SSH-Schlüsseldatei (optional)"
-#: spyder/plugins/ipythonconsole.py:212
-msgid "Host name"
-msgstr "Rechnername"
+#: spyder/plugins/ipythonconsole.py:224
+msgid "Host name:"
+msgstr "Rechnername:"
-#: spyder/plugins/ipythonconsole.py:213
-msgid "Ssh key"
-msgstr "SSH-Schlüssel"
+#: spyder/plugins/ipythonconsole.py:225
+msgid "Password:"
+msgstr "Passwort:"
-#: spyder/plugins/ipythonconsole.py:214
-msgid "Password"
-msgstr "Passwort"
+#: spyder/plugins/ipythonconsole.py:226
+msgid "SSH keyfile:"
+msgstr "SSH-Schlüsseldatei:"
-#: spyder/plugins/ipythonconsole.py:243
-msgid "Open connection file"
-msgstr "Verbindungsdatei öffnen"
+#: spyder/plugins/ipythonconsole.py:257
+msgid "Select kernel connection file"
+msgstr "Verbindungsdatei wählen"
-#: spyder/plugins/ipythonconsole.py:248
-msgid "Select ssh key"
-msgstr "SSH-Schlüssel auswählen"
+#: spyder/plugins/ipythonconsole.py:262
+msgid "Select SSH keyfile"
+msgstr "SSH-Schlüsseldatei auswählen"
-#: spyder/plugins/ipythonconsole.py:281 spyder/plugins/ipythonconsole.py:701
+#: spyder/plugins/ipythonconsole.py:295 spyder/plugins/ipythonconsole.py:780
msgid "IPython console"
msgstr "IPython-Konsole"
-#: spyder/plugins/ipythonconsole.py:288
+#: spyder/plugins/ipythonconsole.py:302
msgid "Display initial banner"
msgstr "Initiales Banner anzeigen"
-#: spyder/plugins/ipythonconsole.py:289
+#: spyder/plugins/ipythonconsole.py:303
msgid ""
"This option lets you hide the message shown at\n"
"the top of the console when it's opened."
@@ -2594,12 +2407,12 @@ msgstr ""
"Mit dieser Option können Sie die am oberen Rand der Konsole\n"
"angezeigte Meldung ausblenden, wenn sie geöffnet ist."
-#: spyder/plugins/ipythonconsole.py:291
+#: spyder/plugins/ipythonconsole.py:305
msgid "Use a pager to display additional text inside the console"
msgstr ""
"Verwenden Sie einen Pager, um zusätzlichen Text in der Konsole anzuzeigen"
-#: spyder/plugins/ipythonconsole.py:293
+#: spyder/plugins/ipythonconsole.py:307
msgid ""
"Useful if you don't want to fill the console with long help or completion "
"texts.\n"
@@ -2609,44 +2422,75 @@ msgstr ""
"Vervollständigungstexten füllen möchten.\n"
"Hinweis: Verwenden Sie die Q-Taste, um aus dem Pager zu kommen."
-#: spyder/plugins/ipythonconsole.py:298
+#: spyder/plugins/ipythonconsole.py:312
msgid "Ask for confirmation before closing"
msgstr "Vor dem Schließen nach einer Bestätigung fragen"
-#: spyder/plugins/ipythonconsole.py:308
+#: spyder/plugins/ipythonconsole.py:315
+msgid "Ask for confirmation before removing all user-defined variables"
+msgstr ""
+"Vor dem Entfernen aller benutzerdefinierten Variablen nach einer Bestätigung "
+"fragen"
+
+#: spyder/plugins/ipythonconsole.py:318
+msgid ""
+"This option lets you hide the warning message shown\n"
+"when resetting the namespace from Spyder."
+msgstr ""
+"Mit dieser Option können Sie die Meldung ausblenden, die beim \n"
+"Zurücksetzen des Namensraumes am oberen Rand der Konsole angezeigt wird."
+
+#: spyder/plugins/ipythonconsole.py:320
+#: spyder/widgets/ipythonconsole/client.py:356
+msgid "Show elapsed time"
+msgstr "Verstrichene Zeit anzeigen"
+
+#: spyder/plugins/ipythonconsole.py:322
+msgid "Ask for confirmation before restarting"
+msgstr "Vor dem Neustart nach einer Bestätigung fragen"
+
+#: spyder/plugins/ipythonconsole.py:324
+msgid ""
+"This option lets you hide the warning message shown\n"
+"when restarting the kernel."
+msgstr ""
+"Mit dieser Option können Sie die am oberen Rand der Konsole\n"
+"angezeigte Meldung ausblenden, wenn der Kernel neugestartet wird."
+
+#: spyder/plugins/ipythonconsole.py:337
msgid "Completion Type"
msgstr "Vervollständigungstyp"
-#: spyder/plugins/ipythonconsole.py:309
+#: spyder/plugins/ipythonconsole.py:338
msgid "Decide what type of completion to use"
msgstr ""
"Entscheiden Sie, welche Art von Vervollständigung verwendet werden soll"
-#: spyder/plugins/ipythonconsole.py:311
+#: spyder/plugins/ipythonconsole.py:340
msgid "Graphical"
msgstr "Grafisch"
-#: spyder/plugins/ipythonconsole.py:311
+#: spyder/plugins/ipythonconsole.py:340
msgid "Plain"
msgstr "Klar"
-#: spyder/plugins/ipythonconsole.py:312
+#: spyder/plugins/ipythonconsole.py:340
+msgid "Terminal"
+msgstr "Terminal"
+
+#: spyder/plugins/ipythonconsole.py:341
msgid "Completion:"
msgstr "Vervollständigung:"
-#: spyder/plugins/ipythonconsole.py:321
-msgid "Light background"
-msgstr "Heller Hintergrund"
-
-#: spyder/plugins/ipythonconsole.py:323
-msgid "Dark background"
-msgstr "Dunkler Hintergrund"
+#: spyder/plugins/ipythonconsole.py:351
+msgid " lines"
+msgstr " Zeilen"
-#: spyder/plugins/ipythonconsole.py:333
+#: spyder/plugins/ipythonconsole.py:351
msgid "Buffer: "
msgstr "Puffer: "
-#: spyder/plugins/ipythonconsole.py:335
+#: spyder/plugins/ipythonconsole.py:353
msgid ""
"Set the maximum number of lines of text shown in the\n"
"console before truncation. Specifying -1 disables it\n"
@@ -2656,19 +2500,19 @@ msgstr ""
"in der Konsole vor der Trunkierung angezeigt werden.\n"
"Angabe von -1 deaktiviert es (nicht empfohlen!)"
-#: spyder/plugins/ipythonconsole.py:344
+#: spyder/plugins/ipythonconsole.py:362
msgid "Support for graphics (Matplotlib)"
msgstr "Unterstützung für Grafiken (Matplotlib)"
-#: spyder/plugins/ipythonconsole.py:345
+#: spyder/plugins/ipythonconsole.py:363
msgid "Activate support"
msgstr "Unterstützung aktivieren"
-#: spyder/plugins/ipythonconsole.py:346
+#: spyder/plugins/ipythonconsole.py:364
msgid "Automatically load Pylab and NumPy modules"
msgstr "Pylab- und NumPy-Module automatisch laden"
-#: spyder/plugins/ipythonconsole.py:349
+#: spyder/plugins/ipythonconsole.py:367
msgid ""
"This lets you load graphics support without importing \n"
"the commands to do plots. Useful to work with other\n"
@@ -2681,15 +2525,19 @@ msgstr ""
"Matplotlib unterscheiden, oder zum Entwickeln von GUIs\n"
"mit Spyder."
-#: spyder/plugins/ipythonconsole.py:364
+#: spyder/plugins/ipythonconsole.py:382
msgid "Inline"
msgstr "Inline"
-#: spyder/plugins/ipythonconsole.py:366
+#: spyder/plugins/ipythonconsole.py:383
+msgid "Automatic"
+msgstr "Automatisch"
+
+#: spyder/plugins/ipythonconsole.py:384
msgid "Graphics backend"
msgstr "Grafik-Backend"
-#: spyder/plugins/ipythonconsole.py:367
+#: spyder/plugins/ipythonconsole.py:385
msgid ""
"Decide how graphics are going to be displayed in the console. If unsure, "
"please select %s to put graphics inside the console or %s to "
@@ -2700,54 +2548,81 @@ msgstr ""
"%s, um mit diesen (durch Zoomen und Verschieben) in einem separaten "
"Fenster zu interagieren."
+# 'Backend' könnte man theoretisch mit 'Unterbau' übersetzen, aber geläufig ist das nicht.
+#: spyder/plugins/ipythonconsole.py:405
+msgid "Backend:"
+msgstr "Backend:"
+
+#: spyder/plugins/ipythonconsole.py:407
+msgid "This option will be applied the next time a console is opened."
+msgstr "Diese Option wird beim nächsten Öffnen einer Konsole angewendet."
+
# Eine passende deutsche Übersetzung gibt es dafür nicht.
-#: spyder/plugins/ipythonconsole.py:400
+#: spyder/plugins/ipythonconsole.py:418
msgid "Inline backend"
msgstr "Inline-Backend"
-#: spyder/plugins/ipythonconsole.py:401
+#: spyder/plugins/ipythonconsole.py:419
msgid "Decide how to render the figures created by this backend"
msgstr ""
"Entscheiden Sie, wie die von diesem Backend erstellten Figuren gerendert "
"werden sollen"
-#: spyder/plugins/ipythonconsole.py:405
+#: spyder/plugins/ipythonconsole.py:423
msgid "Format:"
msgstr "Format:"
-#: spyder/plugins/ipythonconsole.py:408
+#: spyder/plugins/ipythonconsole.py:427
msgid "Resolution:"
msgstr "Auflösung:"
-#: spyder/plugins/ipythonconsole.py:408
+#: spyder/plugins/ipythonconsole.py:427
msgid "dpi"
msgstr "dpi"
-#: spyder/plugins/ipythonconsole.py:410
+#: spyder/plugins/ipythonconsole.py:429
msgid "Only used when the format is PNG. Default is 72"
msgstr "Wird nur verwendet, wenn das Format PNG ist. Voreinstellung ist 72"
-#: spyder/plugins/ipythonconsole.py:413
+#: spyder/plugins/ipythonconsole.py:432
msgid "Width:"
msgstr "Breite:"
-#: spyder/plugins/ipythonconsole.py:413 spyder/plugins/ipythonconsole.py:417
+#: spyder/plugins/ipythonconsole.py:432 spyder/plugins/ipythonconsole.py:436
msgid "inches"
msgstr "Zoll"
-#: spyder/plugins/ipythonconsole.py:415
+#: spyder/plugins/ipythonconsole.py:434
msgid "Default is 6"
msgstr "Voreinstellung ist 6"
-#: spyder/plugins/ipythonconsole.py:417
+#: spyder/plugins/ipythonconsole.py:436
msgid "Height:"
msgstr "Höhe:"
-#: spyder/plugins/ipythonconsole.py:419
+#: spyder/plugins/ipythonconsole.py:438
msgid "Default is 4"
msgstr "Voreinstellung ist 4"
-#: spyder/plugins/ipythonconsole.py:446
+#: spyder/plugins/ipythonconsole.py:440
+msgid "Use a tight layout for inline plots"
+msgstr "Nutze ein enges Layout für Inline-Plots"
+
+#: spyder/plugins/ipythonconsole.py:442
+msgid ""
+"Sets bbox_inches to \"tight\" when\n"
+"plotting inline with matplotlib.\n"
+"When enabled, can cause discrepancies\n"
+"between the image displayed inline and\n"
+"that created using savefig."
+msgstr ""
+"Setzt bbox_inches auf \"tight\" wenn\n"
+"inline mit matplotlib gezeichnet wird.\n"
+"Kann zu Unstimmigkeiten zwischen dem\n"
+"angezeigten Bild und dem durch savefig\n"
+"kreierten Bild führen."
+
+#: spyder/plugins/ipythonconsole.py:475
msgid ""
"You can run several lines of code when a console is started. Please "
"introduce each one separated by commas, for example:
import os, import "
@@ -2757,15 +2632,15 @@ msgstr ""
"Bitte leiten Sie jede durch Kommata getrennt ein, zum Beispiel:
import "
"os, import sys"
-#: spyder/plugins/ipythonconsole.py:452
+#: spyder/plugins/ipythonconsole.py:481
msgid "Lines:"
msgstr "Zeilen:"
-#: spyder/plugins/ipythonconsole.py:461
+#: spyder/plugins/ipythonconsole.py:490
msgid "Run a file"
msgstr "Datei ausführen"
-#: spyder/plugins/ipythonconsole.py:462
+#: spyder/plugins/ipythonconsole.py:491
msgid ""
"You can also run a whole file at startup instead of just some lines (This is "
"similar to have a PYTHONSTARTUP file)."
@@ -2773,35 +2648,60 @@ msgstr ""
"Sie können auch eine ganze Datei beim Start anstelle von nur einigen Zeilen "
"ausführen (dies ist ähnlich wie eine PYTHONSTARTUP-Datei)."
-#: spyder/plugins/ipythonconsole.py:466
+#: spyder/plugins/ipythonconsole.py:495
msgid "Use the following file:"
msgstr "Verwenden Sie folgende Datei:"
-#: spyder/plugins/ipythonconsole.py:480
+#: spyder/plugins/ipythonconsole.py:509
+msgid "Jedi completion"
+msgstr "Jedi Vervollständigung"
+
+#: spyder/plugins/ipythonconsole.py:510
+msgid ""
+"Enable Jedi-based Tab completion in the IPython console; similar to "
+"the greedy completer, but without evaluating the code.
Warning: "
+"Slows down your console when working with large dataframes!"
+msgstr ""
+"Aktiviere die Jedi-basierte Tab-Vervollständigung in der IPython-"
+"Konsole. Entspricht der Greedy-Vervollständigung ohne Codevervollständigung. "
+"
Warnung:Verlangsamt Ihre Konsole beim Arbeiten mit großen "
+"Datenframes!"
+
+#: spyder/plugins/ipythonconsole.py:517
+msgid "Use Jedi completion in the IPython console"
+msgstr "Jedi Vervollständigung in IPython-Konsole benutzen"
+
+#: spyder/plugins/ipythonconsole.py:530
msgid "Greedy completion"
msgstr "Greedy-Vervollständigung"
-#: spyder/plugins/ipythonconsole.py:481
+#: spyder/plugins/ipythonconsole.py:531
msgid ""
"Enable Tab completion on elements of lists, results of function "
-"calls, etc, without assigning them to a variable.
For example, you "
-"can get completions on things like li[0].<Tab> or "
-"ins.meth().<Tab>"
+"calls, etc, without assigning them to a variable, like li[0].<"
+"Tab> or ins.meth().<Tab>
Warning: Due to a "
+"bug, IPython's greedy completer requires a leading <Space> "
+"for some completions; e.g. np.sin(<Space>np.<Tab> "
+"works while np.sin(np.<Tab> doesn't."
msgstr ""
"Tab-Vervollständigung auf Elemente von Listen, Ergebnisse von "
"Funktionsaufrufen, usw. ohne sie einer Variablen zuzuordnen, "
-"aktivieren.
Zum Beispiel können Sie Vervollständigungen auf Sachen wie "
-"li[0].<Tab> oder ins.meth().<Tab> erhalten"
+"aktivieren. Zum Beispiel können Sie Vervollständigungen von li[0].<"
+"Tab> oder ins.meth().<Tab> erhalten.
Warnung:"
+"b> Aufgrund eines Bugs benötigt der IPython Greedy-Vervollständiger ein "
+"führendes <Space> für einige Vervollständigungen. Zum "
+"Beispiel funktioniertnp.sin(<Space>np.<Tab> "
+"währendnp.sin(np.<Tab> nicht funktioniert."
-#: spyder/plugins/ipythonconsole.py:489
-msgid "Use the greedy completer"
-msgstr "Greedy completer verwenden"
+#: spyder/plugins/ipythonconsole.py:543
+msgid "Use greedy completion in the IPython console"
+msgstr "Greedy-Vervollständigung in IPython-Konsole benutzen"
-#: spyder/plugins/ipythonconsole.py:500
+#: spyder/plugins/ipythonconsole.py:555
msgid "Autocall"
msgstr "Autoaufruf"
-#: spyder/plugins/ipythonconsole.py:501
+#: spyder/plugins/ipythonconsole.py:556
msgid ""
"Autocall makes IPython automatically call any callable object even if you "
"didn't type explicit parentheses.
For example, if you type str 43 "
@@ -2811,23 +2711,23 @@ msgstr ""
"wenn Sie keine expliziten Klammern eingegeben haben.
Wenn Sie zum "
"Beispiel str 43 eingeben, wird es automatisch zu str(43)."
-#: spyder/plugins/ipythonconsole.py:508
+#: spyder/plugins/ipythonconsole.py:563
msgid "Smart"
msgstr "Schlau"
-#: spyder/plugins/ipythonconsole.py:509
+#: spyder/plugins/ipythonconsole.py:564
msgid "Full"
msgstr "Vollständig"
-#: spyder/plugins/ipythonconsole.py:510
+#: spyder/plugins/ipythonconsole.py:565
msgid "Off"
msgstr "Aus"
-#: spyder/plugins/ipythonconsole.py:512
+#: spyder/plugins/ipythonconsole.py:567
msgid "Autocall: "
msgstr "Autoaufruf: "
-#: spyder/plugins/ipythonconsole.py:513
+#: spyder/plugins/ipythonconsole.py:568
msgid ""
"On %s mode, Autocall is not applied if there are no arguments after "
"the callable. On %s mode, all callable objects are automatically "
@@ -2838,11 +2738,11 @@ msgstr ""
"alle aufrufbaren Objekte automatisch aufgerufen (auch wenn keine Argumente "
"vorhanden sind)."
-#: spyder/plugins/ipythonconsole.py:525
+#: spyder/plugins/ipythonconsole.py:580
msgid "Symbolic Mathematics"
msgstr "Symbolische Mathematik"
-#: spyder/plugins/ipythonconsole.py:526
+#: spyder/plugins/ipythonconsole.py:581
msgid ""
"Perfom symbolic operations in the console (e.g. integrals, derivatives, "
"vector calculus, etc) and get the outputs in a beautifully printed style (it "
@@ -2852,11 +2752,11 @@ msgstr ""
"Ableitungen, Vektoranalysis, usw.) und erhalten Sie die Ausgaben in einem "
"wunderschönen gedruckten Stil (es erfordert das Modul Sympy)."
-#: spyder/plugins/ipythonconsole.py:531
+#: spyder/plugins/ipythonconsole.py:586
msgid "Use symbolic math"
msgstr "Symbolische Mathematik verwenden"
-#: spyder/plugins/ipythonconsole.py:532
+#: spyder/plugins/ipythonconsole.py:587
msgid ""
"This option loads the Sympy library to work with.
Please refer to its "
"documentation to learn how to use it."
@@ -2864,92 +2764,109 @@ msgstr ""
"Diese Option lädt die Bibliothek Sympy zum Arbeiten.
Bitte beachten Sie "
"die Dokumentation, um zu erfahren, wie man sie benutzt."
-#: spyder/plugins/ipythonconsole.py:542
+#: spyder/plugins/ipythonconsole.py:597
msgid "Prompts"
msgstr "Eingabeaufforderungen"
-#: spyder/plugins/ipythonconsole.py:543
+#: spyder/plugins/ipythonconsole.py:598
msgid "Modify how Input and Output prompts are shown in the console."
msgstr ""
"Ändern Sie, wie Eingabe- und Ausgabe-Eingabeaufforderungen in der Konsole "
"angezeigt werden."
-#: spyder/plugins/ipythonconsole.py:546
+#: spyder/plugins/ipythonconsole.py:601
msgid "Input prompt:"
msgstr "Eingabeprompt:"
-#: spyder/plugins/ipythonconsole.py:548
+#: spyder/plugins/ipythonconsole.py:603
msgid ""
"Default is
In [<span class=\"in-prompt-number\">%i</span>]:"
msgstr ""
-"Voreinstellung ist
In [<span "
-"class=\"in-prompt-number\">%i</span>]:"
+"Voreinstellung ist
In [<span class=\"in-prompt-number\">%i</"
+"span>]:"
-#: spyder/plugins/ipythonconsole.py:552
+#: spyder/plugins/ipythonconsole.py:607
msgid "Output prompt:"
msgstr "Ausgabeprompt:"
-#: spyder/plugins/ipythonconsole.py:554
+#: spyder/plugins/ipythonconsole.py:609
msgid ""
"Default is
Out[<span class=\"out-prompt-number\">%i</span>]:"
msgstr ""
-"Voreinstellung ist
Aus[<span "
-"class=\"out-prompt-number\">%i</span>]:"
+"Voreinstellung ist
Aus[<span class=\"out-prompt-number\">%i</"
+"span>]:"
+
+#: spyder/plugins/ipythonconsole.py:629
+msgid "Graphics"
+msgstr "Grafik"
-#: spyder/plugins/ipythonconsole.py:576 spyder/plugins/workingdirectory.py:44
+#: spyder/plugins/ipythonconsole.py:631
msgid "Startup"
msgstr "Start"
-#: spyder/plugins/ipythonconsole.py:748
+#: spyder/plugins/ipythonconsole.py:658
+msgid ""
+"The directory {} is not writable and it is required to create IPython "
+"consoles. Please make it writable."
+msgstr ""
+"Das Verzeichnis {} ist nicht beschreibbar und es ist zum Erstellen von "
+"IPython-Konsolen erforderlich. Bitte machen Sie es beschreibbar."
+
+#: spyder/plugins/ipythonconsole.py:831
msgid "Open an &IPython console"
msgstr "&IPython-Konsole öffnen"
-#: spyder/plugins/ipythonconsole.py:755
+#: spyder/plugins/ipythonconsole.py:838
msgid "Restart kernel"
msgstr "Kernel neu starten"
-#: spyder/plugins/ipythonconsole.py:764
+#: spyder/plugins/ipythonconsole.py:847
msgid "Open a new IPython console connected to an existing kernel"
msgstr ""
"Neue IPython-Konsole, die mit einem vorhandenen Kernel verbunden ist, öffnen"
-#: spyder/plugins/ipythonconsole.py:856
-msgid ""
-"No IPython console is currently available to run %s.
Please "
-"open a new one and try again."
-msgstr ""
-"Zurzeit ist keine IPython-Konsole verfügbar, um %s "
-"auszuführen.
Bitte öffnen Sie eine neue und versuchen Sie es "
-"erneut."
+#: spyder/plugins/ipythonconsole.py:850
+msgid "Rename tab"
+msgstr "Tab umbenennen"
-#: spyder/plugins/ipythonconsole.py:904
+#: spyder/plugins/ipythonconsole.py:968
msgid ""
-"The directory {} is not writable and it is required to create IPython "
-"consoles. Please make it writable."
+"
Please exit from debugging before trying to run a file in this "
+"console.\n"
+"
"
msgstr ""
-"Das Verzeichnis {} ist nicht beschreibbar und es ist zum Erstellen von "
-"IPython-Konsolen erforderlich. Bitte machen Sie es beschreibbar."
+"
Beenden Sie bitte erst das Debuggen bevor Sie versuchen eine Datei in "
+"dieser Konsole zu starten.\n"
+"
"
-#: spyder/plugins/ipythonconsole.py:917
+#: spyder/plugins/ipythonconsole.py:988
msgid ""
-"Your Python environment or installation doesn't have the ipykernel "
-"module installed on it. Without this module is not possible for Spyder to "
-"create a console for you.
You can install ipykernel by "
-"running in a terminal:
pip install "
-"ipykernel
or
conda install ipykernel"
+"No IPython console is currently available to run %s.
Please "
+"open a new one and try again."
msgstr ""
-"Ihre Python-Umgebung oder -Installation verfügt nicht über das darauf "
-"installierte Modul ipykernel. Ohne dieses Modul ist es für Spyder "
-"nicht möglich, eine Konsole für Sie zu erstellen.
Sie können "
-"ipykernel installieren, indem Sie Folgendes in einem Terminal "
-"ausführen:
pip install ipykernel
or
conda "
-"install ipykernel"
+"Zurzeit ist keine IPython-Konsole verfügbar, um %s auszuführen."
+"
Bitte öffnen Sie eine neue und versuchen Sie es erneut."
-#: spyder/plugins/ipythonconsole.py:1147
+#: spyder/plugins/ipythonconsole.py:1096
+msgid ""
+"Your Python environment or installation doesn't have the spyder-kernels"
+"tt> module or the right version of it installed. Without this module is not "
+"possible for Spyder to create a console for you.
You can install it "
+"by running in a system terminal:
conda install spyder-kernels=0."
+"*
or
pip install spyder-kernels==0.*"
+msgstr ""
+"Ihre Python-Umgebung oder -Installation verfügt nicht über das Modul "
+"spyder-kernels oder nur über eine falsche Version. Ohne dieses "
+"Modul ist es für Spyder nicht möglich, eine Konsole für Sie zu erstellen."
+"
Sie können es installieren, indem Sie Folgendes in einem Terminal "
+"ausführen:
conda install spyder-kernels=0.*"
+"tt>
or
pip install spyder-kernels==0.*"
+
+#: spyder/plugins/ipythonconsole.py:1362
msgid "Do you want to close this console?"
msgstr "Möchten Sie diese Konsole schließen?"
-#: spyder/plugins/ipythonconsole.py:1153
+#: spyder/plugins/ipythonconsole.py:1368
msgid ""
"Do you want to close all other consoles connected to the same kernel as this "
"one?"
@@ -2957,27 +2874,31 @@ msgstr ""
"Möchten Sie alle anderen Konsolen, die mit demselben Kernel verbunden sind, "
"schließen?"
-#: spyder/plugins/ipythonconsole.py:1211
+#: spyder/plugins/ipythonconsole.py:1440
msgid ""
"It was not possible to restart the IPython console when switching to this "
-"project. The error was {0}"
+"project. The error was
{0}"
msgstr ""
"Es war nicht möglich, die IPython-Konsole beim Umschalten auf dieses Projekt "
-"neu zu starten. Der Fehler war {0}"
+"neu zu starten. Der Fehler war
{0}"
-#: spyder/plugins/ipythonconsole.py:1462
+#: spyder/plugins/ipythonconsole.py:1546 spyder/plugins/ipythonconsole.py:1556
+msgid "The error is:
{}"
+msgstr "Der Fehler ist:
{}"
+
+#: spyder/plugins/ipythonconsole.py:1742
msgid "IPython"
msgstr "IPython"
-#: spyder/plugins/ipythonconsole.py:1463
+#: spyder/plugins/ipythonconsole.py:1743
msgid "Unable to connect to %s"
msgstr "Es kann keine Verbindung mit %s hergestellt werden"
-#: spyder/plugins/ipythonconsole.py:1523
+#: spyder/plugins/ipythonconsole.py:1819
msgid "Connection error"
msgstr "Verbindungsfehler"
-#: spyder/plugins/ipythonconsole.py:1524
+#: spyder/plugins/ipythonconsole.py:1820
msgid ""
"Could not open ssh tunnel. The error was:\n"
"\n"
@@ -3001,31 +2922,35 @@ msgstr "Layout löschen"
msgid "Layout Display and Order"
msgstr "Layoutanzeige und -anordnung"
-#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:66
+#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:71
msgid "Python interpreter"
msgstr "Python-Interpreter"
-#: spyder/plugins/maininterpreter.py:68
+#: spyder/plugins/maininterpreter.py:73
msgid "Select the Python interpreter for all Spyder consoles"
msgstr "Wählen Sie den Python-Interpreter für alle Spyder-Konsolen aus"
-#: spyder/plugins/maininterpreter.py:71
+#: spyder/plugins/maininterpreter.py:76
msgid "Default (i.e. the same as Spyder's)"
msgstr "Voreinstellung (d.h. das gleiche wie Spyder)"
-#: spyder/plugins/maininterpreter.py:74
+#: spyder/plugins/maininterpreter.py:79
msgid "Use the following Python interpreter:"
msgstr "Folgenden Python-Interpreter verwenden:"
-#: spyder/plugins/maininterpreter.py:77
+#: spyder/plugins/maininterpreter.py:82
msgid "Executables"
msgstr "Programmdateien"
-#: spyder/plugins/maininterpreter.py:94
+#: spyder/plugins/maininterpreter.py:92
+msgid "Recent custom interpreters"
+msgstr "Letzte benutzerdefinierte Interpreter"
+
+#: spyder/plugins/maininterpreter.py:107
msgid "User Module Reloader (UMR)"
msgstr "User Module Reloader (UMR)"
-#: spyder/plugins/maininterpreter.py:95
+#: spyder/plugins/maininterpreter.py:108
msgid ""
"UMR forces Python to reload modules which were imported when executing a "
"file in a Python or IPython console with the runfile function."
@@ -3034,49 +2959,48 @@ msgstr ""
"einer Python- oder IPython-Konsole mit der Funktion runfile "
"importiert wurden."
-#: spyder/plugins/maininterpreter.py:100
+#: spyder/plugins/maininterpreter.py:113
msgid "Enable UMR"
msgstr "UMR aktivieren"
-#: spyder/plugins/maininterpreter.py:101
+#: spyder/plugins/maininterpreter.py:114
msgid ""
"This option will enable the User Module Reloader (UMR) in Python/IPython "
"consoles. UMR forces Python to reload deeply modules during import when "
-"running a Python script using the Spyder's builtin function "
-"runfile.
1. UMR may require to restart the console in "
-"which it will be called (otherwise only newly imported modules will be "
-"reloaded when executing files).
2. If errors occur when "
-"re-running a PyQt-based program, please check that the Qt objects are "
-"properly destroyed (e.g. you may have to use the attribute "
-"Qt.WA_DeleteOnClose on your main window, using the "
-"setAttribute method)"
-msgstr ""
-"Diese Option aktiviert den User Module Reloader (UMR) in "
-"Python/IPython-Konsolen. UMR zwingt Python, tiefgreifende Module beim Import "
-"zu laden, wenn ein Python-Skript mit der eingebauten Spyder-Funktion "
-"runfile ausgeführt wird.
1. UMR kann einen Neustart der "
-"Konsole erfordern, in der es aufgerufen wird (sonst werden nur neu "
-"importierte Module beim Ausführen von Dateien neu geladen).
2. "
-"Wenn Fehler beim Ausführen eines PyQt-basierten Programms auftreten, "
-"überprüfen Sie bitte, ob die Qt-Objekte ordnungsgemäß zerstört sind (z.B. "
-"müssen Sie das Attribut Qt.WA_DeleteOnClose der Methode "
-"setAttribute in Ihrem Hauptfenster verwenden)"
-
-#: spyder/plugins/maininterpreter.py:117
+"running a Python script using the Spyder's builtin function runfile."
+"
1. UMR may require to restart the console in which it will be "
+"called (otherwise only newly imported modules will be reloaded when "
+"executing files).
2. If errors occur when re-running a PyQt-"
+"based program, please check that the Qt objects are properly destroyed (e.g. "
+"you may have to use the attribute Qt.WA_DeleteOnClose on your main "
+"window, using the setAttribute method)"
+msgstr ""
+"Diese Option aktiviert den User Module Reloader (UMR) in Python/IPython-"
+"Konsolen. UMR zwingt Python, tiefgreifende Module beim Import zu laden, wenn "
+"ein Python-Skript mit der eingebauten Spyder-Funktion runfile "
+"ausgeführt wird.
1. UMR kann einen Neustart der Konsole "
+"erfordern, in der es aufgerufen wird (sonst werden nur neu importierte "
+"Module beim Ausführen von Dateien neu geladen).
2. Wenn Fehler "
+"beim Ausführen eines PyQt-basierten Programms auftreten, überprüfen Sie "
+"bitte, ob die Qt-Objekte ordnungsgemäß zerstört sind (z.B. müssen Sie das "
+"Attribut Qt.WA_DeleteOnClose der Methode setAttribute in Ihrem "
+"Hauptfenster verwenden)"
+
+#: spyder/plugins/maininterpreter.py:130
msgid "Show reloaded modules list"
msgstr "Liste der nachgeladenen Module anzeigen"
-#: spyder/plugins/maininterpreter.py:118
+#: spyder/plugins/maininterpreter.py:131
msgid "Please note that these changes will be applied only to new consoles"
msgstr ""
"Bitte beachten Sie, dass diese Änderungen nur auf neue Konsolen angewendet "
"werden"
-#: spyder/plugins/maininterpreter.py:122
+#: spyder/plugins/maininterpreter.py:135
msgid "Set UMR excluded (not reloaded) modules"
msgstr "UMR-ausgeschlossene (nicht neu geladene) Module festlegen"
-#: spyder/plugins/maininterpreter.py:148
+#: spyder/plugins/maininterpreter.py:163
msgid ""
"You selected an invalid Python interpreter for the console so the previous "
"interpreter will stay. Please make sure to select a valid one."
@@ -3085,7 +3009,7 @@ msgstr ""
"deshalb wird der vorherige Interpreter ausgewählt bleiben. Bitte achten Sie "
"darauf, einen gültigen auszuwählen."
-#: spyder/plugins/maininterpreter.py:176
+#: spyder/plugins/maininterpreter.py:184
msgid ""
"You selected a Python %d interpreter for the console but Spyder is "
"running on Python %d!.
Although this is possible, we recommend "
@@ -3099,18 +3023,18 @@ msgstr ""
"installieren und auszuführen, um falsche Warnungen und Fehler aufgrund der "
"inkompatiblen Syntax zwischen diesen beiden Python-Versionen zu vermeiden."
-#: spyder/plugins/maininterpreter.py:186 spyder/plugins/maininterpreter.py:213
-#: spyder/plugins/maininterpreter.py:217
+#: spyder/plugins/maininterpreter.py:195 spyder/plugins/maininterpreter.py:222
+#: spyder/plugins/maininterpreter.py:226
msgid "UMR"
msgstr "UMR"
-#: spyder/plugins/maininterpreter.py:187
+#: spyder/plugins/maininterpreter.py:196
msgid "Set the list of excluded modules as this: numpy, scipy"
msgstr ""
"Legen Sie die Liste der ausgeschlossenen Module wie folgt fest: numpy, "
"scipy"
-#: spyder/plugins/maininterpreter.py:204
+#: spyder/plugins/maininterpreter.py:213
msgid ""
"You are working with Python 2, this means that you can not import a module "
"that contains non-ascii characters."
@@ -3118,7 +3042,7 @@ msgstr ""
"Sie arbeiten mit Python 2, das bedeutet, dass Sie kein Modul importieren "
"können, das Nicht-ASCII-Zeichen enthält."
-#: spyder/plugins/maininterpreter.py:214
+#: spyder/plugins/maininterpreter.py:223
msgid ""
"The following modules are not installed on your machine:\n"
"%s"
@@ -3126,181 +3050,184 @@ msgstr ""
"Die folgenden Module sind auf Ihrem Rechner nicht installiert:\n"
"%s"
-#: spyder/plugins/maininterpreter.py:218
+#: spyder/plugins/maininterpreter.py:227
msgid ""
"Please note that these changes will be applied only to new Python/IPython "
"consoles"
msgstr ""
-"Bitte beachten Sie, dass diese Änderungen nur auf neue "
-"Python/IPython-Konsolen angewendet werden"
+"Bitte beachten Sie, dass diese Änderungen nur auf neue Python/IPython-"
+"Konsolen angewendet werden"
-#: spyder/plugins/onlinehelp.py:73
+#: spyder/plugins/onlinehelp.py:70
msgid "Online help"
msgstr "Online-Hilfe"
-#: spyder/plugins/outlineexplorer.py:56 spyder/widgets/editortools.py:196
+#: spyder/plugins/outlineexplorer.py:48 spyder/widgets/editortools.py:194
msgid "Outline"
msgstr "Gliederung"
-#: spyder/plugins/projects.py:70 spyder/widgets/projects/explorer.py:112
+#: spyder/plugins/projects.py:77 spyder/widgets/projects/explorer.py:112
#: spyder/widgets/projects/explorer.py:126
msgid "Project explorer"
msgstr "Projektmanager"
-#: spyder/plugins/projects.py:82
+#: spyder/plugins/projects.py:89
msgid "New Project..."
msgstr "Neues Projekt..."
-#: spyder/plugins/projects.py:85
+#: spyder/plugins/projects.py:92
msgid "Open Project..."
msgstr "Projekt öffnen..."
-#: spyder/plugins/projects.py:88
+#: spyder/plugins/projects.py:95
msgid "Close Project"
msgstr "Projekt schließen"
-#: spyder/plugins/projects.py:91
+#: spyder/plugins/projects.py:98
msgid "Delete Project"
msgstr "Projekt löschen"
-#: spyder/plugins/projects.py:97
+#: spyder/plugins/projects.py:104
msgid "Project Preferences"
msgstr "Projekt-Voreinstellungen"
-#: spyder/plugins/projects.py:99
+#: spyder/plugins/projects.py:106
msgid "Recent Projects"
msgstr "Letzte Projekte"
-#: spyder/plugins/projects.py:244
+#: spyder/plugins/projects.py:264
msgid "Open project"
msgstr "Projekt öffnen"
-#: spyder/plugins/projects.py:249
+#: spyder/plugins/projects.py:270
msgid "%s is not a Spyder project!"
msgstr "%s ist kein Spyder-Projekt!"
#: spyder/plugins/runconfig.py:29
-msgid "Execute in current Python or IPython console"
-msgstr "In aktueller Python- oder IPython-Konsole ausführen"
+msgid "Execute in current console"
+msgstr "In aktueller Konsole ausführen"
#: spyder/plugins/runconfig.py:30
-msgid "Execute in a new dedicated Python console"
-msgstr "In einer neuen dedizierten Python-Konsole ausführen"
+msgid "Execute in a dedicated console"
+msgstr "In einer neuen dedizierten Konsole ausführen"
#: spyder/plugins/runconfig.py:31
-msgid "Execute in an external System terminal"
+msgid "Execute in an external system terminal"
msgstr "In einem externen Systemterminal ausführen"
-#: spyder/plugins/runconfig.py:41
+#: spyder/plugins/runconfig.py:42
msgid "Always show %s on a first file run"
msgstr "%s bei erster Dateiausführung immer anzeigen"
-#: spyder/plugins/runconfig.py:44
-msgid "Clear all variables before execution (IPython consoles)"
-msgstr "Alle Variablen vor der Ausführung löschen (IPython-Konsolen)"
+#: spyder/plugins/runconfig.py:45
+msgid "Remove all variables before execution"
+msgstr "Alle Variablen vor der Ausführung löschen"
-#: spyder/plugins/runconfig.py:166 spyder/plugins/runconfig.py:486
+#: spyder/plugins/runconfig.py:46
+msgid "Directly enter debugging when errors appear"
+msgstr ""
+"In den Debugging-Modus gehen, wenn während der Ausführung Fehler auftreten"
+
+#: spyder/plugins/runconfig.py:47
+msgid "Interact with the Python console after execution"
+msgstr "Mit der Python-Konsole nach der Ausführung interagieren"
+
+#: spyder/plugins/runconfig.py:49
+msgid "The directory of the file being executed"
+msgstr "Das Verzeichnis der auszuführenden Datei"
+
+#: spyder/plugins/runconfig.py:50 spyder/plugins/workingdirectory.py:56
+msgid "The current working directory"
+msgstr "Aktuelles Arbeitsverzeichnis"
+
+#: spyder/plugins/runconfig.py:51
+msgid "The following directory:"
+msgstr "Das folgende Verzeichnis:"
+
+#: spyder/plugins/runconfig.py:184 spyder/plugins/runconfig.py:504
msgid "General settings"
msgstr "Allgemeine Einstellungen"
-#: spyder/plugins/runconfig.py:171 spyder/plugins/runconfig.py:219
+#: spyder/plugins/runconfig.py:194 spyder/plugins/runconfig.py:236
msgid "Command line options:"
msgstr "Befehlszeilenoptionen:"
-#: spyder/plugins/runconfig.py:177
-msgid "Working directory:"
-msgstr "Arbeitsverzeichnis:"
-
-#: spyder/plugins/runconfig.py:189 spyder/plugins/runconfig.py:504
-msgid "Enter debugging mode when errors appear during execution"
-msgstr ""
-"In den Debugging-Modus gehen, wenn während der Ausführung Fehler auftreten"
+#: spyder/plugins/runconfig.py:202 spyder/plugins/runconfig.py:514
+msgid "Working Directory settings"
+msgstr "Einstellung des Arbeitsverzeichnises"
-#: spyder/plugins/runconfig.py:207 spyder/plugins/runconfig.py:517
-msgid "Dedicated Python console"
-msgstr "Dedizierte Python-Konsole"
+#: spyder/plugins/runconfig.py:226 spyder/plugins/runconfig.py:548
+msgid "External system terminal"
+msgstr "Externes Systemterminal"
-#: spyder/plugins/runconfig.py:211 spyder/plugins/runconfig.py:519
-msgid "Interact with the Python console after execution"
-msgstr "Mit der Python-Konsole nach der Ausführung interagieren"
-
-#: spyder/plugins/runconfig.py:215
-msgid "Show warning when killing running process"
-msgstr "Warnung beim Töten des laufenden Prozesses anzeigen"
-
-#: spyder/plugins/runconfig.py:224
+#: spyder/plugins/runconfig.py:241
msgid "-u is added to the other options you set here"
msgstr ""
"-u wird zu den anderen Optionen hinzugefügt, die Sie hier festgelegt "
"haben"
-#: spyder/plugins/runconfig.py:234
+#: spyder/plugins/runconfig.py:250
msgid "this dialog"
msgstr "dieser Dialog"
-#: spyder/plugins/runconfig.py:295
+#: spyder/plugins/runconfig.py:315
msgid "Run configuration"
msgstr "Ausführungskonfiguration"
-#: spyder/plugins/runconfig.py:296
+#: spyder/plugins/runconfig.py:316
msgid "The following working directory is not valid:
%s"
msgstr "Das folgende Arbeitsverzeichnis ist nicht gültig:
%s"
-#: spyder/plugins/runconfig.py:374
+#: spyder/plugins/runconfig.py:394
msgid "Run settings for %s"
msgstr "Ausführungseinstellungen für %s"
-#: spyder/plugins/runconfig.py:406
+#: spyder/plugins/runconfig.py:426
msgid "Select a run configuration:"
msgstr "Wählen Sie eine Ausführungskonfiguration aus:"
-#: spyder/plugins/runconfig.py:435 spyder/plugins/runconfig.py:460
-msgid "Run Settings"
-msgstr "Ausführungseinstellungen"
+#: spyder/plugins/runconfig.py:455
+msgid "Run configuration per file"
+msgstr "Dateiweise Ausführungskonfiguration"
-#: spyder/plugins/runconfig.py:462
+#: spyder/plugins/runconfig.py:480
msgid ""
-"The following are the default %s. These options may be overriden "
-"using the %s dialog box (see the %s menu)"
+"The following are the default options for running files.These options may be "
+"overriden using the Configuration per file entry of the Run "
+"menu."
msgstr ""
-"Diese Optionen können mit dem Dialogfenster %s überschrieben werden "
-"(siehe Menü %s)"
+"Die folgenden Optionen sind der Standard beim Ausführen von Dateien. Diese "
+"Optionen können mit dem Dialogfenster Dateiweise Konfiguration... im "
+"Menü Ausführenüberschrieben werden."
-#: spyder/plugins/runconfig.py:488
+#: spyder/plugins/runconfig.py:516
msgid "Default working directory is:"
msgstr "Voreingestelltes Arbeitsverzeichnis ist:"
-#: spyder/plugins/runconfig.py:490
-msgid "the script directory"
-msgstr "das Skriptverzeichnis"
-
-#: spyder/plugins/runconfig.py:493 spyder/plugins/workingdirectory.py:56
-msgid "the following directory:"
-msgstr "das folgende Verzeichnis:"
-
-#: spyder/plugins/runconfig.py:522
-msgid "Show warning when killing running processes"
-msgstr "Warnung beim Töten laufender Prozesse anzeigen"
-
-#: spyder/plugins/runconfig.py:531
+#: spyder/plugins/runconfig.py:556
msgid "Run Settings dialog"
msgstr "Dialog Ausführungseinstellungen"
#: spyder/plugins/shortcuts.py:65
-msgid "Currently used to delete lines on editor"
-msgstr "Wird derzeit verwendet, um Zeilen im Editor zu löschen"
+msgid "Currently used to delete lines on editor/Cut a word"
+msgstr ""
+"Wird derzeit verwendet, um Zeilen im Editor zu löschen/Worte auszuschneiden"
+
+#: spyder/plugins/shortcuts.py:66
+msgid "Currently used to paste a word"
+msgstr "Wird derzeit verwendet, um ein Wort einzufügen"
-#: spyder/plugins/shortcuts.py:69
+#: spyder/plugins/shortcuts.py:70
msgid "We cannot support this shortcut on Windows"
msgstr "Wir können diese Tastenkombination unter Windows nicht unterstützen"
-#: spyder/plugins/shortcuts.py:72
+#: spyder/plugins/shortcuts.py:73
msgid "Shortcuts that use Shift and another key are unsupported"
msgstr ""
"Tastenkombinationen, die die Umschalttaste und eine andere Taste verwenden, "
"werden nicht unterstützt"
-#: spyder/plugins/shortcuts.py:149
+#: spyder/plugins/shortcuts.py:150
msgid ""
"Press the new shortcut and select 'Ok': \n"
"(Press 'Tab' once to switch focus between the shortcut entry \n"
@@ -3310,180 +3237,173 @@ msgstr ""
"(Drücken Sie die 'Tabulatortaste' einmal, um den Fokus zwischen\n"
"dem Tastenkombinations-Eintrag und den Tasten unten zu wechseln)"
-#: spyder/plugins/shortcuts.py:152
+#: spyder/plugins/shortcuts.py:153
msgid "Current shortcut:"
msgstr "Aktuelle Tastenkombination:"
-#: spyder/plugins/shortcuts.py:154
+#: spyder/plugins/shortcuts.py:155
msgid "New shortcut:"
msgstr "Neue Tastenkombination:"
-#: spyder/plugins/shortcuts.py:167
+#: spyder/plugins/shortcuts.py:168
msgid "Shortcut: {0}"
msgstr "Tastenkombination: {0}"
-#: spyder/plugins/shortcuts.py:288
+#: spyder/plugins/shortcuts.py:307
msgid "Please introduce a different shortcut"
msgstr "Bitte geben Sie ein anderes Tastenkürzel ein"
# TYPO in source: 'shorcut'
-#: spyder/plugins/shortcuts.py:325
-msgid "The new shorcut conflicts with:"
+#: spyder/plugins/shortcuts.py:344
+msgid "The new shortcut conflicts with:"
msgstr "Das neue Tastenkürzel steht im Konflikt zu:"
-#: spyder/plugins/shortcuts.py:334 spyder/plugins/shortcuts.py:343
+#: spyder/plugins/shortcuts.py:353 spyder/plugins/shortcuts.py:362
msgid "Forbidden key sequence!"
msgstr "Verbotene Tastenfolge!"
-#: spyder/plugins/shortcuts.py:354
+#: spyder/plugins/shortcuts.py:373
msgid ""
"A compound sequence can have {break} a maximum of 4 subsequences.{break}"
msgstr ""
-"Eine zusammengesetzte Sequenz {break} kann maximal 4 Teilsequenzen "
-"haben.{break}"
+"Eine zusammengesetzte Sequenz {break} kann maximal 4 Teilsequenzen haben."
+"{break}"
-#: spyder/plugins/shortcuts.py:359
+#: spyder/plugins/shortcuts.py:378
msgid "Invalid key entered"
msgstr "Ungültige Taste eingegeben"
-#: spyder/plugins/shortcuts.py:567
+#: spyder/plugins/shortcuts.py:585
msgid "Context"
msgstr "Kontext"
-#: spyder/plugins/shortcuts.py:569
-#: spyder/widgets/variableexplorer/collectionseditor.py:140
+#: spyder/plugins/shortcuts.py:587
+#: spyder/widgets/variableexplorer/collectionseditor.py:153
msgid "Name"
msgstr "Name"
-#: spyder/plugins/shortcuts.py:571
+#: spyder/plugins/shortcuts.py:589
msgid "Shortcut"
msgstr "Tastenkombination"
-#: spyder/plugins/shortcuts.py:573
+#: spyder/plugins/shortcuts.py:591
msgid "Score"
msgstr "Ergebnis"
-#: spyder/plugins/shortcuts.py:733
+#: spyder/plugins/shortcuts.py:752
msgid "Conflicts"
msgstr "Konflikte"
-#: spyder/plugins/shortcuts.py:734
+#: spyder/plugins/shortcuts.py:753
msgid "The following conflicts have been detected:"
msgstr "Die folgenden Konflikte wurden entdeckt:"
-#: spyder/plugins/shortcuts.py:819
+#: spyder/plugins/shortcuts.py:838
msgid "Keyboard shortcuts"
msgstr "Tastenkombinationen"
-#: spyder/plugins/shortcuts.py:827
+#: spyder/plugins/shortcuts.py:846
msgid "Search: "
msgstr "Suchen: "
-#: spyder/plugins/shortcuts.py:828
+#: spyder/plugins/shortcuts.py:847
msgid "Reset to default values"
msgstr "Auf die Standardwerte zurücksetzen"
-#: spyder/plugins/variableexplorer.py:25
+#: spyder/plugins/shortcuts.py:877
+msgid "Shortcuts reset"
+msgstr "Tastenkombinationen zurücksetzen"
+
+#: spyder/plugins/shortcuts.py:878
+msgid "Do you want to reset to default values?"
+msgstr "Auf Standardwerte zurücksetzen?"
+
+#: spyder/plugins/variableexplorer.py:24
+msgid "View and edit DataFrames and Series in the Variable Explorer"
+msgstr "DatenRahmen und -Serien im Variablenmanager anzeigen und bearbeiten"
+
+#: spyder/plugins/variableexplorer.py:29
+msgid "View and edit two and three dimensional arrays in the Variable Explorer"
+msgstr ""
+"Zwei- und dreidimensionale Arrays im Variablenmanager anzeigen und bearbeiten"
+
+#: spyder/plugins/variableexplorer.py:37
msgid "Filter"
msgstr "Filter"
-#: spyder/plugins/variableexplorer.py:27
-#: spyder/widgets/variableexplorer/namespacebrowser.py:173
+#: spyder/plugins/variableexplorer.py:39
+#: spyder/widgets/variableexplorer/namespacebrowser.py:203
msgid "Exclude private references"
msgstr "Private Referenzen ausschließen"
-#: spyder/plugins/variableexplorer.py:28
-#: spyder/widgets/variableexplorer/namespacebrowser.py:188
+#: spyder/plugins/variableexplorer.py:40
+#: spyder/widgets/variableexplorer/namespacebrowser.py:218
msgid "Exclude capitalized references"
msgstr "Großgeschriebene Referenzen ausschließen"
-#: spyder/plugins/variableexplorer.py:29
-#: spyder/widgets/variableexplorer/namespacebrowser.py:181
+#: spyder/plugins/variableexplorer.py:41
+#: spyder/widgets/variableexplorer/namespacebrowser.py:211
msgid "Exclude all-uppercase references"
msgstr "Alle Referenzen in Großschrift ausschließen"
-#: spyder/plugins/variableexplorer.py:30
-#: spyder/widgets/variableexplorer/namespacebrowser.py:196
+#: spyder/plugins/variableexplorer.py:42
+#: spyder/widgets/variableexplorer/namespacebrowser.py:226
msgid "Exclude unsupported data types"
msgstr "Nicht unterstützte Datentypen ausschließen"
-#: spyder/plugins/variableexplorer.py:36
-#: spyder/widgets/variableexplorer/collectionseditor.py:716
+#: spyder/plugins/variableexplorer.py:48
+#: spyder/widgets/variableexplorer/collectionseditor.py:738
msgid "Show arrays min/max"
msgstr "Arrays min/max anzeigen"
-#: spyder/plugins/variableexplorer.py:176
+#: spyder/plugins/variableexplorer.py:202
msgid "Variable explorer"
msgstr "Variablenmanager"
-#: spyder/plugins/workingdirectory.py:37
+#: spyder/plugins/workingdirectory.py:39
msgid ""
-"The global working directory is the working directory for newly "
-"opened consoles (Python/IPython consoles and terminals), for the "
-"file explorer, for the find in files plugin and for new files "
-"created in the editor."
+"The current working directory is the working directory for IPython "
+"consoles and the current directory for the File Explorer."
msgstr ""
-"Das globale Arbeitsverzeichnis ist das Arbeitsverzeichnis für neu "
-"geöffnete Konsolen (Python/IPython-Konsolen und Terminals), für den "
-"Dateimanager, für das Plugin find in files und für neue "
-"Dateien, die im Editor erstellt wurden."
+"Das aktuelle Arbeitsverzeichnis ist das Arbeitsverzeichnis für "
+"IPython-Konsolen und das aktuelle Verzeichnis des Dateimanagers."
-#: spyder/plugins/workingdirectory.py:46
-msgid "At startup, the global working directory is:"
-msgstr "Beim Start ist das globale Arbeitsverzeichnis:"
+#: spyder/plugins/workingdirectory.py:44
+msgid "Console directory"
+msgstr "Verzeichnis der Konsole"
-#: spyder/plugins/workingdirectory.py:50
-msgid "the same as in last session"
-msgstr "das gleiche wie in der letzten Sitzung"
+#: spyder/plugins/workingdirectory.py:45
+msgid "The working directory for new consoles is:"
+msgstr "Arbeitsverzeichnis für neue Konsolen ist:"
-#: spyder/plugins/workingdirectory.py:52
-msgid "At startup, Spyder will restore the global directory from last session"
+#: spyder/plugins/workingdirectory.py:49
+msgid ""
+"The current project directory or user home directory (if no project is "
+"active)"
msgstr ""
-"Beim Start wird Spyder das globale Verzeichnis aus der letzten Sitzung "
-"wiederherstellen"
-
-#: spyder/plugins/workingdirectory.py:58
-msgid "At startup, the global working directory will be the specified path"
-msgstr "Beim Start ist das globale Arbeitsverzeichnis der angegebene Pfad"
-
-#: spyder/plugins/workingdirectory.py:70
-msgid "Files are opened from:"
-msgstr "Dateien werden geöffnet aus:"
-
-#: spyder/plugins/workingdirectory.py:74 spyder/plugins/workingdirectory.py:87
-msgid "the current file directory"
-msgstr "das aktuelle Dateiverzeichnis"
-
-#: spyder/plugins/workingdirectory.py:78 spyder/plugins/workingdirectory.py:91
-msgid "the global working directory"
-msgstr "das globale Arbeitsverzeichnis"
-
-#: spyder/plugins/workingdirectory.py:83
-msgid "Files are created in:"
-msgstr "Dateien werden erstellt in:"
-
-#: spyder/plugins/workingdirectory.py:97
-msgid "Change to file base directory"
-msgstr "In Dateibasisverzeichnis wechseln"
+"Das aktuelle Projektverzeichnis oder das Benutzerverzeichnis (wenn kein "
+"Projekt aktiv ist)"
-#: spyder/plugins/workingdirectory.py:99
-msgid "When opening a file"
-msgstr "Beim Öffnen einer Datei"
+#: spyder/plugins/workingdirectory.py:62
+msgid "the following directory:"
+msgstr "das folgende Verzeichnis:"
-#: spyder/plugins/workingdirectory.py:101
-msgid "When saving a file"
-msgstr "Beim Speichern einer Datei"
+#: spyder/plugins/workingdirectory.py:64
+msgid "The directory when a new console is open will be the specified path"
+msgstr ""
+"Beim öffnen einer neuen Konsole ist das globale Arbeitsverzeichnis der "
+"angegebene Pfad"
-#: spyder/plugins/workingdirectory.py:169
+#: spyder/plugins/workingdirectory.py:124
msgid "Back"
msgstr "Zurück"
-#: spyder/plugins/workingdirectory.py:177 spyder/widgets/explorer.py:1139
-#: spyder/widgets/variableexplorer/importwizard.py:537
+#: spyder/plugins/workingdirectory.py:130 spyder/widgets/explorer.py:1199
+#: spyder/widgets/variableexplorer/importwizard.py:539
msgid "Next"
msgstr "Weiter"
-#: spyder/plugins/workingdirectory.py:188
+#: spyder/plugins/workingdirectory.py:141
msgid ""
"This is the working directory for newly\n"
"opened consoles (Python/IPython consoles and\n"
@@ -3497,31 +3417,39 @@ msgstr ""
"das Finden im Dateien-Plugin und für neue\n"
"Dateien, die im Editor erstellt wurden"
-#: spyder/plugins/workingdirectory.py:216
+#: spyder/plugins/workingdirectory.py:166
msgid "Browse a working directory"
msgstr "Arbeitsverzeichnis durchsuchen"
-#: spyder/plugins/workingdirectory.py:223
+#: spyder/plugins/workingdirectory.py:173
msgid "Change to parent directory"
msgstr "Zum übergeordneten Verzeichnis wechseln"
-#: spyder/plugins/workingdirectory.py:230
-msgid "Global working directory"
-msgstr "Globales Arbeitsverzeichnis"
+#: spyder/plugins/workingdirectory.py:180 spyder/widgets/findinfiles.py:240
+msgid "Current working directory"
+msgstr "Aktuelles Arbeitsverzeichnis"
-#: spyder/utils/codeanalysis.py:92
+#: spyder/utils/codeanalysis.py:94
msgid "Real-time code analysis on the Editor"
msgstr "Echtzeit-Codeanalyse im Editor"
-#: spyder/utils/codeanalysis.py:96
+#: spyder/utils/codeanalysis.py:98
msgid "Real-time code style analysis on the Editor"
msgstr "Echtzeit-Programmierstilanalyse im Editor"
-#: spyder/utils/environ.py:46 spyder/widgets/externalshell/pythonshell.py:307
+#: spyder/utils/environ.py:48
msgid "Environment variables"
msgstr "Umgebungsvariablen"
-#: spyder/utils/environ.py:96
+#: spyder/utils/environ.py:57
+msgid ""
+"An error occurred while trying to show your environment variables. The error "
+"was
{0}"
+msgstr ""
+"Beim anzeigen Ihrer Umgebungsvariablen ist ein Fehler aufgetreten. Der "
+"Fehler war
{0}"
+
+#: spyder/utils/environ.py:108
msgid ""
"Module pywin32 was not found.
Please restart this Windows "
"session (not the computer) for changes to take effect."
@@ -3530,171 +3458,113 @@ msgstr ""
"Windows-Sitzung (nicht den Computer) neu, damit die Änderungen "
"wirksam werden."
-#: spyder/utils/environ.py:109
+#: spyder/utils/environ.py:121
msgid ""
"If you accept changes, this will modify the current user environment "
"variables directly in Windows registry. Use it with precautions, at "
"your own risks.
Note that for changes to take effect, you will need "
"to restart the parent process of this application (simply restart Spyder if "
"you have executed it from a Windows shortcut, otherwise restart any "
-"application from which you may have executed it, like Python(x,y) "
-"Home for example)"
+"application from which you may have executed it, like Python(x,y) Home"
+"i> for example)"
msgstr ""
"Wenn Sie Änderungen akzeptieren, werden die aktuellen "
-"Benutzerumgebungsvariablen direkt in der "
-"Windows-Registrierungsdatenbank geändert. Verwenden Sie es mit Vorsicht, "
-"auf eigene Gefahr.
Beachten Sie, damit die Änderungen wirksam werden, "
-"müssen Sie den übergeordneten Prozess dieser Anwendung neu starten (starten "
-"Sie Spyder einfach neu, wenn Sie es über eine Windows-Verknüpfung ausgeführt "
-"haben, andernfalls starten Sie jede Anwendung neu, von wo Sie sie ausgeführt "
-"haben, wie zum Beispiel Python(x,y) Heimverzeichnis)"
-
-#: spyder/utils/help/sphinxify.py:217 spyder/utils/help/sphinxify.py:227
+"Benutzerumgebungsvariablen direkt in der Windows-Registrierungsdatenbank"
+"b> geändert. Verwenden Sie es mit Vorsicht, auf eigene Gefahr."
+"
Beachten Sie, damit die Änderungen wirksam werden, müssen Sie den "
+"übergeordneten Prozess dieser Anwendung neu starten (starten Sie Spyder "
+"einfach neu, wenn Sie es über eine Windows-Verknüpfung ausgeführt haben, "
+"andernfalls starten Sie jede Anwendung neu, von wo Sie sie ausgeführt haben, "
+"wie zum Beispiel Python(x,y) Heimverzeichnis)"
+
+#: spyder/utils/help/sphinxify.py:216 spyder/utils/help/sphinxify.py:226
msgid ""
"It was not possible to generate rich text help for this object.Please "
"see it in plain text."
msgstr ""
-"Es war nicht möglich, Rich-Text-Hilfe für dieses Objekt zu "
-"erzeugen.Bitte sehen Sie es sich im Klartext an."
+"Es war nicht möglich, Rich-Text-Hilfe für dieses Objekt zu erzeugen."
+"br>Bitte sehen Sie es sich im Klartext an."
-#: spyder/utils/introspection/manager.py:33
-#: spyder/utils/introspection/manager.py:38
+#: spyder/utils/introspection/manager.py:34
+#: spyder/utils/introspection/manager.py:39
msgid "Editor's code completion, go-to-definition and help"
msgstr "Codevervollständigung, Gehe-zu-Definition und Hilfe des Editors"
-#: spyder/utils/iofuncs.py:407
-msgid "Supported files"
-msgstr "Unterstützte Dateien"
-
-#: spyder/utils/iofuncs.py:409
-msgid "All files (*.*)"
-msgstr "Alle Dateien (*.*)"
-
-#: spyder/utils/iofuncs.py:419
-msgid "Spyder data files"
-msgstr "Spyder-Datendateien"
-
-#: spyder/utils/iofuncs.py:421
-#: spyder/widgets/variableexplorer/collectionseditor.py:1071
-msgid "NumPy arrays"
-msgstr "NumPy-Arrays"
-
-#: spyder/utils/iofuncs.py:422
-msgid "NumPy zip arrays"
-msgstr "NumPy zip-Arrays"
-
-#: spyder/utils/iofuncs.py:423
-msgid "Matlab files"
-msgstr "Matlab-Dateien"
-
-#: spyder/utils/iofuncs.py:424
-msgid "CSV text files"
-msgstr "CSV-Textdateien"
-
-#: spyder/utils/iofuncs.py:426
-msgid "JPEG images"
-msgstr "JPEG-Bilder"
-
-#: spyder/utils/iofuncs.py:427
-msgid "PNG images"
-msgstr "PNG-Bilder"
-
-#: spyder/utils/iofuncs.py:428
-msgid "GIF images"
-msgstr "GIF-Bilder"
-
-#: spyder/utils/iofuncs.py:429
-msgid "TIFF images"
-msgstr "TIFF-Bilder"
-
-#: spyder/utils/iofuncs.py:430 spyder/utils/iofuncs.py:431
-msgid "Pickle files"
-msgstr "Pickle-Dateien"
-
-#: spyder/utils/iofuncs.py:432
-msgid "JSON files"
-msgstr "JSON-Dateien"
-
-#: spyder/utils/iofuncs.py:451 spyder/utils/iofuncs.py:458
-msgid "Unsupported file type '%s'"
-msgstr "Nicht unterstützter Dateityp '%s'"
-
-#: spyder/utils/programs.py:287
+#: spyder/utils/programs.py:308
msgid "It was not possible to run this file in an external terminal"
msgstr ""
"Es war nicht möglich, diese Datei in einem externen Terminal auszuführen"
-#: spyder/utils/syntaxhighlighters.py:34
+#: spyder/utils/syntaxhighlighters.py:35
msgid "Syntax highlighting for Matlab, Julia and other file types"
msgstr "Syntaxhervorhebung für Matlab, Julia und andere Dateitypen"
-#: spyder/utils/syntaxhighlighters.py:43
+#: spyder/utils/syntaxhighlighters.py:44
msgid "Background:"
msgstr "Hintergrund:"
-#: spyder/utils/syntaxhighlighters.py:44
-#: spyder/widgets/sourcecode/codeeditor.py:114
+#: spyder/utils/syntaxhighlighters.py:45
+#: spyder/widgets/sourcecode/codeeditor.py:107
msgid "Current line:"
msgstr "Aktuelle Zeile:"
-#: spyder/utils/syntaxhighlighters.py:45
+#: spyder/utils/syntaxhighlighters.py:46
msgid "Current cell:"
msgstr "Aktuelle Zelle:"
-#: spyder/utils/syntaxhighlighters.py:46
+#: spyder/utils/syntaxhighlighters.py:47
msgid "Occurrence:"
msgstr "Vorkommen:"
-#: spyder/utils/syntaxhighlighters.py:47
+#: spyder/utils/syntaxhighlighters.py:48
msgid "Link:"
msgstr "Link:"
-#: spyder/utils/syntaxhighlighters.py:48
+#: spyder/utils/syntaxhighlighters.py:49
msgid "Side areas:"
msgstr "Seitenbereiche:"
-#: spyder/utils/syntaxhighlighters.py:49
+#: spyder/utils/syntaxhighlighters.py:50
msgid "Matched
parens:"
msgstr "Zusammenpassende
runde Klammern:"
-#: spyder/utils/syntaxhighlighters.py:50
+#: spyder/utils/syntaxhighlighters.py:51
msgid "Unmatched
parens:"
msgstr "Nicht zusammenpassende
runde Klammern:"
-#: spyder/utils/syntaxhighlighters.py:51
+#: spyder/utils/syntaxhighlighters.py:52
msgid "Normal text:"
msgstr "Normaler Text:"
-#: spyder/utils/syntaxhighlighters.py:52
+#: spyder/utils/syntaxhighlighters.py:53
msgid "Keyword:"
msgstr "Schlüsselwort:"
-#: spyder/utils/syntaxhighlighters.py:53
+#: spyder/utils/syntaxhighlighters.py:54
msgid "Builtin:"
msgstr "Eingebaut:"
-#: spyder/utils/syntaxhighlighters.py:54
+#: spyder/utils/syntaxhighlighters.py:55
msgid "Definition:"
msgstr "Definition:"
-#: spyder/utils/syntaxhighlighters.py:55
+#: spyder/utils/syntaxhighlighters.py:56
msgid "Comment:"
msgstr "Kommentar:"
-#: spyder/utils/syntaxhighlighters.py:56
+#: spyder/utils/syntaxhighlighters.py:57
msgid "String:"
msgstr "Zeichenkette:"
-#: spyder/utils/syntaxhighlighters.py:57
+#: spyder/utils/syntaxhighlighters.py:58
msgid "Number:"
msgstr "Zahl:"
-#: spyder/utils/syntaxhighlighters.py:58
+#: spyder/utils/syntaxhighlighters.py:59
msgid "Instance:"
msgstr "Instanz:"
#: spyder/widgets/arraybuilder.py:179
-#, fuzzy
msgid ""
"\n"
" Numpy Array/Matrix Helper
\n"
@@ -3710,7 +3580,7 @@ msgstr ""
"\n"
" Numpy Array/Matrix-Helfer
\n"
" Geben Sie ein Array in Matlab ein: [1 2;3 4]
\n"
-" oder Spyder vereinfachte Syntax : 1 2;3 4
\n"
+" oder Spyder vereinfachte Syntax : 1 2;3 4
\n"
"
\n"
" Drücken Sie 'Eingabe' für Array oder 'Strg+Eingabe' für Matrix.\n"
"
\n"
@@ -3748,39 +3618,39 @@ msgstr ""
msgid "Array dimensions not valid"
msgstr "Array-Dimensionen nicht gültig"
-#: spyder/widgets/browser.py:55 spyder/widgets/sourcecode/codeeditor.py:2364
+#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2738
msgid "Zoom out"
msgstr "Hinauszoomen"
-#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2360
+#: spyder/widgets/browser.py:61 spyder/widgets/sourcecode/codeeditor.py:2734
msgid "Zoom in"
msgstr "Hineinzoomen"
-#: spyder/widgets/browser.py:179
+#: spyder/widgets/browser.py:216
msgid "Home"
msgstr "Zuhause"
-#: spyder/widgets/browser.py:215
+#: spyder/widgets/browser.py:252
msgid "Find text"
msgstr "Text suchen"
-#: spyder/widgets/browser.py:233
+#: spyder/widgets/browser.py:269
msgid "Address:"
msgstr "Adresse:"
-#: spyder/widgets/browser.py:269
+#: spyder/widgets/browser.py:305
msgid "Unable to load page"
msgstr "Die Seite kann nicht geladen werden"
-#: spyder/widgets/comboboxes.py:162
+#: spyder/widgets/comboboxes.py:165
msgid "Press enter to validate this entry"
msgstr "Drücken Sie die Eingabetaste, um diesen Eintrag zu bestätigen"
-#: spyder/widgets/comboboxes.py:163
+#: spyder/widgets/comboboxes.py:166
msgid "This entry is incorrect"
msgstr "Dieser Eintrag ist falsch"
-#: spyder/widgets/comboboxes.py:206
+#: spyder/widgets/comboboxes.py:209
msgid "Press enter to validate this path"
msgstr "Drücken Sie die Eingabetaste, um diesen Pfad zu bestätigen"
@@ -3809,15 +3679,15 @@ msgid ""
"Spyder depends on several Python modules to provide the right functionality "
"for all its panes. The table below shows the required and installed versions "
"(if any) of all of them.
Note: You can safely use Spyder "
-"without the following modules installed: %s and "
-"%s.
Please also note that new dependencies or changed ones "
-"will be correctly detected only after Spyder is restarted."
+"without the following modules installed: %s and %s."
+"
Please also note that new dependencies or changed ones will be "
+"correctly detected only after Spyder is restarted."
msgstr ""
"Spyder hängt von mehreren Python-Modulen ab, um die richtige Funktionalität "
"für all seine Bereiche zu bieten. Die folgende Tabelle zeigt die "
-"erforderlichen und installierten Versionen (falls vorhanden) von "
-"allen.
Hinweis: Sie können Spyder sicher verwenden, ohne dass "
-"die folgenden Module installiert sind: %s und %s.
Bitte "
+"erforderlichen und installierten Versionen (falls vorhanden) von allen."
+"
Hinweis: Sie können Spyder sicher verwenden, ohne dass die "
+"folgenden Module installiert sind: %s und %s.
Bitte "
"beachten Sie auch, dass neue Abhängigkeiten oder geänderte erst nach dem "
"Neustart von Spyder korrekt erkannt werden."
@@ -3825,77 +3695,78 @@ msgstr ""
msgid "Copy to clipboard"
msgstr "In Zwischenablage kopieren"
-#: spyder/widgets/editor.py:473
+#: spyder/widgets/editor.py:511
msgid "Find symbols in file..."
msgstr "Symbole in Datei suchen..."
-#: spyder/widgets/editor.py:476
+#: spyder/widgets/editor.py:514
msgid "Copy path to clipboard"
msgstr "Pfad in die Zwischenablage kopieren"
-#: spyder/widgets/editor.py:480
+#: spyder/widgets/editor.py:518
msgid "Close all to the right"
msgstr "Alles auf der rechten Seite schließen"
-#: spyder/widgets/editor.py:482
+#: spyder/widgets/editor.py:520
msgid "Close all but this"
msgstr "Alles außer dieser schließen"
-#: spyder/widgets/editor.py:486 spyder/widgets/explorer.py:329
+#: spyder/widgets/editor.py:524 spyder/widgets/explorer.py:373
msgid "Show in Finder"
msgstr "In Finder anzeigen"
-#: spyder/widgets/editor.py:488 spyder/widgets/explorer.py:331
+#: spyder/widgets/editor.py:526 spyder/widgets/explorer.py:375
msgid "Show in external file explorer"
msgstr "In externem Dateimanager anzeigen"
-#: spyder/widgets/editor.py:1159
+#: spyder/widgets/editor.py:1201
msgid "Temporary file"
msgstr "Temporäre Datei"
-#: spyder/widgets/editor.py:1246
+#: spyder/widgets/editor.py:1287
msgid "New window"
msgstr "Neues Fenster"
-#: spyder/widgets/editor.py:1247
+#: spyder/widgets/editor.py:1288
msgid "Create a new editor window"
msgstr "Neues Editorfenster erstellen"
-#: spyder/widgets/editor.py:1250
+#: spyder/widgets/editor.py:1291
msgid "Split vertically"
msgstr "Vertikal teilen"
-#: spyder/widgets/editor.py:1252
+#: spyder/widgets/editor.py:1293
msgid "Split vertically this editor window"
msgstr "Dieses Editorfenster vertikal teilen"
-#: spyder/widgets/editor.py:1254
+#: spyder/widgets/editor.py:1295
msgid "Split horizontally"
msgstr "Horizontal teilen"
-#: spyder/widgets/editor.py:1256
+#: spyder/widgets/editor.py:1297
msgid "Split horizontally this editor window"
msgstr "Dieses Editorfenster horizontal teilen"
-#: spyder/widgets/editor.py:1258
+#: spyder/widgets/editor.py:1299
msgid "Close this panel"
msgstr "Diesen Bereich schließen"
-#: spyder/widgets/editor.py:1436
+#: spyder/widgets/editor.py:1534
msgid "%s has been modified.
Do you want to save changes?"
msgstr "%s wurde geändert.
Möchten Sie die Änderungen speichern?"
-#: spyder/widgets/editor.py:1499 spyder/widgets/editor.py:1588
-msgid "Save"
-msgstr "Speichern"
+#: spyder/widgets/editor.py:1620 spyder/widgets/editor.py:1783
+#: spyder/widgets/explorer.py:82
+msgid "Save Error"
+msgstr "Fehler speichern"
-#: spyder/widgets/editor.py:1500 spyder/widgets/editor.py:1589
-#: spyder/widgets/shell.py:267
+#: spyder/widgets/editor.py:1621 spyder/widgets/editor.py:1784
+#: spyder/widgets/explorer.py:83
msgid "Unable to save file '%s'
Error message:
%s"
msgstr ""
"Datei '%s' kann nicht gespeichert werden
Fehlermeldung:
%s"
-#: spyder/widgets/editor.py:1763
+#: spyder/widgets/editor.py:1971
msgid ""
"%s is unavailable (this file may have been removed, moved or renamed "
"outside Spyder).
Do you want to close it?"
@@ -3904,7 +3775,7 @@ msgstr ""
"von Spyder entfernt, verschoben oder umbenannt).
Möchten Sie sie "
"schließen?"
-#: spyder/widgets/editor.py:1783
+#: spyder/widgets/editor.py:1994
msgid ""
"%s has been modified outside Spyder.
Do you want to reload it and "
"lose all your changes?"
@@ -3912,7 +3783,7 @@ msgstr ""
"%s wurde außerhalb von Spyder geändert.
Möchten Sie sie neu laden "
"und all Ihre Änderungen verlieren?"
-#: spyder/widgets/editor.py:1889
+#: spyder/widgets/editor.py:2104
msgid ""
"All changes to %s will be lost.
Do you want to revert file from "
"disk?"
@@ -3920,11 +3791,11 @@ msgstr ""
"Alle Änderungen an %s gehen verloren.
Möchten Sie die Datei von "
"der Festplatte zurücksetzen?"
-#: spyder/widgets/editor.py:2032
+#: spyder/widgets/editor.py:2250
msgid "Loading %s..."
msgstr "%s wird geladen..."
-#: spyder/widgets/editor.py:2042
+#: spyder/widgets/editor.py:2262
msgid ""
"%s contains mixed end-of-line characters.
Spyder will fix this "
"automatically."
@@ -3932,11 +3803,11 @@ msgstr ""
"%s enthält gemischte Zeilenendezeichen.
Spyder wird dies "
"automatisch beheben."
-#: spyder/widgets/editor.py:2466
+#: spyder/widgets/editor.py:2672
msgid "Close window"
msgstr "Fenster schließen"
-#: spyder/widgets/editor.py:2468
+#: spyder/widgets/editor.py:2674
msgid "Close this window"
msgstr "Dieses Fenster schließen"
@@ -3960,129 +3831,129 @@ msgstr "Funktion definiert bei Zeile %s"
msgid "Cell starts at line %s"
msgstr "Zelle beginnt bei Zeile %s"
-#: spyder/widgets/editortools.py:203 spyder/widgets/editortools.py:540
+#: spyder/widgets/editortools.py:201 spyder/widgets/editortools.py:527
msgid "Go to cursor position"
msgstr "Gehe zu Cursorposition"
-#: spyder/widgets/editortools.py:206
+#: spyder/widgets/editortools.py:204
msgid "Show absolute path"
msgstr "Absoluten Pfad anzeigen"
-#: spyder/widgets/editortools.py:209 spyder/widgets/explorer.py:242
+#: spyder/widgets/editortools.py:207 spyder/widgets/explorer.py:286
msgid "Show all files"
msgstr "Alle Dateien anzeigen"
-#: spyder/widgets/editortools.py:212
+#: spyder/widgets/editortools.py:210
msgid "Show special comments"
msgstr "Besondere Kommentare anzeigen"
-#: spyder/widgets/editortools.py:511
+#: spyder/widgets/editortools.py:500
msgid "Show/hide outline explorer"
msgstr "Gliederungsmanager anzeigen/ausblenden"
-#: spyder/widgets/explorer.py:238
+#: spyder/widgets/explorer.py:282
msgid "Edit filename filters..."
msgstr "Dateinamensfilter bearbeiten..."
-#: spyder/widgets/explorer.py:252
+#: spyder/widgets/explorer.py:296
msgid "Edit filename filters"
msgstr "Dateinamensfilter bearbeiten"
-#: spyder/widgets/explorer.py:253
+#: spyder/widgets/explorer.py:297
msgid "Name filters:"
msgstr "Namensfilter:"
-#: spyder/widgets/explorer.py:272
+#: spyder/widgets/explorer.py:316
msgid "File..."
msgstr "Datei..."
-#: spyder/widgets/explorer.py:276
+#: spyder/widgets/explorer.py:320
msgid "Module..."
msgstr "Modul..."
-#: spyder/widgets/explorer.py:280
+#: spyder/widgets/explorer.py:324
msgid "Folder..."
msgstr "Ordner..."
-#: spyder/widgets/explorer.py:284
+#: spyder/widgets/explorer.py:328
msgid "Package..."
msgstr "Paket..."
-#: spyder/widgets/explorer.py:305
-#: spyder/widgets/variableexplorer/collectionseditor.py:691
+#: spyder/widgets/explorer.py:349
+#: spyder/widgets/variableexplorer/collectionseditor.py:713
msgid "Edit"
msgstr "Bearbeiten"
-#: spyder/widgets/explorer.py:307
+#: spyder/widgets/explorer.py:351
msgid "Move..."
msgstr "Verschieben..."
-#: spyder/widgets/explorer.py:310
+#: spyder/widgets/explorer.py:354
msgid "Delete..."
msgstr "Löschen..."
-#: spyder/widgets/explorer.py:313
+#: spyder/widgets/explorer.py:357
msgid "Rename..."
msgstr "Umbenennen..."
-#: spyder/widgets/explorer.py:316
+#: spyder/widgets/explorer.py:360
msgid "Open"
msgstr "Öffnen"
-#: spyder/widgets/explorer.py:317 spyder/widgets/sourcecode/codeeditor.py:2332
+#: spyder/widgets/explorer.py:361 spyder/widgets/sourcecode/codeeditor.py:2706
msgid "Convert to Python script"
msgstr "Zu Python-Skript konvertieren"
-#: spyder/widgets/explorer.py:358
+#: spyder/widgets/explorer.py:393
msgid "Commit"
msgstr "Commit"
-#: spyder/widgets/explorer.py:361
+#: spyder/widgets/explorer.py:396
msgid "Browse repository"
msgstr "Repositorium durchsuchen"
-#: spyder/widgets/explorer.py:372
+#: spyder/widgets/explorer.py:407
msgid "Open command prompt here"
msgstr "Eingabeaufforderung hier öffnen"
-#: spyder/widgets/explorer.py:374
+#: spyder/widgets/explorer.py:409
msgid "Open terminal here"
msgstr "Terminal hier öffnen"
-#: spyder/widgets/explorer.py:375
+#: spyder/widgets/explorer.py:410
msgid "Open IPython console here"
msgstr "IPython-Konsole hier öffnen"
-#: spyder/widgets/explorer.py:389
+#: spyder/widgets/explorer.py:424
msgid "New"
msgstr "Neu"
-#: spyder/widgets/explorer.py:397
+#: spyder/widgets/explorer.py:432
msgid "Import"
msgstr "Importieren"
-#: spyder/widgets/explorer.py:543
+#: spyder/widgets/explorer.py:583
msgid "Do you really want to delete %s?"
msgstr "Möchten Sie %s wirklich löschen?"
-#: spyder/widgets/explorer.py:561
+#: spyder/widgets/explorer.py:601
msgid "delete"
msgstr "löschen"
-#: spyder/widgets/explorer.py:562 spyder/widgets/projects/explorer.py:148
-#: spyder/widgets/projects/explorer.py:248
+#: spyder/widgets/explorer.py:602 spyder/widgets/projects/explorer.py:148
+#: spyder/widgets/projects/explorer.py:256
msgid "Project Explorer"
msgstr "Projektmanager"
-#: spyder/widgets/explorer.py:563 spyder/widgets/projects/explorer.py:149
+#: spyder/widgets/explorer.py:603 spyder/widgets/projects/explorer.py:149
msgid "Unable to %s %s
Error message:
%s"
msgstr "Kann nicht %s %s
Fehlermeldung:
%s"
-#: spyder/widgets/explorer.py:578
+#: spyder/widgets/explorer.py:618
msgid "File Explorer"
msgstr "Dateimanager"
-#: spyder/widgets/explorer.py:579
+#: spyder/widgets/explorer.py:619
msgid ""
"The current directory contains a project.
If you want to delete the "
"project, please go to Projects » Delete Project"
@@ -4091,11 +3962,11 @@ msgstr ""
"löschen möchten, gehen Sie bitte zu Projekte » Projekt "
"löschen"
-#: spyder/widgets/explorer.py:596 spyder/widgets/sourcecode/codeeditor.py:1811
+#: spyder/widgets/explorer.py:636 spyder/widgets/sourcecode/codeeditor.py:2167
msgid "Conversion error"
msgstr "Konvertierungsfehler"
-#: spyder/widgets/explorer.py:597 spyder/widgets/sourcecode/codeeditor.py:1812
+#: spyder/widgets/explorer.py:637 spyder/widgets/sourcecode/codeeditor.py:2168
msgid ""
"It was not possible to convert this notebook. The error is:\n"
"\n"
@@ -4103,435 +3974,529 @@ msgstr ""
"Es war nicht möglich, dieses Notebook zu konvertieren. Der Fehler ist:\n"
"\n"
-#: spyder/widgets/explorer.py:614 spyder/widgets/explorer.py:622
-#: spyder/widgets/explorer.py:633
-#: spyder/widgets/variableexplorer/collectionseditor.py:720
-#: spyder/widgets/variableexplorer/collectionseditor.py:966
+#: spyder/widgets/explorer.py:654 spyder/widgets/explorer.py:662
+#: spyder/widgets/explorer.py:676
+#: spyder/widgets/variableexplorer/collectionseditor.py:742
+#: spyder/widgets/variableexplorer/collectionseditor.py:988
msgid "Rename"
msgstr "Umbenennen"
-#: spyder/widgets/explorer.py:615
+#: spyder/widgets/explorer.py:655
msgid "New name:"
msgstr "Neuer Name:"
-#: spyder/widgets/explorer.py:623
+#: spyder/widgets/explorer.py:663
msgid ""
-"Do you really want to rename %s and overwrite the existing file "
-"%s?"
+"Do you really want to rename %s and overwrite the existing file "
+"%s?"
msgstr ""
"Möchten Sie %s wirklich umbenennen und die vorhandene Datei %s "
"überschreiben?"
-#: spyder/widgets/explorer.py:634
+#: spyder/widgets/explorer.py:677
msgid "Unable to rename file %s
Error message:
%s"
msgstr ""
-"Datei %s kann nicht umbenannt "
-"werden
Fehlermeldung:
%s"
+"Datei %s kann nicht umbenannt werden
Fehlermeldung:
"
+"%s"
-#: spyder/widgets/explorer.py:677
+#: spyder/widgets/explorer.py:724
msgid "Unable to move %s
Error message:
%s"
msgstr ""
"%s kann nicht verschoben werden
Fehlermeldung:
%s"
-#: spyder/widgets/explorer.py:695
+#: spyder/widgets/explorer.py:742
msgid "Unable to create folder %s
Error message:
%s"
msgstr ""
-"Ordner %s kann nicht erstellt "
-"werden
Fehlermeldung:
%s"
+"Ordner %s kann nicht erstellt werden
Fehlermeldung:
"
+"%s"
-#: spyder/widgets/explorer.py:708 spyder/widgets/explorer.py:742
+#: spyder/widgets/explorer.py:755 spyder/widgets/explorer.py:789
msgid "Unable to create file %s
Error message:
%s"
msgstr ""
"Datei %s kann nicht erstellt werden
Fehlermeldung:
%s"
-#: spyder/widgets/explorer.py:716
+#: spyder/widgets/explorer.py:763
msgid "New folder"
msgstr "Neuer Ordner"
-#: spyder/widgets/explorer.py:717
+#: spyder/widgets/explorer.py:764
msgid "Folder name:"
msgstr "Ordnername:"
-#: spyder/widgets/explorer.py:722
+#: spyder/widgets/explorer.py:769
msgid "New package"
msgstr "Neues Paket"
-#: spyder/widgets/explorer.py:723
+#: spyder/widgets/explorer.py:770
msgid "Package name:"
msgstr "Paketname:"
-#: spyder/widgets/explorer.py:763
+#: spyder/widgets/explorer.py:810
msgid "New module"
msgstr "Neues Modul"
-#: spyder/widgets/explorer.py:781
+#: spyder/widgets/explorer.py:825
msgid ""
"For %s support, please install one of the
following tools:
%s"
msgstr ""
"Für %s-Unterstützung installieren Sie bitte eines der
folgenden "
"Werkzeuge:
%s"
-#: spyder/widgets/explorer.py:785
+#: spyder/widgets/explorer.py:829
msgid "Unable to find external program.
%s"
msgstr "Externes Programm kann nicht gefunden werden.
%s"
-#: spyder/widgets/explorer.py:1008
+#: spyder/widgets/explorer.py:1049
msgid "Show current directory only"
msgstr "Nur aktuelles Verzeichnis anzeigen"
-#: spyder/widgets/explorer.py:1108
+#: spyder/widgets/explorer.py:1163
msgid "You don't have the right permissions to open this directory"
msgstr ""
"Sie haben nicht die richtigen Berechtigungen, um dieses Verzeichnis zu öffnen"
-#: spyder/widgets/explorer.py:1136
-#: spyder/widgets/variableexplorer/importwizard.py:533
+#: spyder/widgets/explorer.py:1194
+msgid "Show icons and text"
+msgstr "Symbole und Text anzeigen"
+
+#: spyder/widgets/explorer.py:1196
+#: spyder/widgets/variableexplorer/importwizard.py:535
msgid "Previous"
msgstr "Vorheriges"
-#: spyder/widgets/explorer.py:1142
-msgid "Parent"
-msgstr "Übergeordnetes"
-
-#: spyder/widgets/externalshell/baseshell.py:129
-msgid "Run again this program"
-msgstr "Dieses Programm erneut ausführen"
-
-#: spyder/widgets/externalshell/baseshell.py:132
-msgid "Kill"
-msgstr "Töten"
-
-#: spyder/widgets/externalshell/baseshell.py:134
-msgid "Kills the current process, causing it to exit immediately"
-msgstr "Tötet den aktuellen Prozess und veranlasst ihn sofort zu beenden"
-
-#: spyder/widgets/externalshell/baseshell.py:206
-msgid "Running..."
-msgstr "Läuft..."
-
-#: spyder/widgets/externalshell/baseshell.py:213
-msgid "Terminated."
-msgstr "Terminiert."
-
-#: spyder/widgets/externalshell/baseshell.py:238
-#: spyder/widgets/ipythonconsole/help.py:131 spyder/widgets/mixins.py:692
-msgid "Arguments"
-msgstr "Argumente"
-
-#: spyder/widgets/externalshell/baseshell.py:239
-msgid "Command line arguments:"
-msgstr "Befehlszeilenargumente:"
-
-#: spyder/widgets/externalshell/pythonshell.py:45
-msgid ""
-"NOTE: The Python console is going to be REMOVED in Spyder 3.2. Please start "
-"to migrate your work to the IPython console instead.\n"
-"\n"
-msgstr ""
-"HINWEIS: Die Python-Konsole wird in Spyder 3.2 ENTFERNT. Bitte beginnen Sie, "
-"Ihre Arbeit auf die IPython-Konsole zu migrieren.\n"
-"\n"
-
-#: spyder/widgets/externalshell/pythonshell.py:272
-msgid "Variables"
-msgstr "Variablen"
-
-#: spyder/widgets/externalshell/pythonshell.py:273
-msgid "Show/hide global variables explorer"
-msgstr "Globalen Variablenmanager anzeigen/ausblenden"
-
-#: spyder/widgets/externalshell/pythonshell.py:277
-msgid "Terminate"
-msgstr "Terminieren"
-
-#: spyder/widgets/externalshell/pythonshell.py:278
-msgid ""
-"Attempts to stop the process. The process\n"
-"may not exit as a result of clicking this\n"
-"button (it is given the chance to prompt\n"
-"the user for any unsaved files, etc)."
-msgstr ""
-"Versucht, den Prozess zu stoppen. Der\n"
-"Prozess kann nicht durch Klicken auf diese\n"
-"Schaltfläche beendet werden (es wird die\n"
-"Chance gegeben, den Benutzer alle nicht\n"
-"gespeicherten Dateien usw. zu melden)."
-
-#: spyder/widgets/externalshell/pythonshell.py:291
-msgid "Interact"
-msgstr "Interagieren"
-
-#: spyder/widgets/externalshell/pythonshell.py:293
-msgid "Debug"
-msgstr "Debug"
-
-#: spyder/widgets/externalshell/pythonshell.py:295
-#: spyder/widgets/externalshell/pythonshell.py:361
-msgid "Arguments..."
-msgstr "Argumente..."
-
-#: spyder/widgets/externalshell/pythonshell.py:297
-msgid "Post Mortem Debug"
-msgstr "Post-Mortem-Debug"
-
-#: spyder/widgets/externalshell/pythonshell.py:303
-msgid "Working directory"
-msgstr "Arbeitsverzeichnis"
-
-#: spyder/widgets/externalshell/pythonshell.py:305
-msgid "Set current working directory"
-msgstr "Aktuelles Arbeitsverzeichnis festlegen"
-
-#: spyder/widgets/externalshell/pythonshell.py:311
-#: spyder/widgets/ipythonconsole/client.py:272
-msgid "Show sys.path contents"
-msgstr "sys.path-Inhalt anzeigen"
-
-#: spyder/widgets/externalshell/pythonshell.py:357
-msgid "Arguments: %s"
-msgstr "Argumente: %s"
-
-#: spyder/widgets/externalshell/pythonshell.py:359
-msgid "No argument"
-msgstr "Kein Argument"
-
-#: spyder/widgets/externalshell/pythonshell.py:527
-msgid "A Python console failed to start!"
-msgstr "Eine Python-Konsole konnte nicht gestartet werden!"
-
-#: spyder/widgets/externalshell/systemshell.py:106
-msgid "Process failed to start"
-msgstr "Der Prozess konnte nicht gestartet werden"
-
-#: spyder/widgets/fileswitcher.py:109
+#: spyder/widgets/fileswitcher.py:110
msgid "unsaved file"
msgstr "ungespeicherte Datei"
-#: spyder/widgets/fileswitcher.py:245
+#: spyder/widgets/fileswitcher.py:249
msgid ""
"Press Enter to switch files or Esc to cancel.
Type to "
"filter filenames.
Use :number to go to a line, e.g. "
-"main:42
Use @symbol_text to go to a symbol, "
-"e.g. @init
Press Ctrl+W to close current "
+"main:42
Use @symbol_text to go to a symbol, e."
+"g. @init
Press Ctrl+W to close current "
"tab.
"
msgstr ""
"Drücken Sie Eingabe, um Dateien zu wechseln oder Esc zum "
"Abbrechen.
Tippen Sie, um Dateinamen zu filtern.
Verwenden Sie "
-":Nummer, um zu einer Zeile zu gehen, z.B. "
-"main:42
Verwenden Sie @symbol_text, um zu "
-"einem Symbol zu gehen, z.B. @init
Drücken Sie "
-"Strg+W, um die aktuelle Registerkarte zu schließen.
"
+":Nummer, um zu einer Zeile zu gehen, z.B. main:42
"
+"b>
Verwenden Sie @symbol_text, um zu einem Symbol zu gehen, z.B. "
+"@init
Drücken Sie Strg+W, um die aktuelle "
+"Registerkarte zu schließen.
"
-#: spyder/widgets/fileswitcher.py:533
+#: spyder/widgets/fileswitcher.py:663
msgid "lines"
msgstr "Zeilen"
-#: spyder/widgets/findinfiles.py:97
+#: spyder/widgets/findinfiles.py:121
msgid "Unexpected error: see internal console"
msgstr "Unerwarteter Fehler: siehe interne Konsole"
-#: spyder/widgets/findinfiles.py:125
+#: spyder/widgets/findinfiles.py:158
msgid "invalid regular expression"
msgstr "ungültiger regulärer Ausdruck"
-#: spyder/widgets/findinfiles.py:216
+#: spyder/widgets/findinfiles.py:217
msgid "permission denied errors were encountered"
msgstr "Fehler zu verweigerter Erlaubnis wurden vorgefunden"
-#: spyder/widgets/findinfiles.py:254
+#: spyder/widgets/findinfiles.py:232
+msgid "Search directory"
+msgstr "Verzeichnis durchsuchen"
+
+#: spyder/widgets/findinfiles.py:245
+msgid "Project"
+msgstr "Projekt"
+
+# TYPO in source: No blank space in 'thecurrent'
+#: spyder/widgets/findinfiles.py:246
+msgid ""
+"Search in all files and directories present on the current project path (if "
+"opened)"
+msgstr ""
+"In allen Dateien und Verzeichnissen, die im aktuellen Projektpfad vorhanden "
+"sind, suchen (falls geöffnet)"
+
+#: spyder/widgets/findinfiles.py:251
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "File"
+msgstr "Datei"
+
+#: spyder/widgets/findinfiles.py:252
+msgid "Search in current opened file"
+msgstr "In der aktuell geöffneten Datei suchen"
+
+#: spyder/widgets/findinfiles.py:257
+msgid "Select other directory"
+msgstr "Anderes Verzeichnis auswählen"
+
+#: spyder/widgets/findinfiles.py:258
+msgid "Search in other folder present on the file system"
+msgstr "In anderem Ordner suchen"
+
+#: spyder/widgets/findinfiles.py:262
+msgid "Clear the list of other directories"
+msgstr "Die Liste der anderen Verzeichnisse säubern"
+
+#: spyder/widgets/findinfiles.py:333
+msgid "Clear other directories"
+msgstr "Andere Verzeichnisse leeren"
+
+#: spyder/widgets/findinfiles.py:334
+msgid "Do you want to clear the list of other directories?"
+msgstr "Möchten Sie die Liste der anderen Verzeichnisse leeren?"
+
+#: spyder/widgets/findinfiles.py:404 spyder/widgets/findreplace.py:52
+msgid "Regular expression error"
+msgstr "Fehler im regulären Ausdruck"
+
+#: spyder/widgets/findinfiles.py:427
msgid "Search pattern"
msgstr "Suchmuster"
-#: spyder/widgets/findinfiles.py:257 spyder/widgets/findinfiles.py:292
-#: spyder/widgets/findreplace.py:89
+#: spyder/widgets/findinfiles.py:430 spyder/widgets/findinfiles.py:470
+#: spyder/widgets/findreplace.py:100
msgid "Regular expression"
msgstr "Regulärer Ausdruck"
-#: spyder/widgets/findinfiles.py:266
+#: spyder/widgets/findinfiles.py:433 spyder/widgets/findreplace.py:106
+msgid "Case Sensitive"
+msgstr "Groß-/Kleinschreibung beachten"
+
+#: spyder/widgets/findinfiles.py:444
msgid "Search"
msgstr "Suchen"
-#: spyder/widgets/findinfiles.py:269
+#: spyder/widgets/findinfiles.py:447
msgid "Start search"
msgstr "Suche starten"
-#: spyder/widgets/findinfiles.py:276
-msgid "Stop search"
-msgstr "Suche stoppen"
-
-#: spyder/widgets/findinfiles.py:286
-msgid "Excluded filenames pattern"
-msgstr "Ausgeschlossene Dateinamensmuster"
-
-#: spyder/widgets/findinfiles.py:295
-msgid "Exclude:"
-msgstr "Ausschließen:"
-
-#: spyder/widgets/findinfiles.py:304
-msgid "Path"
-msgstr "Pfad"
-
-# TYPO in source: No blank space in 'thecurrent'
-#: spyder/widgets/findinfiles.py:306
-msgid "Search in all files and directories present on thecurrent Spyder path"
-msgstr ""
-"In allen Dateien und Verzeichnissen, die im aktuellen Spyder-Pfad vorhanden "
-"sind, suchen"
-
-#: spyder/widgets/findinfiles.py:310
-msgid "Project"
-msgstr "Projekt"
+#: spyder/widgets/findinfiles.py:454
+msgid "Stop search"
+msgstr "Suche stoppen"
-# TYPO in source: No blank space in 'thecurrent'
-#: spyder/widgets/findinfiles.py:311
-msgid ""
-"Search in all files and directories present on thecurrent project path (If "
-"opened)"
-msgstr ""
-"In allen Dateien und Verzeichnissen, die im aktuellen Projektpfad vorhanden "
-"sind, suchen (falls geöffnet)"
+#: spyder/widgets/findinfiles.py:464
+msgid "Exclude pattern"
+msgstr "Muster ausschließen"
-#: spyder/widgets/findinfiles.py:317
-msgid "File"
-msgstr "Datei"
+#: spyder/widgets/findinfiles.py:473
+msgid "Exclude:"
+msgstr "Ausschließen:"
-#: spyder/widgets/findinfiles.py:318
-msgid "Search in current opened file"
-msgstr "In der aktuell geöffneten Datei suchen"
+#: spyder/widgets/findinfiles.py:482
+msgid "Search in:"
+msgstr "Suchen in:"
-#: spyder/widgets/findinfiles.py:348
+#: spyder/widgets/findinfiles.py:511
msgid "Hide advanced options"
msgstr "Erweiterte Optionen ausblenden"
-#: spyder/widgets/findinfiles.py:351
+#: spyder/widgets/findinfiles.py:514
msgid "Show advanced options"
msgstr "Erweiterte Optionen anzeigen"
-#: spyder/widgets/findinfiles.py:593 spyder/widgets/findinfiles.py:610
+#: spyder/widgets/findinfiles.py:790 spyder/widgets/findinfiles.py:877
msgid "String not found"
msgstr "Zeichenkette nicht gefunden"
-#: spyder/widgets/findinfiles.py:612
+#: spyder/widgets/findinfiles.py:879
msgid "matches in"
msgstr "Übereinstimmungen in"
-#: spyder/widgets/findinfiles.py:613
+#: spyder/widgets/findinfiles.py:880
msgid "file"
msgstr "Datei"
-#: spyder/widgets/findinfiles.py:660
+#: spyder/widgets/findinfiles.py:912
+msgid " Scanning: {0}"
+msgstr " Untersuche: {0}"
+
+#: spyder/widgets/findinfiles.py:914
+msgid " Searching for files in folder: {0}"
+msgstr " Suche nach Dateien im Ordner: {0}"
+
+#: spyder/widgets/findinfiles.py:918
msgid " Searching for files..."
msgstr " Suche nach Dateien..."
-#: spyder/widgets/findreplace.py:65
+#: spyder/widgets/findreplace.py:49
+msgid "No matches"
+msgstr "Keine Übereinstimmungen"
+
+#: spyder/widgets/findreplace.py:50 spyder/widgets/findreplace.py:51
+#: spyder/widgets/findreplace.py:73
msgid "Search string"
msgstr "Suchbegriff"
-#: spyder/widgets/findreplace.py:95
-msgid "Case Sensitive"
-msgstr "Groß-/Kleinschreibung beachten"
-
-#: spyder/widgets/findreplace.py:101
+#: spyder/widgets/findreplace.py:112
msgid "Whole words"
msgstr "Ganze Wörter"
-#: spyder/widgets/findreplace.py:107
+#: spyder/widgets/findreplace.py:118
msgid "Highlight matches"
msgstr "Übereinstimmungen hervorheben"
-#: spyder/widgets/findreplace.py:121
+#: spyder/widgets/findreplace.py:132
msgid "Replace with:"
msgstr "Ersetzen mit:"
-#: spyder/widgets/findreplace.py:123
+#: spyder/widgets/findreplace.py:134
msgid "Replace string"
msgstr "Zeichenkette ersetzen"
-#: spyder/widgets/findreplace.py:127
-msgid "Replace/find"
-msgstr "Ersetzen/suchen"
+#: spyder/widgets/findreplace.py:138
+msgid "Replace/find next"
+msgstr "Nächstes ersetzen/suchen"
-#: spyder/widgets/findreplace.py:134
+#: spyder/widgets/findreplace.py:143
+msgid "Replace selection"
+msgstr "Auswahl ersetzen"
+
+#: spyder/widgets/findreplace.py:151
msgid "Replace all"
msgstr "Alle ersetzen"
-#: spyder/widgets/internalshell.py:262
+#: spyder/widgets/findreplace.py:583
+msgid "of"
+msgstr "von"
+
+#: spyder/widgets/findreplace.py:587
+msgid "matches"
+msgstr "Übereinstimmungen"
+
+#: spyder/widgets/findreplace.py:590
+msgid "no matches"
+msgstr "keine Übereinstimmungen"
+
+#: spyder/widgets/github/backend.py:151
+msgid "Invalid credentials"
+msgstr "Ungültige Anmeldedaten"
+
+#: spyder/widgets/github/backend.py:152
+msgid "Failed to create Github issue, invalid credentials..."
+msgstr ""
+"Erstellen des Github-Fehlerberichts fehlgeschlagen, ungültige Anmeldedaten..."
+
+#: spyder/widgets/github/backend.py:159
+msgid "Failed to create issue"
+msgstr "Erstellen des Fehlerberichts fehlgeschlagen"
+
+#: spyder/widgets/github/backend.py:160
+msgid "Failed to create Github issue. Error %d"
+msgstr "Erstellen des Github-Fehlerberichts fehlgeschlagen. Fehler %d"
+
+#: spyder/widgets/github/backend.py:167
+msgid "Issue created on Github"
+msgstr "Fehlerbericht auf Github erstellt"
+
+#: spyder/widgets/github/backend.py:168
+msgid ""
+"Issue successfully created. Would you like to open the issue in your web "
+"browser?"
+msgstr ""
+"Fehlerbericht erfolgreich erstellt. Wollen Sie den Bericht in Ihrem "
+"Webbrowser anzeigen?"
+
+#: spyder/widgets/github/backend.py:195
+msgid "Failed to store password"
+msgstr "Speichern des Passworts fehlgeschlagen"
+
+#: spyder/widgets/github/backend.py:196
+msgid ""
+"It was not possible to securely save your password. You will be prompted for "
+"your Github credentials next time you want to report an issue."
+msgstr ""
+"Es war nicht möglich ihr Passwort sicher zu speichern. Sie werden nach Ihren "
+"Github-Anmeldedaten gefragt, wenn sie das nächste mal einen Fehler melden "
+"wollen."
+
+#: spyder/widgets/github/backend.py:212
+msgid "Failed to store token"
+msgstr "Speichern des Tokens fehlgeschlagen"
+
+#: spyder/widgets/github/backend.py:213
+msgid ""
+"It was not possible to securely save your token. You will be prompted for "
+"your Github token next time you want to report an issue."
+msgstr ""
+"Es war nicht möglich ihren Token sicher zu speichern. Sie werden nach Ihrem "
+"Github-Token gefragt, wenn sie das nächste mal einen Fehler melden wollen."
+
+#: spyder/widgets/github/backend.py:237
+msgid "Failed to retrieve password"
+msgstr "Passwort kann nicht abgerufen werden"
+
+#: spyder/widgets/github/backend.py:238
+msgid ""
+"It was not possible to retrieve your password. Please introduce it again."
+msgstr ""
+"Es war nicht möglich, Ihr Passwort abzurufen. Bitte geben Sie es erneut ein."
+
+#: spyder/widgets/github/backend.py:249
+msgid "Failed to retrieve token"
+msgstr "Token kann nicht abgerufen werden"
+
+#: spyder/widgets/github/backend.py:250
+msgid "It was not possible to retrieve your token. Please introduce it again."
+msgstr ""
+"Es war nicht möglich, Ihren Token abzurufen. Bitte geben Sie es erneut ein."
+
+#: spyder/widgets/github/gh_login.py:38
+msgid "Sign in to Github"
+msgstr "In Github anmelden"
+
+#: spyder/widgets/github/gh_login.py:57
+msgid ""
+"For regular users, i.e. users without two-factor authentication "
+"enabled"
+msgstr "Für übliche Benutzer, d.h. ohne Zwei-Faktor-Authentifizierung"
+
+#: spyder/widgets/github/gh_login.py:62
+msgid "Username:"
+msgstr "Benutzername:"
+
+#: spyder/widgets/github/gh_login.py:69
+msgid "Password: "
+msgstr "Passwort: "
+
+#: spyder/widgets/github/gh_login.py:81
+msgid "Remember me"
+msgstr "Login merken"
+
+#: spyder/widgets/github/gh_login.py:82
+msgid "Spyder will save your credentials safely"
+msgstr "Spyder wird Ihre Anmeldedaten sicher speichern"
+
+#: spyder/widgets/github/gh_login.py:99
+msgid "Password Only"
+msgstr "Nur Passwort"
+
+#: spyder/widgets/github/gh_login.py:105
+msgid ""
+"For users with two-factor authentication enabled, or who prefer a per-"
+"app token authentication.
You can go here "
+"and click \"Generate token\" at the bottom to create a new token to use for "
+"this, with the appropriate permissions."
+msgstr ""
+"Für Benutzer mit Zwei-Faktor-Authentifizierung, oder die einen Pro-"
+"App-Token-Authentifizierung bevorzugen.
Sie könnenhier am Ende der Seite auf \"Generate token\" klicken, um "
+"einen neuen Token mit den entsprechenden Rechten zu erstellen."
+
+#: spyder/widgets/github/gh_login.py:127
+msgid "Remember token"
+msgstr "Token merken"
+
+#: spyder/widgets/github/gh_login.py:128
+msgid "Spyder will save your token safely"
+msgstr "Spyder wird ihren Token sicher speichern"
+
+#: spyder/widgets/github/gh_login.py:145
+msgid "Access Token"
+msgstr "Zugangs-Token"
+
+#: spyder/widgets/github/gh_login.py:148
+msgid "Sign in"
+msgstr "Anmelden"
+
+#: spyder/widgets/internalshell.py:263
msgid "Help..."
msgstr "Hilfe..."
-#: spyder/widgets/internalshell.py:279
+#: spyder/widgets/internalshell.py:280
msgid "Shell special commands:"
msgstr "Shell-Spezialbefehle:"
-#: spyder/widgets/internalshell.py:280
+#: spyder/widgets/internalshell.py:281
msgid "Internal editor:"
msgstr "Interner Editor:"
-#: spyder/widgets/internalshell.py:281
+#: spyder/widgets/internalshell.py:282
msgid "External editor:"
msgstr "Externer Editor:"
-#: spyder/widgets/internalshell.py:282
+#: spyder/widgets/internalshell.py:283
msgid "Run script:"
msgstr "Skript ausführen:"
-#: spyder/widgets/internalshell.py:283
+#: spyder/widgets/internalshell.py:284
msgid "Remove references:"
msgstr "Referenzen entfernen:"
-#: spyder/widgets/internalshell.py:284
+#: spyder/widgets/internalshell.py:285
msgid "System commands:"
msgstr "Systembefehle:"
-#: spyder/widgets/internalshell.py:285
+#: spyder/widgets/internalshell.py:286
msgid "Python help:"
msgstr "Python-Hilfe:"
-#: spyder/widgets/internalshell.py:286
+#: spyder/widgets/internalshell.py:287
msgid "GUI-based editor:"
msgstr "GUI-basierter Editor:"
-#: spyder/widgets/ipythonconsole/client.py:233
+#: spyder/widgets/internalshell.py:418
+msgid ""
+"In order to use commands like \"raw_input\" or \"input\" run Spyder with the "
+"multithread option (--multithread) from a system terminal"
+msgstr ""
+"Um Kommandos wie \"raw_input\" oder \"input\" zu benutzen müssen Sie Spyder "
+"mit der multithread-Option (--multithread) aus einer System-Konsole starten"
+
+#: spyder/widgets/ipythonconsole/client.py:308
msgid "An error ocurred while starting the kernel"
msgstr "Beim Starten des Kernels ist ein Fehler aufgetreten"
-#: spyder/widgets/ipythonconsole/client.py:266
+#: spyder/widgets/ipythonconsole/client.py:352
+#: spyder/widgets/ipythonconsole/client.py:408
+#: spyder/widgets/ipythonconsole/client.py:441
+#: spyder/widgets/ipythonconsole/shell.py:234
+#: spyder/widgets/variableexplorer/namespacebrowser.py:196
+msgid "Remove all variables"
+msgstr "Alle Dateien entfernen"
+
+#: spyder/widgets/ipythonconsole/client.py:361
msgid "Show environment variables"
msgstr "Umgebungsvariablen anzeigen"
-#: spyder/widgets/ipythonconsole/client.py:293
+#: spyder/widgets/ipythonconsole/client.py:368
+msgid "Show sys.path contents"
+msgstr "sys.path-Inhalt anzeigen"
+
+#: spyder/widgets/ipythonconsole/client.py:395
msgid "Stop the current command"
msgstr "Aktuellen Befehl stoppen"
-#: spyder/widgets/ipythonconsole/client.py:316
+#: spyder/widgets/ipythonconsole/client.py:406
+#: spyder/widgets/variableexplorer/collectionseditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:970
+msgid "Remove"
+msgstr "Entfernen"
+
+#: spyder/widgets/ipythonconsole/client.py:429
msgid "Inspect current object"
msgstr "Aktuelles Objekt inspizieren"
-#: spyder/widgets/ipythonconsole/client.py:321
+#: spyder/widgets/ipythonconsole/client.py:435
msgid "Clear line or block"
msgstr "Zeile oder Block löschen"
-#: spyder/widgets/ipythonconsole/client.py:325
-msgid "Reset namespace"
-msgstr "Namensraum zurücksetzen"
-
-#: spyder/widgets/ipythonconsole/client.py:328
+#: spyder/widgets/ipythonconsole/client.py:448
msgid "Clear console"
msgstr "Konsole leeren"
-#: spyder/widgets/ipythonconsole/client.py:371
+#: spyder/widgets/ipythonconsole/client.py:507
msgid "Are you sure you want to restart the kernel?"
msgstr "Sind Sie sicher, dass Sie den Kernel neu starten möchten?"
-#: spyder/widgets/ipythonconsole/client.py:373
+#: spyder/widgets/ipythonconsole/client.py:509
msgid "Restart kernel?"
msgstr "Kernel neu starten?"
-#: spyder/widgets/ipythonconsole/client.py:385
+#: spyder/widgets/ipythonconsole/client.py:526
msgid "Error restarting kernel: %s\n"
msgstr "Fehler beim Neustarten des Kernels: %s\n"
-#: spyder/widgets/ipythonconsole/client.py:390
+#: spyder/widgets/ipythonconsole/client.py:534
msgid ""
"
Restarting kernel...\n"
"
"
@@ -4539,44 +4504,55 @@ msgstr ""
"
Kernel wird neu gestartet...\n"
"
"
-#: spyder/widgets/ipythonconsole/client.py:394
+#: spyder/widgets/ipythonconsole/client.py:538
msgid "Cannot restart a kernel not started by Spyder\n"
msgstr "Kann keinen Kernel neu starten, der nicht von Spyder gestartet wurde\n"
-#: spyder/widgets/ipythonconsole/client.py:466
+#: spyder/widgets/ipythonconsole/client.py:649
msgid "Connecting to kernel..."
msgstr "Verbindungsaufbau mit Kernel..."
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:126
+#: spyder/widgets/ipythonconsole/help.py:128 spyder/widgets/mixins.py:726
+msgid "Arguments"
+msgstr "Argumente"
+
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:138
msgid "Loading this kind of data while debugging is not supported."
msgstr ""
"Das Laden dieser Art von Daten während des Debuggens wird nicht unterstützt."
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:145
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:157
msgid "Saving data while debugging is not supported."
msgstr "Das Speichern von Daten während des Debuggens wird nicht unterstützt."
-#: spyder/widgets/ipythonconsole/shell.py:169
-msgid "Reset IPython namespace"
-msgstr "IPython-Namensraum zurücksetzen"
+#: spyder/widgets/ipythonconsole/shell.py:235
+msgid ""
+"All user-defined variables will be removed. Are you sure you want to proceed?"
+msgstr ""
+"Alle benutzerdefinierten Variablen werden entfernt. Sind Sie sicher, dass "
+"Sie fortsetzen wollen?"
+
+#: spyder/widgets/ipythonconsole/shell.py:241
+msgid "Don't show again."
+msgstr "Nicht wieder anzeigen."
-#: spyder/widgets/ipythonconsole/shell.py:170
+#: spyder/widgets/ipythonconsole/shell.py:266
msgid ""
-"All user-defined variables will be removed.
Are you sure you want to "
-"reset the namespace?"
+"
Removing all variables...\n"
+"
"
msgstr ""
-"Alle benutzerdefinierten Variablen werden entfernt.
Sind Sie sicher, dass "
-"Sie den Namensraum zurücksetzen möchten?"
+"
Entferne alle Variablen...\n"
+"
"
-#: spyder/widgets/ipythonconsole/shell.py:320
-msgid "Changing backend to Qt for Mayavi"
-msgstr "Backend für Mayavi wird zu Qt geändert"
+#: spyder/widgets/ipythonconsole/shell.py:432
+msgid "Changing backend to Qt4 for Mayavi"
+msgstr "Backend für Mayavi wird zu Qt4 geändert"
-#: spyder/widgets/ipythonconsole/shell.py:358
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel died, restarting"
msgstr "Kernel gestorben, wie neu gestartet"
-#: spyder/widgets/ipythonconsole/shell.py:358
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel restarting"
msgstr "Kernel startet neu"
@@ -4604,61 +4580,70 @@ msgstr "Auswahl einklappen"
msgid "Expand selection"
msgstr "Auswahl ausklappen"
-#: spyder/widgets/pathmanager.py:87
+#: spyder/widgets/pathmanager.py:98
msgid "Move to top"
msgstr "Nach ganz oben verschieben"
-#: spyder/widgets/pathmanager.py:93
+#: spyder/widgets/pathmanager.py:104
msgid "Move up"
msgstr "Nach oben verschieben"
-#: spyder/widgets/pathmanager.py:99
+#: spyder/widgets/pathmanager.py:110
msgid "Move down"
msgstr "Nach unten verschieben"
-#: spyder/widgets/pathmanager.py:105
+#: spyder/widgets/pathmanager.py:116
msgid "Move to bottom"
msgstr "Nach ganz unten verschieben"
-#: spyder/widgets/pathmanager.py:116 spyder/widgets/pathmanager.py:231
+#: spyder/widgets/pathmanager.py:127 spyder/widgets/pathmanager.py:270
+#: spyder/widgets/pathmanager.py:282
msgid "Add path"
msgstr "Pfad hinzufügen"
-#: spyder/widgets/pathmanager.py:121 spyder/widgets/pathmanager.py:214
+#: spyder/widgets/pathmanager.py:132 spyder/widgets/pathmanager.py:247
msgid "Remove path"
msgstr "Pfad entfernen"
-#: spyder/widgets/pathmanager.py:131
+#: spyder/widgets/pathmanager.py:142
msgid "Synchronize..."
msgstr "Synchronisieren..."
-#: spyder/widgets/pathmanager.py:133
+#: spyder/widgets/pathmanager.py:144
msgid "Synchronize Spyder's path list with PYTHONPATH environment variable"
msgstr ""
"Spyders Pfadliste mit der Umgebungsvariablen PYTHONPATH synchronisieren"
-#: spyder/widgets/pathmanager.py:145
+#: spyder/widgets/pathmanager.py:156
msgid "Synchronize"
msgstr "Synchronisieren"
-#: spyder/widgets/pathmanager.py:146
+#: spyder/widgets/pathmanager.py:157
msgid ""
"This will synchronize Spyder's path list with PYTHONPATH environment "
"variable for current user, allowing you to run your Python modules outside "
"Spyder without having to configure sys.path.
Do you want to clear "
"contents of PYTHONPATH before adding Spyder's path list?"
msgstr ""
-"Dies synchronisiert die Spyder-Pfadliste mit der "
-"PYTHONPATH-Umgebungsvariablen für den aktuellen Benutzer, so dass Sie "
-"Ihre Python-Module außerhalb von Spyder ausführen können, ohne dass sys.path "
+"Dies synchronisiert die Spyder-Pfadliste mit der PYTHONPATH-"
+"Umgebungsvariablen für den aktuellen Benutzer, so dass Sie Ihre Python-"
+"Module außerhalb von Spyder ausführen können, ohne dass sys.path "
"konfiguriert werden muss.
Möchten Sie den Inhalt von PYTHONPATH löschen, "
"bevor Sie Spyders Pfadliste hinzufügen?"
-#: spyder/widgets/pathmanager.py:215
+#: spyder/widgets/pathmanager.py:248
msgid "Do you really want to remove selected path?"
msgstr "Möchten Sie den ausgewählten Pfad wirklich entfernen?"
-#: spyder/widgets/pathmanager.py:232
+#: spyder/widgets/pathmanager.py:271
+msgid ""
+"You are using Python 2 and the path selected has Unicode characters. The new "
+"path will not be added."
+msgstr ""
+"Sie benutzen Python 2 und der gewählte Pfad beinhaltet Unicode-Zeichen. Der "
+"neue Pfad wird nicht hinzugefügt."
+
+#: spyder/widgets/pathmanager.py:283
msgid ""
"This directory is already included in Spyder path list.
Do you want to "
"move it to the top of the list?"
@@ -4732,7 +4717,7 @@ msgstr "kopieren"
msgid "move"
msgstr "verschieben"
-#: spyder/widgets/projects/explorer.py:236
+#: spyder/widgets/projects/explorer.py:244
msgid ""
"Do you really want to delete {filename}?
Note: This "
"action will only delete the project. Its files are going to be preserved on "
@@ -4742,10 +4727,10 @@ msgstr ""
"Aktion löscht nur das Projekt. Dessen Dateien bleiben auf der Festplatte "
"erhalten."
-#: spyder/widgets/projects/explorer.py:249
+#: spyder/widgets/projects/explorer.py:257
msgid ""
-"Unable to delete {varpath}
The error message "
-"was:
{error}"
+"Unable to delete {varpath}
The error message was:"
+"
{error}"
msgstr ""
"{varpath} kann nicht gelöscht werden
Die Fehlermeldung "
"war:
{error}"
@@ -4775,7 +4760,7 @@ msgid "Python version"
msgstr "Python-Version"
#: spyder/widgets/projects/projectdialog.py:83
-#: spyder/widgets/variableexplorer/importwizard.py:527
+#: spyder/widgets/variableexplorer/importwizard.py:529
msgid "Cancel"
msgstr "Abbrechen"
@@ -4787,7 +4772,7 @@ msgstr "Erstellen"
msgid "Create new project"
msgstr "Neues Projekt erstellen"
-#: spyder/widgets/projects/type/__init__.py:215
+#: spyder/widgets/projects/type/__init__.py:223
msgid "Empty project"
msgstr "Leeres Projekt"
@@ -4799,10 +4784,108 @@ msgstr "Python-Projekt"
msgid "Python package"
msgstr "Python-Paket"
-#: spyder/widgets/pydocgui.py:110
+#: spyder/widgets/pydocgui.py:117
msgid "Module or package:"
msgstr "Modul oder Paket:"
+#: spyder/widgets/reporterror.py:128
+msgid "Issue reporter"
+msgstr "Problem melden"
+
+#: spyder/widgets/reporterror.py:136
+msgid "Please fill the following information"
+msgstr "Bitte füllen Sie die folgenden Informationen aus"
+
+#: spyder/widgets/reporterror.py:138
+msgid "Spyder has encountered an internal problem!"
+msgstr "Spyder hat ein internes Problem festgestellt!"
+
+#: spyder/widgets/reporterror.py:140
+msgid ""
+"{title}
Before reporting this problem, please consult our "
+"comprehensive Troubleshooting Guide "
+"which should help solve most issues, and search for known bugs matching your error message or problem "
+"description for a quicker solution."
+msgstr ""
+"{title}
Bevor Sie dieses Problem melden, konsultieren Sie bitte"
+"i> unsere umfassenden Fehlersuchhilfe, "
+"die dabei helfen sollte die meisten Probleme zu lösen. Suchen Sie auch nach "
+"bekannten Fehlern, die Ihrer "
+"Fehlermeldung oder Problembeschreibung entsprechen, um eine schnellere Hilfe "
+"zu erhalten."
+
+#: spyder/widgets/reporterror.py:158 spyder/widgets/reporterror.py:190
+msgid "{} more characters to go..."
+msgstr "{} weitere Zeichen notwendig..."
+
+#: spyder/widgets/reporterror.py:162
+msgid "Title: {}"
+msgstr "Titel: {}"
+
+#: spyder/widgets/reporterror.py:168
+msgid "Steps to reproduce: {}"
+msgstr "Schritte zum Reproduzieren: {}"
+
+#: spyder/widgets/reporterror.py:169
+msgid ""
+"Please enter a detailed step-by-step description (in English) of what led up "
+"to the problem below. Issue reports without a clear way to reproduce them "
+"will be closed."
+msgstr ""
+"Bitte geben sie eine detaillierte Schritt-für-Schritt-Beschreibung (in "
+"Englisch), was zu dem Problem geführt hat. Problemmeldungen ohne eine "
+"eindeutige Möglichkeit des Reproduzierens werden geschlossen."
+
+#: spyder/widgets/reporterror.py:194
+msgid "Hide all future errors during this session"
+msgstr "Verstecke alle zukünftigen Fehler während dieser Sitzung"
+
+#: spyder/widgets/reporterror.py:201
+msgid "Submit to Github"
+msgstr "Bei Github einreichen"
+
+#: spyder/widgets/reporterror.py:205 spyder/widgets/reporterror.py:312
+msgid "Show details"
+msgstr "Details anzeigen"
+
+#: spyder/widgets/reporterror.py:210
+#: spyder/widgets/variableexplorer/arrayeditor.py:740
+#: spyder/widgets/variableexplorer/collectionseditor.py:1397
+#: spyder/widgets/variableexplorer/dataframeeditor.py:756
+#: spyder/widgets/variableexplorer/texteditor.py:72
+msgid "Close"
+msgstr "S&chließen"
+
+#: spyder/widgets/reporterror.py:286
+msgid ""
+"An error occurred while trying to send the issue to Github automatically. "
+"Would you like to open it manually?
If so, please make sure to paste "
+"your clipboard into the issue report box that will appear in a new browser "
+"tab before clicking Submit on that page."
+msgstr ""
+"Während des automatischen Sendens des Problems an Github ist ein Fehler "
+"aufgetreten. Wollen Sie es manuell öffnen?
Falls ja, stellen Sie "
+"sicher das Sie den Inhalt ihrer Zwischenablage in die Fehlermeldungsbox "
+"einfügen, die in einem neuen Browser-Tab geöffnet wird, bevor sie auf "
+"Submit klicken."
+
+#: spyder/widgets/reporterror.py:320
+msgid "Hide details"
+msgstr "Details ausblenden"
+
+#: spyder/widgets/reporterror.py:329 spyder/widgets/reporterror.py:337
+msgid "more characters to go..."
+msgstr "weitere Zeichen notwendig..."
+
+#: spyder/widgets/reporterror.py:331
+msgid "Description complete; thanks!"
+msgstr "Beschreibung vollständig. Danke!"
+
+#: spyder/widgets/reporterror.py:339
+msgid "Title complete; thanks!"
+msgstr "Titel vollständig. Danke!"
+
#: spyder/widgets/shell.py:131
msgid "Save history log..."
msgstr "Chronikprotokoll speichern..."
@@ -4841,36 +4924,36 @@ msgstr "Shell-Inhalt löschen (Befehl 'cls')"
msgid "Spyder Keyboard ShortCuts"
msgstr "Spyder Tastaturkürzel"
-#: spyder/widgets/sourcecode/codeeditor.py:108
+#: spyder/widgets/sourcecode/codeeditor.py:101
msgid "Go to line:"
msgstr "Gehe zu Zeile:"
-#: spyder/widgets/sourcecode/codeeditor.py:116
+#: spyder/widgets/sourcecode/codeeditor.py:109
msgid "Line count:"
msgstr "Zeilenanzahl:"
-#: spyder/widgets/sourcecode/codeeditor.py:1079
+#: spyder/widgets/sourcecode/codeeditor.py:1334
msgid "Breakpoint"
msgstr "Haltepunkt"
-#: spyder/widgets/sourcecode/codeeditor.py:1080
+#: spyder/widgets/sourcecode/codeeditor.py:1335
msgid "Condition:"
msgstr "Bedingung:"
-#: spyder/widgets/sourcecode/codeeditor.py:1384
+#: spyder/widgets/sourcecode/codeeditor.py:1740
msgid "Code analysis"
msgstr "Codeanalyse"
# Im Sinne von Arbeiten, die noch zu machen sind.
-#: spyder/widgets/sourcecode/codeeditor.py:1438
+#: spyder/widgets/sourcecode/codeeditor.py:1794
msgid "To do"
msgstr "Offene Punkte"
-#: spyder/widgets/sourcecode/codeeditor.py:1798
+#: spyder/widgets/sourcecode/codeeditor.py:2154
msgid "Removal error"
msgstr "Entfernungsfehler"
-#: spyder/widgets/sourcecode/codeeditor.py:1799
+#: spyder/widgets/sourcecode/codeeditor.py:2155
msgid ""
"It was not possible to remove outputs from this notebook. The error is:\n"
"\n"
@@ -4879,15 +4962,15 @@ msgstr ""
"ist:\n"
"\n"
-#: spyder/widgets/sourcecode/codeeditor.py:2329
+#: spyder/widgets/sourcecode/codeeditor.py:2703
msgid "Clear all ouput"
msgstr "Gesamte Ausgabe löschen"
-#: spyder/widgets/sourcecode/codeeditor.py:2335
+#: spyder/widgets/sourcecode/codeeditor.py:2709
msgid "Go to definition"
msgstr "Gehe zur Definition"
-#: spyder/widgets/sourcecode/codeeditor.py:2368
+#: spyder/widgets/sourcecode/codeeditor.py:2742
msgid "Zoom reset"
msgstr "Zoom zurücksetzen"
@@ -4935,103 +5018,108 @@ msgstr "Zeile:"
msgid "Column:"
msgstr "Spalte:"
-#: spyder/widgets/tabs.py:146
+#: spyder/widgets/tabs.py:274
msgid "Browse tabs"
msgstr "Registerkarten durchsuchen"
-#: spyder/widgets/tabs.py:275
+#: spyder/widgets/tabs.py:413
msgid "Close current tab"
msgstr "Aktuelle Registerkarte schließen"
-#: spyder/widgets/variableexplorer/arrayeditor.py:498
+#: spyder/widgets/variableexplorer/arrayeditor.py:509
msgid "It was not possible to copy values for this array"
msgstr "Es war nicht möglich, Werte für dieses Array zu kopieren"
-#: spyder/widgets/variableexplorer/arrayeditor.py:533
-#: spyder/widgets/variableexplorer/arrayeditor.py:566
-#: spyder/widgets/variableexplorer/dataframeeditor.py:689
-#: spyder/widgets/variableexplorer/dataframeeditor.py:734
+#: spyder/widgets/variableexplorer/arrayeditor.py:545
+#: spyder/widgets/variableexplorer/arrayeditor.py:578
+#: spyder/widgets/variableexplorer/dataframeeditor.py:728
+#: spyder/widgets/variableexplorer/dataframeeditor.py:787
msgid "Format"
msgstr "Format"
-#: spyder/widgets/variableexplorer/arrayeditor.py:538
-#: spyder/widgets/variableexplorer/dataframeeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:550
+#: spyder/widgets/variableexplorer/dataframeeditor.py:732
msgid "Resize"
msgstr "Größe ändern"
-#: spyder/widgets/variableexplorer/arrayeditor.py:567
-#: spyder/widgets/variableexplorer/dataframeeditor.py:735
+#: spyder/widgets/variableexplorer/arrayeditor.py:553
+#: spyder/widgets/variableexplorer/dataframeeditor.py:736
+msgid "Background color"
+msgstr "Hintergrundfarbe"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:579
+#: spyder/widgets/variableexplorer/dataframeeditor.py:788
msgid "Float formatting"
msgstr "Float-Formatierung"
-#: spyder/widgets/variableexplorer/arrayeditor.py:575
+#: spyder/widgets/variableexplorer/arrayeditor.py:587
msgid "Format (%s) is incorrect"
msgstr "Format (%s) ist falsch"
-#: spyder/widgets/variableexplorer/arrayeditor.py:611
+#: spyder/widgets/variableexplorer/arrayeditor.py:625
msgid "Arrays with more than 3 dimensions are not supported"
msgstr "Arrays mit mehr als 3 Dimensionen werden nicht unterstützt"
-#: spyder/widgets/variableexplorer/arrayeditor.py:615
+#: spyder/widgets/variableexplorer/arrayeditor.py:629
msgid "The 'xlabels' argument length do no match array column number"
msgstr ""
"Die Argumentlänge von 'xlabels' entspricht nicht der Array-Spaltennummer"
-#: spyder/widgets/variableexplorer/arrayeditor.py:619
+#: spyder/widgets/variableexplorer/arrayeditor.py:633
msgid "The 'ylabels' argument length do no match array row number"
msgstr ""
"Die Argumentlänge von 'ylabels' entspricht nicht der Array-Zeilennummer"
-#: spyder/widgets/variableexplorer/arrayeditor.py:626
+#: spyder/widgets/variableexplorer/arrayeditor.py:640
msgid "%s arrays"
msgstr "%s Arrays"
-#: spyder/widgets/variableexplorer/arrayeditor.py:627
+#: spyder/widgets/variableexplorer/arrayeditor.py:641
msgid "%s are currently not supported"
msgstr "%s werden momentan nicht unterstützt"
-#: spyder/widgets/variableexplorer/arrayeditor.py:634
+#: spyder/widgets/variableexplorer/arrayeditor.py:648
msgid "NumPy array"
msgstr "NumPy-Array"
-#: spyder/widgets/variableexplorer/arrayeditor.py:636
-#: spyder/widgets/variableexplorer/arrayeditor.py:790
+#: spyder/widgets/variableexplorer/arrayeditor.py:650
+#: spyder/widgets/variableexplorer/arrayeditor.py:828
msgid "Array editor"
msgstr "Array-Editor"
-#: spyder/widgets/variableexplorer/arrayeditor.py:638
+#: spyder/widgets/variableexplorer/arrayeditor.py:652
msgid "read only"
msgstr "schreibgeschützt"
-#: spyder/widgets/variableexplorer/arrayeditor.py:668
+#: spyder/widgets/variableexplorer/arrayeditor.py:685
msgid "Record array fields:"
msgstr "Array-Felder aufzeichnen:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:680
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Data"
msgstr "Daten"
-#: spyder/widgets/variableexplorer/arrayeditor.py:680
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Mask"
msgstr "Maske"
-#: spyder/widgets/variableexplorer/arrayeditor.py:680
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Masked data"
msgstr "Maskierte Daten"
-#: spyder/widgets/variableexplorer/arrayeditor.py:691
+#: spyder/widgets/variableexplorer/arrayeditor.py:708
msgid "Axis:"
msgstr "Achse:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:696
+#: spyder/widgets/variableexplorer/arrayeditor.py:713
msgid "Index:"
msgstr "Index:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:709
+#: spyder/widgets/variableexplorer/arrayeditor.py:726
msgid "Warning: changes are applied separately"
msgstr "Warnung: Änderungen werden separat angewendet"
-#: spyder/widgets/variableexplorer/arrayeditor.py:710
+#: spyder/widgets/variableexplorer/arrayeditor.py:727
msgid ""
"For performance reasons, changes applied to masked array won't be reflected "
"in array's data (and vice-versa)."
@@ -5039,47 +5127,54 @@ msgstr ""
"Aus Leistungsgründen werden Änderungen, die auf ein maskiertes Array "
"angewendet werden, nicht in Array-Daten (und umgekehrt) reflektiert."
-#: spyder/widgets/variableexplorer/collectionseditor.py:138
+#: spyder/widgets/variableexplorer/arrayeditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:1392
+#: spyder/widgets/variableexplorer/dataframeeditor.py:751
+#: spyder/widgets/variableexplorer/texteditor.py:67
+msgid "Save and Close"
+msgstr "Speichern und Schließen"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:151
msgid "Index"
msgstr "Index"
-#: spyder/widgets/variableexplorer/collectionseditor.py:143
+#: spyder/widgets/variableexplorer/collectionseditor.py:156
msgid "Tuple"
msgstr "Tupel"
-#: spyder/widgets/variableexplorer/collectionseditor.py:146
+#: spyder/widgets/variableexplorer/collectionseditor.py:159
msgid "List"
msgstr "Liste"
-#: spyder/widgets/variableexplorer/collectionseditor.py:149
+#: spyder/widgets/variableexplorer/collectionseditor.py:162
msgid "Dictionary"
msgstr "Wörterbuch"
-#: spyder/widgets/variableexplorer/collectionseditor.py:151
+#: spyder/widgets/variableexplorer/collectionseditor.py:164
msgid "Key"
msgstr "Schlüssel"
-#: spyder/widgets/variableexplorer/collectionseditor.py:156
+#: spyder/widgets/variableexplorer/collectionseditor.py:169
msgid "Attribute"
msgstr "Attribut"
-#: spyder/widgets/variableexplorer/collectionseditor.py:160
+#: spyder/widgets/variableexplorer/collectionseditor.py:173
msgid "elements"
msgstr "Elemente"
-#: spyder/widgets/variableexplorer/collectionseditor.py:336
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Size"
msgstr "Größe"
-#: spyder/widgets/variableexplorer/collectionseditor.py:336
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Type"
msgstr "Typ"
-#: spyder/widgets/variableexplorer/collectionseditor.py:336
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Value"
msgstr "Wert"
-#: spyder/widgets/variableexplorer/collectionseditor.py:434
+#: spyder/widgets/variableexplorer/collectionseditor.py:450
msgid ""
"Opening this variable can be slow\n"
"\n"
@@ -5089,309 +5184,329 @@ msgstr ""
"\n"
"Möchten Sie trotzdem fortfahren?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:445
+#: spyder/widgets/variableexplorer/collectionseditor.py:461
msgid ""
-"Spyder was unable to retrieve the value of this variable from the "
-"console.
The error mesage was:
%s"
+"Spyder was unable to retrieve the value of this variable from the console."
+"
The error mesage was:
%s"
msgstr ""
-"Spyder konnte den Wert dieser Variablen nicht aus der Konsole "
-"abrufen.
Die Fehlermeldung war:
%s"
+"Spyder konnte den Wert dieser Variablen nicht aus der Konsole abrufen."
+"
Die Fehlermeldung war:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:622
+#: spyder/widgets/variableexplorer/collectionseditor.py:643
msgid "Edit item"
msgstr "Element bearbeiten"
-#: spyder/widgets/variableexplorer/collectionseditor.py:623
+#: spyder/widgets/variableexplorer/collectionseditor.py:644
msgid "Unable to assign data to item.
Error message:
%s"
msgstr ""
-"Dem Element können keine Daten zugeordnet "
-"werden.
Fehlermeldung:
%s"
+"Dem Element können keine Daten zugeordnet werden."
+"b>
Fehlermeldung:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:683
+#: spyder/widgets/variableexplorer/collectionseditor.py:705
msgid "Resize rows to contents"
msgstr "Größe der Zeilen auf Inhalt anpassen"
-#: spyder/widgets/variableexplorer/collectionseditor.py:694
-#: spyder/widgets/variableexplorer/collectionseditor.py:1040
-#: spyder/widgets/variableexplorer/collectionseditor.py:1057
+#: spyder/widgets/variableexplorer/collectionseditor.py:716
+#: spyder/widgets/variableexplorer/collectionseditor.py:1066
+#: spyder/widgets/variableexplorer/collectionseditor.py:1083
msgid "Plot"
msgstr "Plot"
-#: spyder/widgets/variableexplorer/collectionseditor.py:698
+#: spyder/widgets/variableexplorer/collectionseditor.py:720
msgid "Histogram"
msgstr "Histogramm"
-#: spyder/widgets/variableexplorer/collectionseditor.py:702
+#: spyder/widgets/variableexplorer/collectionseditor.py:724
msgid "Show image"
msgstr "Bild anzeigen"
-#: spyder/widgets/variableexplorer/collectionseditor.py:706
-#: spyder/widgets/variableexplorer/collectionseditor.py:1065
+#: spyder/widgets/variableexplorer/collectionseditor.py:728
+#: spyder/widgets/variableexplorer/collectionseditor.py:1091
msgid "Save array"
msgstr "Array speichern"
-#: spyder/widgets/variableexplorer/collectionseditor.py:710
-#: spyder/widgets/variableexplorer/collectionseditor.py:1004
-#: spyder/widgets/variableexplorer/collectionseditor.py:1012
+#: spyder/widgets/variableexplorer/collectionseditor.py:732
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Insert"
msgstr "Einfügen"
-#: spyder/widgets/variableexplorer/collectionseditor.py:713
-#: spyder/widgets/variableexplorer/collectionseditor.py:948
-msgid "Remove"
-msgstr "Entfernen"
-
-#: spyder/widgets/variableexplorer/collectionseditor.py:723
-#: spyder/widgets/variableexplorer/collectionseditor.py:969
+#: spyder/widgets/variableexplorer/collectionseditor.py:745
+#: spyder/widgets/variableexplorer/collectionseditor.py:991
msgid "Duplicate"
msgstr "Duplizieren"
-#: spyder/widgets/variableexplorer/collectionseditor.py:946
+#: spyder/widgets/variableexplorer/collectionseditor.py:968
msgid "Do you want to remove the selected item?"
msgstr "Möchten Sie das ausgewählte Element entfernen?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:947
+#: spyder/widgets/variableexplorer/collectionseditor.py:969
msgid "Do you want to remove all selected items?"
msgstr "Möchten Sie alle ausgewählten Elemente entfernen?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:967
+#: spyder/widgets/variableexplorer/collectionseditor.py:989
msgid "New variable name:"
msgstr "Neuer Variablenname:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:970
+#: spyder/widgets/variableexplorer/collectionseditor.py:992
msgid "Variable name:"
msgstr "Variablenname:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1004
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
msgid "Key:"
msgstr "Schlüssel:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1012
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Value:"
msgstr "Wert:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1028
+#: spyder/widgets/variableexplorer/collectionseditor.py:1054
msgid "Import error"
msgstr "Importfehler"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1029
+#: spyder/widgets/variableexplorer/collectionseditor.py:1055
msgid "Please install matplotlib or guiqwt."
msgstr "Bitte installieren Sie matplotlib oder guiqwt."
-#: spyder/widgets/variableexplorer/collectionseditor.py:1041
+#: spyder/widgets/variableexplorer/collectionseditor.py:1067
msgid "Unable to plot data.
Error message:
%s"
msgstr ""
"Daten können nicht geplottet werden.
Fehlermeldung:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1058
+#: spyder/widgets/variableexplorer/collectionseditor.py:1084
msgid "Unable to show image.
Error message:
%s"
msgstr "Bild kann nicht angezeigt werden.
Fehlermeldung:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1081
+#: spyder/widgets/variableexplorer/collectionseditor.py:1097
+msgid "NumPy arrays"
+msgstr "NumPy-Arrays"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1107
msgid "Unable to save array
Error message:
%s"
msgstr "Array kann nicht gespeichert werden
Fehlermeldung:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1106
+#: spyder/widgets/variableexplorer/collectionseditor.py:1132
msgid "It was not possible to copy this array"
msgstr "Es war nicht möglich, dieses Array zu kopieren"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1131
+#: spyder/widgets/variableexplorer/collectionseditor.py:1144
+msgid "It was not possible to copy this dataframe"
+msgstr "Es war nicht möglich, die Daten zu kopieren"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1166
msgid "Clipboard contents"
msgstr "Inhalt der Zwischenablage"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1146
+#: spyder/widgets/variableexplorer/collectionseditor.py:1181
msgid "Import from clipboard"
msgstr "Aus Zwischenablage importieren"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1148
+#: spyder/widgets/variableexplorer/collectionseditor.py:1183
msgid "Empty clipboard"
msgstr "Leere Zwischenablage"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1149
+#: spyder/widgets/variableexplorer/collectionseditor.py:1184
msgid "Nothing to be imported from clipboard."
msgstr "Aus der Zwischenablage kann nichts importiert werden."
-#: spyder/widgets/variableexplorer/dataframeeditor.py:583
+#: spyder/widgets/variableexplorer/dataframeeditor.py:321
+msgid ""
+"It is not possible to display this value because\n"
+"an error ocurred while trying to do it"
+msgstr ""
+"Es ist nicht möglich diesen Wert darzustellen,\n"
+"weil bei dem Versuch ein Fehler auftrat"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To bool"
msgstr "Zu bool"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:583
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To complex"
msgstr "Zu komplex"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:584
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To float"
msgstr "Zu float"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:584
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To int"
msgstr "Zu int"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:585
+#: spyder/widgets/variableexplorer/dataframeeditor.py:623
msgid "To str"
msgstr "Zu str"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:669
+#: spyder/widgets/variableexplorer/dataframeeditor.py:707
msgid "%s editor"
msgstr "%s Editor"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:703
+#: spyder/widgets/variableexplorer/dataframeeditor.py:742
msgid "Column min/max"
msgstr "Spalte min/max"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:743
+#: spyder/widgets/variableexplorer/dataframeeditor.py:796
msgid "Format ({}) is incorrect"
msgstr "Format ({}) ist falsch"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:747
+#: spyder/widgets/variableexplorer/dataframeeditor.py:800
msgid "Format ({}) should start with '%'"
msgstr "Format ({}) sollte mit '%' beginnen"
-#: spyder/widgets/variableexplorer/importwizard.py:116
-#: spyder/widgets/variableexplorer/importwizard.py:436
+#: spyder/widgets/variableexplorer/importwizard.py:118
+#: spyder/widgets/variableexplorer/importwizard.py:438
msgid "Import as"
msgstr "Importieren als"
-#: spyder/widgets/variableexplorer/importwizard.py:118
+#: spyder/widgets/variableexplorer/importwizard.py:120
msgid "data"
msgstr "Daten"
-#: spyder/widgets/variableexplorer/importwizard.py:122
+#: spyder/widgets/variableexplorer/importwizard.py:124
msgid "code"
msgstr "Code"
-#: spyder/widgets/variableexplorer/importwizard.py:125
-#: spyder/widgets/variableexplorer/importwizard.py:512
+#: spyder/widgets/variableexplorer/importwizard.py:127
+#: spyder/widgets/variableexplorer/importwizard.py:514
msgid "text"
msgstr "Text"
-#: spyder/widgets/variableexplorer/importwizard.py:138
+#: spyder/widgets/variableexplorer/importwizard.py:140
msgid "Column separator:"
msgstr "Spaltentrennzeichen:"
-#: spyder/widgets/variableexplorer/importwizard.py:142
+#: spyder/widgets/variableexplorer/importwizard.py:144
msgid "Tab"
msgstr "Tabulator"
-#: spyder/widgets/variableexplorer/importwizard.py:145
+#: spyder/widgets/variableexplorer/importwizard.py:147
msgid "Whitespace"
msgstr "Leerzeichen"
-#: spyder/widgets/variableexplorer/importwizard.py:148
-#: spyder/widgets/variableexplorer/importwizard.py:166
+#: spyder/widgets/variableexplorer/importwizard.py:150
+#: spyder/widgets/variableexplorer/importwizard.py:168
msgid "other"
msgstr "andere"
-#: spyder/widgets/variableexplorer/importwizard.py:159
+#: spyder/widgets/variableexplorer/importwizard.py:161
msgid "Row separator:"
msgstr "Zeilentrennzeichen:"
# Zu EOL (End of Line) gibt es keine adäquate deutsche Übersetzung.
-#: spyder/widgets/variableexplorer/importwizard.py:163
+#: spyder/widgets/variableexplorer/importwizard.py:165
msgid "EOL"
msgstr "EOL"
-#: spyder/widgets/variableexplorer/importwizard.py:178
+#: spyder/widgets/variableexplorer/importwizard.py:180
msgid "Additional options"
msgstr "Zusätzliche Optionen"
-#: spyder/widgets/variableexplorer/importwizard.py:182
+#: spyder/widgets/variableexplorer/importwizard.py:184
msgid "Skip rows:"
msgstr "Zeilen überspringen:"
-#: spyder/widgets/variableexplorer/importwizard.py:193
+#: spyder/widgets/variableexplorer/importwizard.py:195
msgid "Comments:"
msgstr "Kommentare:"
-#: spyder/widgets/variableexplorer/importwizard.py:199
+#: spyder/widgets/variableexplorer/importwizard.py:201
msgid "Transpose"
msgstr "Transponieren"
-#: spyder/widgets/variableexplorer/importwizard.py:439
+#: spyder/widgets/variableexplorer/importwizard.py:441
msgid "array"
msgstr "Array"
-#: spyder/widgets/variableexplorer/importwizard.py:444
+#: spyder/widgets/variableexplorer/importwizard.py:446
msgid "list"
msgstr "Liste"
-#: spyder/widgets/variableexplorer/importwizard.py:449
+#: spyder/widgets/variableexplorer/importwizard.py:451
msgid "DataFrame"
msgstr "DatenRahmen"
-#: spyder/widgets/variableexplorer/importwizard.py:495
-#: spyder/widgets/variableexplorer/importwizard.py:579
+#: spyder/widgets/variableexplorer/importwizard.py:497
+#: spyder/widgets/variableexplorer/importwizard.py:581
msgid "Import wizard"
msgstr "Importassistent"
-#: spyder/widgets/variableexplorer/importwizard.py:500
+#: spyder/widgets/variableexplorer/importwizard.py:502
msgid "Raw text"
msgstr "Rohtext"
-#: spyder/widgets/variableexplorer/importwizard.py:503
+#: spyder/widgets/variableexplorer/importwizard.py:505
msgid "variable_name"
msgstr "Variablenname"
-#: spyder/widgets/variableexplorer/importwizard.py:514
+#: spyder/widgets/variableexplorer/importwizard.py:516
msgid "table"
msgstr "Tabelle"
-#: spyder/widgets/variableexplorer/importwizard.py:515
+#: spyder/widgets/variableexplorer/importwizard.py:517
msgid "Preview"
msgstr "Vorschau"
-#: spyder/widgets/variableexplorer/importwizard.py:519
+#: spyder/widgets/variableexplorer/importwizard.py:521
msgid "Variable Name"
msgstr "Variablenname"
-#: spyder/widgets/variableexplorer/importwizard.py:542
+#: spyder/widgets/variableexplorer/importwizard.py:544
msgid "Done"
msgstr "Fertig"
-#: spyder/widgets/variableexplorer/importwizard.py:580
+#: spyder/widgets/variableexplorer/importwizard.py:582
msgid ""
-"Unable to proceed to next step
Please check your "
-"entries.
Error message:
%s"
+"Unable to proceed to next step
Please check your entries."
+"
Error message:
%s"
msgstr ""
"Der nächste Schritt kann nicht stattfinden
Bitte überprüfen "
"Sie Ihre Einträge.
Fehlermeldung:
%s"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:158
-#: spyder/widgets/variableexplorer/namespacebrowser.py:253
+#: spyder/widgets/variableexplorer/namespacebrowser.py:184
+#: spyder/widgets/variableexplorer/namespacebrowser.py:397
msgid "Import data"
msgstr "Daten importieren"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:161
-#: spyder/widgets/variableexplorer/namespacebrowser.py:326
-#: spyder/widgets/variableexplorer/namespacebrowser.py:342
+#: spyder/widgets/variableexplorer/namespacebrowser.py:187
+#: spyder/widgets/variableexplorer/namespacebrowser.py:477
+#: spyder/widgets/variableexplorer/namespacebrowser.py:491
+#: spyder/plugins/profiler/widgets/profilergui.py:121
msgid "Save data"
msgstr "Daten speichern"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:166
+#: spyder/widgets/variableexplorer/namespacebrowser.py:192
msgid "Save data as..."
msgstr "Daten speichern als..."
-#: spyder/widgets/variableexplorer/namespacebrowser.py:174
+#: spyder/widgets/variableexplorer/namespacebrowser.py:204
msgid "Exclude references which name starts with an underscore"
msgstr "Referenzen, deren Name mit einem Unterstrich beginnt, ausschließen"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:182
+#: spyder/widgets/variableexplorer/namespacebrowser.py:212
msgid "Exclude references which name is uppercase"
msgstr "Referenzen mit Name in Großbuchstaben ausschließen"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:189
+#: spyder/widgets/variableexplorer/namespacebrowser.py:219
msgid "Exclude references which name starts with an uppercase character"
msgstr "Referenzen, deren Name mit einem Großbuchstaben beginnt, ausschließen"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:197
+#: spyder/widgets/variableexplorer/namespacebrowser.py:227
msgid ""
-"Exclude references to unsupported data types (i.e. which won't be "
-"handled/saved correctly)"
+"Exclude references to unsupported data types (i.e. which won't be handled/"
+"saved correctly)"
msgstr ""
"Referenzen auf nicht unterstützte Datentypen ausschließen (d.h. was nicht "
"korrekt behandelt/gespeichert wird)"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:273
+#: spyder/widgets/variableexplorer/namespacebrowser.py:306
+msgid ""
+"The object you are trying to modify is too big to be sent back to the "
+"kernel. Therefore, your modifications won't take place."
+msgstr ""
+"Das Objekt, dass Sie versuchen zu ändern ist zu groß um an den Kernel "
+"zurückgesendet zu werden. Die Veränderungen werden nicht ausgeführt."
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:417
msgid ""
"Unsupported file extension '%s'
Would you like to import it "
"anyway (by selecting a known file format)?"
@@ -5399,38 +5514,29 @@ msgstr ""
"Nicht unterstützte Dateierweiterung '%s'
Möchten Sie sie "
"trotzdem importieren (indem Sie ein bekanntes Dateiformat auswählen)?"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:281
+#: spyder/widgets/variableexplorer/namespacebrowser.py:425
msgid "Open file as:"
msgstr "Datei öffnen als:"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:314
+#: spyder/widgets/variableexplorer/namespacebrowser.py:459
msgid "Unable to load '%s'
Error message:
%s"
msgstr "'%s' kann nicht geladen werden
Fehlermeldung:
%s"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:343
+#: spyder/widgets/variableexplorer/namespacebrowser.py:492
msgid "Unable to save current workspace
Error message:
%s"
msgstr ""
-"Aktuelle Arbeitsfläche kann nicht gespeichert "
-"werden
Fehlermeldung:
%s"
+"Aktuelle Arbeitsfläche kann nicht gespeichert werden"
+"b>
Fehlermeldung:
%s"
-#: spyder/widgets/variableexplorer/texteditor.py:74
+#: spyder/widgets/variableexplorer/texteditor.py:84
msgid "Text editor"
msgstr "Texteditor"
-#: spyder/widgets/variableexplorer/utils.py:29
-msgid "View and edit DataFrames and Series in the Variable Explorer"
-msgstr "DatenRahmen und -Serien im Variablenmanager anzeigen und bearbeiten"
-
-#: spyder/widgets/variableexplorer/utils.py:34
-msgid "View and edit two and three dimensional arrays in the Variable Explorer"
-msgstr ""
-"Zwei- und dreidimensionale Arrays im Variablenmanager anzeigen und bearbeiten"
-
-#: spyder/workers/updates.py:90 spyder/workers/updates.py:92
+#: spyder/workers/updates.py:128 spyder/workers/updates.py:130
msgid "Unable to retrieve information."
msgstr "Informationen können nicht abgerufen werden."
-#: spyder/workers/updates.py:94
+#: spyder/workers/updates.py:132
msgid ""
"Unable to connect to the internet.
Make sure the connection is "
"working properly."
@@ -5438,229 +5544,306 @@ msgstr ""
"Kann nicht mit dem Internet verbinden.
Stellen Sie sicher, dass die "
"Verbindung ordnungsgemäß funktioniert."
-#: spyder/workers/updates.py:97
+#: spyder/workers/updates.py:135
msgid "Unable to check for updates."
msgstr "Aktualisierungen können nicht gesucht werden."
-#~ msgid "Loading external console..."
-#~ msgstr "Externe Konsole wird geladen..."
-
-#~ msgid "The Python console"
-#~ msgstr "Die Python-Konsole"
+#: spyder/plugins/breakpoints/plugin.py:45
+#, fuzzy
+msgid "Breakpoints"
+msgstr "Haltepunkt"
+
+#: spyder/plugins/breakpoints/plugin.py:80
+#, fuzzy
+msgid "List breakpoints"
+msgstr "Haltepunkt"
-# TYPO in source: No blank space at the beginning of the third sentence. 'only to it.To select'
-#~ msgid ""
-#~ "You can also run your code on a Python console. These consoles are useful "
-#~ "because they let you run a file in a console dedicated only to it.To "
-#~ "select this behavior, please press the F6 key.
By pressing "
-#~ "the button below and then focusing the Variable Explorer, you will notice "
-#~ "that Python consoles are also connected to that pane, and that the "
-#~ "Variable Explorer only shows the variables of the currently focused "
-#~ "console."
-#~ msgstr ""
-#~ "Sie können Ihren Code auch in einer Python-Konsole ausführen. Diese "
-#~ "Konsolen sind nützlich, da sie Ihnen eine Datei in einer nur dazu "
-#~ "dedizierten Konsole ausführen lassen.vUm dieses Verhalten auszuwählen, "
-#~ "drücken Sie bitte die Taste F6.
Wenn Sie die Schaltfläche "
-#~ "unten drücken und dann den Variablenmanager in den Fokus nehmen, werden "
-#~ "Sie feststellen, dass auch Python-Konsolen mit diesem Bereich verbunden "
-#~ "sind und der Variablenmanager nur die Variablen der aktuell fokussierten "
-#~ "Konsole anzeigt."
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+#, fuzzy
+msgid "Condition"
+msgstr "Bedingung:"
-#~ msgid "Show TODO/FIXME/XXX/HINT/TIP/@todo comments list"
-#~ msgstr "TODO/FIXME/XXX/HINT/TIP/@todo comments list anzeigen"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+#, fuzzy
+msgid "Line"
+msgstr "Zeile:"
-#~ msgid "Python Console"
-#~ msgstr "Python-Konsole"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:201
+#, fuzzy
+msgid "Clear this breakpoint"
+msgstr "Haltepunkt festlegen/löschen"
-#~ msgid "Unable to save script '%s'
Error message:
%s"
-#~ msgstr ""
-#~ "Skript '%s' kann nicht gespeichert "
-#~ "werden
Fehlermeldung:
%s"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:206
+#, fuzzy
+msgid "Edit this breakpoint"
+msgstr "Bedingten Haltepunkt festlegen/bearbeiten"
-#~ msgid "Included filenames pattern"
-#~ msgstr "Eingeschlossene Dateinamensmuster"
+#: spyder/plugins/profiler/plugin.py:33 spyder/plugins/pylint/plugin.py:47
+msgid "Results"
+msgstr ""
-#~ msgid "Include:"
-#~ msgstr "Einschließen:"
+#: spyder/plugins/profiler/plugin.py:34
+msgid ""
+"Profiler plugin results (the output of python's profile/cProfile)\n"
+"are stored here:"
+msgstr ""
-#~ msgid "PYTHONPATH"
-#~ msgstr "PYTHONPATH"
+#: spyder/plugins/profiler/plugin.py:75
+#, fuzzy
+msgid "Profiler"
+msgstr "Datei"
-#~ msgid ""
-#~ "Search in all directories listed in sys.path which are outside the Python "
-#~ "installation directory"
-#~ msgstr ""
-#~ "In allen Verzeichnissen, die in sys.path aufgelistet sind und sich "
-#~ "außerhalb des Python-Installationsverzeichnisses befinden, suchen"
+#: spyder/plugins/profiler/plugin.py:104
+#: spyder/plugins/profiler/widgets/profilergui.py:81
+#, fuzzy
+msgid "Profile"
+msgstr "Datei"
-#~ msgid "Hg repository"
-#~ msgstr "Hg-Repositorium"
+#: spyder/plugins/profiler/widgets/profilergui.py:82
+#, fuzzy
+msgid "Run profiler"
+msgstr "Datei ausführen"
-#~ msgid "Search in current directory hg repository"
-#~ msgstr "Im aktuellen Verzeichnis hg-Repositorium suchen"
+#: spyder/plugins/profiler/widgets/profilergui.py:88
+#, fuzzy
+msgid "Stop current profiling"
+msgstr "Aktuellen Befehl stoppen"
-#~ msgid "Here:"
-#~ msgstr "Hier:"
+#: spyder/plugins/profiler/widgets/profilergui.py:96
+#: spyder/plugins/profiler/widgets/profilergui.py:219
+#, fuzzy
+msgid "Select Python script"
+msgstr "Python-Skripte"
-#~ msgid "Search recursively in this directory"
-#~ msgstr "Rekursiv in diesem Verzeichnis suchen"
+#: spyder/plugins/profiler/widgets/profilergui.py:102
+#: spyder/plugins/pylint/widgets/pylintgui.py:224
+#, fuzzy
+msgid "Output"
+msgstr "Ausgabeprompt:"
-#~ msgid "Browse a search directory"
-#~ msgstr "Suchverzeichnis durchsuchen"
+#: spyder/plugins/profiler/widgets/profilergui.py:104
+#, fuzzy
+msgid "Show program's output"
+msgstr "Absoluten Pfad anzeigen"
-#~ msgid "Search canceled"
-#~ msgstr "Suche abgebrochen"
+#: spyder/plugins/profiler/widgets/profilergui.py:113
+#, fuzzy
+msgid "Collapse one level up"
+msgstr "Alle einklappen"
-#~ msgid "interrupted"
-#~ msgstr "unterbrochen"
+#: spyder/plugins/profiler/widgets/profilergui.py:118
+#, fuzzy
+msgid "Expand one level down"
+msgstr "Auswahl ausklappen"
-#~ msgid ""
-#~ "
Restarting kernel because an error occurred while debugging\n"
-#~ "
"
-#~ msgstr ""
-#~ "
Kernel wird neu gestartet, da beim Debuggen ein Fehler aufgetreten "
-#~ "ist\n"
-#~ "
"
+#: spyder/plugins/profiler/widgets/profilergui.py:124
+#, fuzzy
+msgid "Save profiling data"
+msgstr "Daten speichern"
-#~ msgid ""
-#~ "Inspecting and setting values while debugging in IPython consoles is not "
-#~ "supported yet by Spyder."
-#~ msgstr ""
-#~ "Inspektion und Festlegung von Werten, während dem Debuggen in "
-#~ "IPython-Konsolen, wird von Spyder noch nicht unterstützt."
+#: spyder/plugins/profiler/widgets/profilergui.py:126
+#, fuzzy
+msgid "Load data"
+msgstr "Maskierte Daten"
-#~ msgid "IPython Console integration"
-#~ msgstr "IPython-Konsolenintegration"
+#: spyder/plugins/profiler/widgets/profilergui.py:129
+msgid "Load profiling data for comparison"
+msgstr ""
-#~ msgid "Updates"
-#~ msgstr "Aktualisierungen"
+#: spyder/plugins/profiler/widgets/profilergui.py:131
+#, fuzzy
+msgid "Clear comparison"
+msgstr "Konsole leeren"
-#~ msgid "&Font..."
-#~ msgstr "Schri&ftart..."
+#: spyder/plugins/profiler/widgets/profilergui.py:171
+msgid "Please install"
+msgstr ""
-#~ msgid "Set shell font style"
-#~ msgstr "Shell-Schriftstil festlegen"
+#: spyder/plugins/profiler/widgets/profilergui.py:172
+#, fuzzy
+msgid "the Python profiler modules"
+msgstr "Installierte Python-Module"
-#~ msgid "Select a new font"
-#~ msgstr "Wählen Sie eine neue Schriftart aus"
+#: spyder/plugins/profiler/widgets/profilergui.py:179
+#, fuzzy
+msgid "Save profiler result"
+msgstr "Datei speichern"
-#~ msgid "tab"
-#~ msgstr "Tabulator"
+#: spyder/plugins/profiler/widgets/profilergui.py:182
+#: spyder/plugins/profiler/widgets/profilergui.py:188
+msgid "Profiler result"
+msgstr ""
-#~ msgid "Breakpoints"
-#~ msgstr "Haltepunkte"
+#: spyder/plugins/profiler/widgets/profilergui.py:187
+msgid "Select script to compare"
+msgstr ""
-#~ msgid "Exit"
-#~ msgstr "Beenden"
+#: spyder/plugins/profiler/widgets/profilergui.py:227
+#: spyder/plugins/profiler/widgets/profilergui.py:232
+msgid "Profiler output"
+msgstr ""
-#~ msgid "Exit Debug"
-#~ msgstr "Debug beenden"
+#: spyder/plugins/profiler/widgets/profilergui.py:251
+msgid "Profiling, please wait..."
+msgstr ""
-#~ msgid "?"
-#~ msgstr "?"
+#: spyder/plugins/profiler/widgets/profilergui.py:343
+msgid "Sorting data, please wait..."
+msgstr ""
-#~ msgid "Set font style"
-#~ msgstr "Schriftstil festlegen"
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Function/Module"
+msgstr ""
-#~ msgid "Kernel"
-#~ msgstr "Kernel"
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Total Time"
+msgstr ""
-#~ msgid "Kernel %s"
-#~ msgstr "Kernel %s"
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Diff"
+msgstr ""
-#~ msgid "Open an IPython console"
-#~ msgstr "IPython-Konsole öffnen"
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Calls"
+msgstr ""
-#~ msgid "Refresh interval: "
-#~ msgstr "Aktualisierungsintervall: "
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Local Time"
+msgstr ""
-#~ msgid "Truncate values"
-#~ msgstr "Werte verkürzen"
+#: spyder/plugins/profiler/widgets/profilergui.py:391
+#, fuzzy
+msgid "File:line"
+msgstr "Zeile löschen"
-#~ msgid "Python(x,y)"
-#~ msgstr "Python(x,y)"
+#: spyder/plugins/profiler/widgets/profilergui.py:565
+#, fuzzy
+msgid "Function or module name"
+msgstr "Auswahl oder aktuelle Zeile ausführen"
-#~ msgid "Reload last session"
-#~ msgstr "Letzte Sitzung neu laden"
+#: spyder/plugins/profiler/widgets/profilergui.py:569
+msgid "Time in function (including sub-functions)"
+msgstr ""
-#~ msgid "Load session..."
-#~ msgstr "Sitzung laden..."
+#: spyder/plugins/profiler/widgets/profilergui.py:578
+msgid "Local time in function (not in sub-functions)"
+msgstr ""
-#~ msgid "Load Spyder session"
-#~ msgstr "Spyder-Sitzung laden"
+#: spyder/plugins/profiler/widgets/profilergui.py:588
+msgid "Total number of calls (including recursion)"
+msgstr ""
-#~ msgid "Save session and quit..."
-#~ msgstr "Sitzung speichern und schließen..."
+#: spyder/plugins/profiler/widgets/profilergui.py:598
+msgid "File:line where function is defined"
+msgstr ""
-#~ msgid "Save current session and quit application"
-#~ msgstr "Aktuelle Sitzung speichern und Anwendung schließen"
+#: spyder/plugins/profiler/widgets/profilergui.py:603
+msgid "recursion"
+msgstr ""
-#~ msgid "Python(x,y) launcher"
-#~ msgstr "Python(x,y)-Starter"
+#: spyder/plugins/pylint/plugin.py:36
+#, fuzzy
+msgid "Save file before analyzing it"
+msgstr "Speichern Sie alle Dateien, bevor Sie das Skript ausführen"
-#~ msgid "Python(x,y) documentation folder"
-#~ msgstr "Python(x,y)-Dokumentationsordner"
+#: spyder/plugins/pylint/plugin.py:40
+#, fuzzy
+msgid "The following option will be applied at next startup."
+msgstr "Diese Option wird beim nächsten Öffnen einer Konsole angewendet."
-#~ msgid "guidata documentation"
-#~ msgstr "guidata-Dokumentation"
+#: spyder/plugins/pylint/plugin.py:43
+#, fuzzy
+msgid "History: "
+msgstr "Chronik"
-#~ msgid "guiqwt documentation"
-#~ msgstr "guiqwt-Dokumentation"
+#: spyder/plugins/pylint/plugin.py:44
+msgid " results"
+msgstr ""
-#~ msgid "NumPy documentation"
-#~ msgstr "NumPy-Dokumentation"
+#: spyder/plugins/pylint/plugin.py:48
+msgid "Results are stored here:"
+msgstr ""
-#~ msgid "SciPy documentation"
-#~ msgstr "SciPy-Dokumentation"
+#: spyder/plugins/pylint/plugin.py:98
+#: spyder/plugins/pylint/widgets/pylintgui.py:83
+#, fuzzy
+msgid "Static code analysis"
+msgstr "Echtzeit-Codeanalyse"
-#~ msgid "Open session"
-#~ msgstr "Sitzung öffnen"
+#: spyder/plugins/pylint/plugin.py:133
+#, fuzzy
+msgid "Run static code analysis"
+msgstr "Echtzeit-Codeanalyse"
-#~ msgid "Spyder sessions"
-#~ msgstr "Spyder-Sitzungen"
+#: spyder/plugins/pylint/widgets/pylintgui.py:117
+msgid "Results for "
+msgstr ""
-#~ msgid "Save session"
-#~ msgstr "Sitzung speichern"
+#: spyder/plugins/pylint/widgets/pylintgui.py:122
+#, fuzzy
+msgid "Convention"
+msgstr "Bedingung:"
-#~ msgid "Save Python script"
-#~ msgstr "Python-Skript speichern"
+#: spyder/plugins/pylint/widgets/pylintgui.py:124
+msgid "Refactor"
+msgstr ""
-#~ msgid "Refresh"
-#~ msgstr "Aktualisieren"
+#: spyder/plugins/pylint/widgets/pylintgui.py:206
+#, fuzzy
+msgid "Analyze"
+msgstr "Analyse"
-#~ msgid "Refresh periodically"
-#~ msgstr "Regelmäßig aktualisieren"
+#: spyder/plugins/pylint/widgets/pylintgui.py:207
+#, fuzzy
+msgid "Run analysis"
+msgstr "Codeanalyse"
-#~ msgid "its own configuration file"
-#~ msgstr "seine eigene Konfigurationsdatei"
+#: spyder/plugins/pylint/widgets/pylintgui.py:212
+#, fuzzy
+msgid "Stop current analysis"
+msgstr "Aktuellen Befehl stoppen"
-#~ msgid " and "
-#~ msgstr " und "
+#: spyder/plugins/pylint/widgets/pylintgui.py:218
+#: spyder/plugins/pylint/widgets/pylintgui.py:288
+#, fuzzy
+msgid "Select Python file"
+msgstr "Datei auswählen"
-#~ msgid "the following projects:
%s"
-#~ msgstr "die folgenden Projekte:
%s"
+#: spyder/plugins/pylint/widgets/pylintgui.py:226
+#, fuzzy
+msgid "Complete output"
+msgstr "Vervollständigung:"
-#~ msgid "Existing Pydev project"
-#~ msgstr "Bestehendes Pydev-Projekt"
+#: spyder/plugins/pylint/widgets/pylintgui.py:260
+msgid "Pylint script was not found. Please add \"%s\" to PATH."
+msgstr ""
-#~ msgid "Add to PYTHONPATH"
-#~ msgstr "Zu PYTHONPATH hinzufügen"
+#: spyder/plugins/pylint/widgets/pylintgui.py:263
+#, fuzzy
+msgid "Please install pylint:"
+msgstr "Bitte installieren Sie matplotlib oder guiqwt."
-#~ msgid "Remove from PYTHONPATH"
-#~ msgstr "Von PYTHONPATH entfernen"
+#: spyder/plugins/pylint/widgets/pylintgui.py:326
+msgid "Pylint output"
+msgstr ""
-#~ msgid "Properties"
-#~ msgstr "Eigenschaften"
+#: spyder/plugins/pylint/widgets/pylintgui.py:465
+msgid "Source code has not been rated yet."
+msgstr ""
-#~ msgid "The project %s is already opened!"
-#~ msgstr "Das Projekt %s ist bereits geöffnet!"
+#: spyder/plugins/pylint/widgets/pylintgui.py:471
+msgid "Analysis did not succeed (see output for more details)."
+msgstr ""
-#~ msgid "Import existing project"
-#~ msgstr "Bestehendes Projekt importieren"
+#: spyder/plugins/pylint/widgets/pylintgui.py:484
+msgid "Global evaluation:"
+msgstr ""
-#~ msgid "Import existing Pydev project"
-#~ msgstr "Bestehendes Pydev-Projekt importieren"
+#: spyder/plugins/pylint/widgets/pylintgui.py:488
+#, fuzzy
+msgid "previous run:"
+msgstr "Vorheriges"
-#~ msgid "This is the current workspace directory"
-#~ msgstr "Dies ist das aktuelle Arbeitsflächenverzeichnis"
+#~ msgid "Parent"
+#~ msgstr "Übergeordnetes"
diff --git a/spyder/locale/es/LC_MESSAGES/spyder.mo b/spyder/locale/es/LC_MESSAGES/spyder.mo
index 7e19ef1580e..c563594abe1 100644
Binary files a/spyder/locale/es/LC_MESSAGES/spyder.mo and b/spyder/locale/es/LC_MESSAGES/spyder.mo differ
diff --git a/spyder/locale/es/LC_MESSAGES/spyder.po b/spyder/locale/es/LC_MESSAGES/spyder.po
index 09ac5e07dd1..ea82ef126f6 100644
--- a/spyder/locale/es/LC_MESSAGES/spyder.po
+++ b/spyder/locale/es/LC_MESSAGES/spyder.po
@@ -1,12 +1,18 @@
# -*- coding: utf-8 -*-
-# Spyder's spanish translation file
-# Copyright (C) 2011 Spyder Development team
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+#
+# Spyder's Spanish gettext translation file
#
msgid ""
msgstr ""
"Project-Id-Version: 2.1\n"
-"POT-Creation-Date: 2018-02-19 11:56+-05\n"
-"PO-Revision-Date: 2018-02-25 10:23-0500\n"
+"POT-Creation-Date: 2018-11-13 11:49+-05\n"
+"PO-Revision-Date: 2018-11-20 14:35-0500\n"
"Last-Translator: Carlos Cordoba \n"
"Language-Team: Python\n"
"Language: es\n"
@@ -16,49 +22,41 @@ msgstr ""
"Generated-By: pygettext.py 1.5\n"
"X-Poedit-SourceCharset: utf-8\n"
"X-Poedit-Basepath: ../../../..\n"
-"X-Generator: Poedit 2.0.1\n"
+"X-Generator: Poedit 2.0.4\n"
-#: spyder/app/mainwindow.py:134
+#: spyder/app/mainwindow.py:139
msgid "Initializing..."
msgstr "Inicializando..."
-#: spyder/app/mainwindow.py:238
+#: spyder/app/mainwindow.py:252
msgid "Python2 documentation"
msgstr "Documentación de Python2"
-#: spyder/app/mainwindow.py:240
+#: spyder/app/mainwindow.py:254
msgid "Python3 documentation"
msgstr "Documentación de Python3"
-#: spyder/app/mainwindow.py:242
+#: spyder/app/mainwindow.py:256
msgid "Numpy and Scipy documentation"
msgstr "Documentación de Numpy y Scipy"
-#: spyder/app/mainwindow.py:244
+#: spyder/app/mainwindow.py:258
msgid "Matplotlib documentation"
msgstr "Documentación de Matplotlib"
-#: spyder/app/mainwindow.py:247
-msgid "PyQt4 Reference Guide"
-msgstr "Manual de referencia de PyQt4"
-
-#: spyder/app/mainwindow.py:250
-msgid "PyQt4 API Reference"
-msgstr "Referencia del API de PyQt4"
-
-#: spyder/app/mainwindow.py:253
+#: spyder/app/mainwindow.py:261
msgid "PyQt5 Reference Guide"
msgstr "Manual de referencia de PyQt5"
-#: spyder/app/mainwindow.py:256
+#: spyder/app/mainwindow.py:264
msgid "PyQt5 API Reference"
msgstr "Referencia del API de PyQt5"
-#: spyder/app/mainwindow.py:258
+#: spyder/app/mainwindow.py:266
msgid "WinPython"
msgstr "WinPython"
-#: spyder/app/mainwindow.py:518
+#: spyder/app/mainwindow.py:525
msgid ""
"An error occurred while creating a socket needed by Spyder. Please, try to "
"run as an Administrator from cmd.exe the following command and then restart "
@@ -70,173 +68,173 @@ msgstr ""
"el siguiente comando y reinicie su equipo:
netsh winsock reset
"
-#: spyder/app/mainwindow.py:550
+#: spyder/app/mainwindow.py:557
msgid "Close current pane"
msgstr "Cerrar panel actual"
-#: spyder/app/mainwindow.py:555
+#: spyder/app/mainwindow.py:562
msgid "Lock panes"
msgstr "Bloquear los paneles"
-#: spyder/app/mainwindow.py:562
+#: spyder/app/mainwindow.py:569
msgid "Use next layout"
msgstr "Utilizar la siguiente disposición"
-#: spyder/app/mainwindow.py:566
+#: spyder/app/mainwindow.py:573
msgid "Use previous layout"
msgstr "Utilizar la disposición anterior"
-#: spyder/app/mainwindow.py:576 spyder/widgets/editor.py:497
+#: spyder/app/mainwindow.py:583 spyder/widgets/editor.py:507
msgid "File switcher..."
msgstr "Cambiador de archivos..."
-#: spyder/app/mainwindow.py:578
+#: spyder/app/mainwindow.py:585
msgid "Fast switch between files"
msgstr "Cambiar rápidamente entre archivos"
-#: spyder/app/mainwindow.py:584
+#: spyder/app/mainwindow.py:591
msgid "Symbol finder..."
msgstr "Buscador de símbolos..."
-#: spyder/app/mainwindow.py:586
+#: spyder/app/mainwindow.py:593
msgid "Fast symbol search in file"
msgstr "Búsqueda rápida de símbolos en el archivo"
-#: spyder/app/mainwindow.py:605 spyder/widgets/sourcecode/codeeditor.py:2673
+#: spyder/app/mainwindow.py:612 spyder/widgets/sourcecode/codeeditor.py:2680
msgid "Undo"
msgstr "Deshacer"
-#: spyder/app/mainwindow.py:607 spyder/widgets/sourcecode/codeeditor.py:2676
+#: spyder/app/mainwindow.py:614 spyder/widgets/sourcecode/codeeditor.py:2683
msgid "Redo"
msgstr "Rehacer"
-#: spyder/app/mainwindow.py:609 spyder/widgets/shell.py:123
-#: spyder/widgets/sourcecode/codeeditor.py:2682
-#: spyder/widgets/variableexplorer/arrayeditor.py:467
-#: spyder/widgets/variableexplorer/collectionseditor.py:674
-#: spyder/widgets/variableexplorer/dataframeeditor.py:592
+#: spyder/app/mainwindow.py:616 spyder/widgets/shell.py:123
+#: spyder/widgets/sourcecode/codeeditor.py:2689
+#: spyder/widgets/variableexplorer/arrayeditor.py:465
+#: spyder/widgets/variableexplorer/collectionseditor.py:710
+#: spyder/widgets/variableexplorer/dataframeeditor.py:616
msgid "Copy"
msgstr "Copiar"
-#: spyder/app/mainwindow.py:611 spyder/widgets/shell.py:119
-#: spyder/widgets/sourcecode/codeeditor.py:2679
+#: spyder/app/mainwindow.py:618 spyder/widgets/shell.py:119
+#: spyder/widgets/sourcecode/codeeditor.py:2686
msgid "Cut"
msgstr "Cortar"
-#: spyder/app/mainwindow.py:613 spyder/widgets/shell.py:127
-#: spyder/widgets/sourcecode/codeeditor.py:2685
-#: spyder/widgets/variableexplorer/collectionseditor.py:671
+#: spyder/app/mainwindow.py:620 spyder/widgets/shell.py:127
+#: spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/widgets/variableexplorer/collectionseditor.py:707
msgid "Paste"
msgstr "Pegar"
-#: spyder/app/mainwindow.py:616 spyder/widgets/shell.py:140
-#: spyder/widgets/sourcecode/codeeditor.py:2688
+#: spyder/app/mainwindow.py:623 spyder/widgets/shell.py:140
+#: spyder/widgets/sourcecode/codeeditor.py:2695
msgid "Select All"
msgstr "Seleccionar todo"
-#: spyder/app/mainwindow.py:626 spyder/plugins/editor.py:1422
+#: spyder/app/mainwindow.py:633 spyder/plugins/editor.py:1421
msgid "&File"
msgstr "&Archivo"
-#: spyder/app/mainwindow.py:627 spyder/plugins/editor.py:1410
+#: spyder/app/mainwindow.py:634 spyder/plugins/editor.py:1409
msgid "File toolbar"
msgstr "Barra de archivo"
-#: spyder/app/mainwindow.py:631 spyder/plugins/editor.py:1423
+#: spyder/app/mainwindow.py:638 spyder/plugins/editor.py:1422
msgid "&Edit"
msgstr "&Editar"
-#: spyder/app/mainwindow.py:632 spyder/plugins/editor.py:1420
+#: spyder/app/mainwindow.py:639 spyder/plugins/editor.py:1419
msgid "Edit toolbar"
msgstr "Barra de edición"
-#: spyder/app/mainwindow.py:636 spyder/plugins/editor.py:1424
+#: spyder/app/mainwindow.py:643 spyder/plugins/editor.py:1423
msgid "&Search"
msgstr "&Buscar"
-#: spyder/app/mainwindow.py:637 spyder/plugins/editor.py:1412
+#: spyder/app/mainwindow.py:644 spyder/plugins/editor.py:1411
msgid "Search toolbar"
msgstr "Barra de búsqueda"
-#: spyder/app/mainwindow.py:641 spyder/plugins/editor.py:1425
+#: spyder/app/mainwindow.py:648 spyder/plugins/editor.py:1424
msgid "Sour&ce"
msgstr "&Código fuente"
-#: spyder/app/mainwindow.py:642 spyder/plugins/editor.py:1414
+#: spyder/app/mainwindow.py:649 spyder/plugins/editor.py:1413
msgid "Source toolbar"
msgstr "Barra de código fuente"
-#: spyder/app/mainwindow.py:646 spyder/plugins/editor.py:803
-#: spyder/plugins/editor.py:1426
+#: spyder/app/mainwindow.py:653 spyder/plugins/editor.py:803
+#: spyder/plugins/editor.py:1425
msgid "&Run"
msgstr "E&jecutar"
-#: spyder/app/mainwindow.py:647 spyder/plugins/editor.py:1416
+#: spyder/app/mainwindow.py:654 spyder/plugins/editor.py:1415
msgid "Run toolbar"
msgstr "Barra de ejecución"
-#: spyder/app/mainwindow.py:651 spyder/plugins/editor.py:762
+#: spyder/app/mainwindow.py:658 spyder/plugins/editor.py:762
msgid "&Debug"
msgstr "&Depurar"
-#: spyder/app/mainwindow.py:652 spyder/plugins/editor.py:1418
+#: spyder/app/mainwindow.py:659 spyder/plugins/editor.py:1417
msgid "Debug toolbar"
msgstr "Barra de depuración"
-#: spyder/app/mainwindow.py:656
+#: spyder/app/mainwindow.py:663
msgid "C&onsoles"
msgstr "&Terminales"
-#: spyder/app/mainwindow.py:659
+#: spyder/app/mainwindow.py:666
msgid "&Projects"
msgstr "&Proyectos"
-#: spyder/app/mainwindow.py:662 spyder/plugins/editor.py:1427
+#: spyder/app/mainwindow.py:669 spyder/plugins/editor.py:1426
msgid "&Tools"
msgstr "&Herramientas"
-#: spyder/app/mainwindow.py:665 spyder/plugins/editor.py:1428
+#: spyder/app/mainwindow.py:672 spyder/plugins/editor.py:1427
msgid "&View"
msgstr "&Ver"
-#: spyder/app/mainwindow.py:668 spyder/plugins/editor.py:1429
+#: spyder/app/mainwindow.py:675 spyder/plugins/editor.py:1428
msgid "&Help"
msgstr "A&yuda"
-#: spyder/app/mainwindow.py:673
+#: spyder/app/mainwindow.py:680
msgid "Welcome to Spyder!"
msgstr "Bienvenido a Spyder!"
-#: spyder/app/mainwindow.py:678
+#: spyder/app/mainwindow.py:685
msgid "Pre&ferences"
msgstr "Pre&ferencias"
-#: spyder/app/mainwindow.py:685 spyder/widgets/pathmanager.py:53
+#: spyder/app/mainwindow.py:692 spyder/widgets/pathmanager.py:54
msgid "PYTHONPATH manager"
msgstr "Administrador del PYTHONPATH"
-#: spyder/app/mainwindow.py:688
+#: spyder/app/mainwindow.py:695
msgid "Python Path Manager"
msgstr "Manejador de rutas de Python"
-#: spyder/app/mainwindow.py:691
+#: spyder/app/mainwindow.py:698
msgid "Update module names list"
msgstr "Actualizar la lista de nombres de módulos"
-#: spyder/app/mainwindow.py:694
+#: spyder/app/mainwindow.py:701
msgid "Refresh list of module names available in PYTHONPATH"
msgstr ""
"Actualiza la lista de nombres de los módulos disponibles en su PYTHONPATH"
-#: spyder/app/mainwindow.py:697
+#: spyder/app/mainwindow.py:704
msgid "Reset Spyder to factory defaults"
msgstr "Restaurar Spyder a su configuración por defecto"
-#: spyder/app/mainwindow.py:702
+#: spyder/app/mainwindow.py:709
msgid "Current user environment variables..."
msgstr "Variables de entorno del usuario actual..."
-#: spyder/app/mainwindow.py:704
+#: spyder/app/mainwindow.py:711
msgid ""
"Show and edit current user environment variables in Windows registry (i.e. "
"for all sessions)"
@@ -246,51 +244,43 @@ msgstr ""
"registro de Windows (es decir,\n"
"para todas las sesiones)"
-#: spyder/app/mainwindow.py:713 spyder/app/mainwindow.py:1137
+#: spyder/app/mainwindow.py:720 spyder/app/mainwindow.py:1115
msgid "External Tools"
msgstr "Herramientas externas"
-#: spyder/app/mainwindow.py:716
+#: spyder/app/mainwindow.py:723
msgid "WinPython control panel"
msgstr "Panel de control de WinPython"
-#: spyder/app/mainwindow.py:725
+#: spyder/app/mainwindow.py:733
msgid "Qt Designer"
msgstr "Diseñador de interfaces de Qt"
-#: spyder/app/mainwindow.py:730
+#: spyder/app/mainwindow.py:737
msgid "Qt Linguist"
msgstr "Traductor de aplicaciones de Qt"
-#: spyder/app/mainwindow.py:736
-msgid "Qt examples"
-msgstr "Ejemplos de Qt"
-
-#: spyder/app/mainwindow.py:756
+#: spyder/app/mainwindow.py:758
msgid "guidata examples"
msgstr "Ejemplos de guidata"
-#: spyder/app/mainwindow.py:767
+#: spyder/app/mainwindow.py:769
msgid "guiqwt examples"
msgstr "Ejemplos de guiqwt"
-#: spyder/app/mainwindow.py:772
+#: spyder/app/mainwindow.py:774
msgid "Sift"
msgstr "Sift"
-#: spyder/app/mainwindow.py:782
-msgid "ViTables"
-msgstr "ViTables"
-
-#: spyder/app/mainwindow.py:796
+#: spyder/app/mainwindow.py:792
msgid "Fullscreen mode"
msgstr "Modo a pantalla completa"
-#: spyder/app/mainwindow.py:808
+#: spyder/app/mainwindow.py:804
msgid "Main toolbar"
msgstr "Barra principal"
-#: spyder/app/mainwindow.py:817
+#: spyder/app/mainwindow.py:813
msgid ""
"Spyder Internal Console\n"
"\n"
@@ -311,167 +301,169 @@ msgstr ""
"\n"
"Por favor no ejecuta su código en esta terminal\n"
-#: spyder/app/mainwindow.py:834
+#: spyder/app/mainwindow.py:830
msgid "Loading help..."
msgstr "Cargando la ayuda..."
-#: spyder/app/mainwindow.py:841
+#: spyder/app/mainwindow.py:837
msgid "Loading outline explorer..."
msgstr "Cargando el explorador de código..."
-#: spyder/app/mainwindow.py:847
+#: spyder/app/mainwindow.py:843
msgid "Loading editor..."
msgstr "Cargando el editor..."
-#: spyder/app/mainwindow.py:853 spyder/plugins/console.py:141
-#: spyder/widgets/ipythonconsole/client.py:414
+#: spyder/app/mainwindow.py:849 spyder/plugins/console.py:141
+#: spyder/widgets/ipythonconsole/client.py:453
msgid "&Quit"
msgstr "&Salir"
-#: spyder/app/mainwindow.py:855 spyder/plugins/console.py:143
+#: spyder/app/mainwindow.py:851 spyder/plugins/console.py:143
msgid "Quit"
msgstr "Salir"
-#: spyder/app/mainwindow.py:859
+#: spyder/app/mainwindow.py:855
msgid "&Restart"
msgstr "&Reiniciar"
-#: spyder/app/mainwindow.py:861
+#: spyder/app/mainwindow.py:857
msgid "Restart"
msgstr "Reiniciar"
-#: spyder/app/mainwindow.py:875
+#: spyder/app/mainwindow.py:871
msgid "Loading file explorer..."
msgstr "Cargando el explorador de archivos..."
-#: spyder/app/mainwindow.py:882
+#: spyder/app/mainwindow.py:878
msgid "Loading history plugin..."
msgstr "Cargando el historial..."
-#: spyder/app/mainwindow.py:893
+#: spyder/app/mainwindow.py:889
msgid "Loading online help..."
msgstr "Cargando la ayuda en línea..."
-#: spyder/app/mainwindow.py:898
+#: spyder/app/mainwindow.py:894
msgid "Loading project explorer..."
msgstr "Cargando el explorador de proyectos..."
-#: spyder/app/mainwindow.py:911
+#: spyder/app/mainwindow.py:907
msgid "Loading namespace browser..."
msgstr "Cargando el explorador de variables..."
-#: spyder/app/mainwindow.py:917
+#: spyder/app/mainwindow.py:913
msgid "Loading IPython console..."
msgstr "Cargando la terminal de IPython..."
-#: spyder/app/mainwindow.py:922
+#: spyder/app/mainwindow.py:918
msgid "Setting up main window..."
msgstr "Construyendo la ventana principal..."
-#: spyder/app/mainwindow.py:926
+#: spyder/app/mainwindow.py:922
msgid "Troubleshooting..."
msgstr "Solución de problemas..."
-#: spyder/app/mainwindow.py:928
+#: spyder/app/mainwindow.py:924
msgid "Dependencies..."
msgstr "Dependencias..."
-#: spyder/app/mainwindow.py:932
+#: spyder/app/mainwindow.py:928
msgid "Report issue..."
msgstr "Reportar un problema..."
-#: spyder/app/mainwindow.py:936
+#: spyder/app/mainwindow.py:932
msgid "Spyder support..."
-msgstr "Obtener soporte para Spyder"
+msgstr "Obtener soporte para Spyder..."
-#: spyder/app/mainwindow.py:939
+#: spyder/app/mainwindow.py:935
msgid "Check for updates..."
msgstr "Buscar actualizaciones..."
-#: spyder/app/mainwindow.py:962
+#: spyder/app/mainwindow.py:940
msgid "Spyder documentation"
msgstr "Documentación de Spyder"
-#: spyder/app/mainwindow.py:970
+#: spyder/app/mainwindow.py:948
msgid "Spyder tutorial"
msgstr "Tutorial de Spyder"
-#: spyder/app/mainwindow.py:975
+#: spyder/app/mainwindow.py:953
msgid "Shortcuts Summary"
msgstr "Resumen de atajos"
-#: spyder/app/mainwindow.py:981
+#: spyder/app/mainwindow.py:959
msgid "Interactive tours"
msgstr "Tours interactivos"
-#: spyder/app/mainwindow.py:1008
+#: spyder/app/mainwindow.py:986
msgid "Python documentation"
msgstr "Documentación de Python"
-#: spyder/app/mainwindow.py:1014
+#: spyder/app/mainwindow.py:992
msgid "IPython documentation"
msgstr "Documentación de IPython"
-#: spyder/app/mainwindow.py:1015
+#: spyder/app/mainwindow.py:993
msgid "Intro to IPython"
msgstr "Ayuda básica"
-#: spyder/app/mainwindow.py:1017
+#: spyder/app/mainwindow.py:995
msgid "Quick reference"
msgstr "Referencia rápida"
-#: spyder/app/mainwindow.py:1019
+#: spyder/app/mainwindow.py:997
msgid "Console help"
msgstr "Ayuda de la terminal"
-#: spyder/app/mainwindow.py:1049
+#: spyder/app/mainwindow.py:1027
msgid "Installed Python modules"
msgstr "Módulos instalados de Python"
-#: spyder/app/mainwindow.py:1053
+#: spyder/app/mainwindow.py:1031
msgid "Online documentation"
msgstr "Documentación en línea"
-#: spyder/app/mainwindow.py:1066
+#: spyder/app/mainwindow.py:1044
msgid "Qt documentation"
msgstr "Documentación de Qt"
-#: spyder/app/mainwindow.py:1072
+#: spyder/app/mainwindow.py:1050
msgid "About %s..."
msgstr "Acerca de %s..."
-#: spyder/app/mainwindow.py:1103
+#: spyder/app/mainwindow.py:1081
msgid "Panes"
msgstr "Paneles"
-#: spyder/app/mainwindow.py:1105
+#: spyder/app/mainwindow.py:1083
msgid "Toolbars"
msgstr "Barras de herramientas"
-#: spyder/app/mainwindow.py:1106
+#: spyder/app/mainwindow.py:1084
msgid "Window layouts"
msgstr "Disposiciones de componentes"
-#: spyder/app/mainwindow.py:1115 spyder/app/mainwindow.py:1943
-#: spyder/app/mainwindow.py:1944
+#: spyder/app/mainwindow.py:1093 spyder/app/mainwindow.py:1920
+#: spyder/app/mainwindow.py:1921
msgid "Show toolbars"
msgstr "Mostrar barras de herramientas"
-#: spyder/app/mainwindow.py:1130
+#: spyder/app/mainwindow.py:1108
msgid "Attached console window (debugging)"
msgstr "Ventana de terminal anexa (para depuración)"
-#: spyder/app/mainwindow.py:1322 spyder/plugins/projects.py:254
-#: spyder/widgets/explorer.py:721 spyder/widgets/explorer.py:826
-#: spyder/widgets/variableexplorer/arrayeditor.py:587
-#: spyder/widgets/variableexplorer/collectionseditor.py:427
-#: spyder/widgets/variableexplorer/dataframeeditor.py:758
-#: spyder/widgets/variableexplorer/dataframeeditor.py:762
-#: spyder/widgets/variableexplorer/namespacebrowser.py:299
+#: spyder/app/mainwindow.py:1298 spyder/app/mainwindow.py:1988
+#: spyder/plugins/configdialog.py:1154 spyder/plugins/projects.py:269
+#: spyder/widgets/explorer.py:723 spyder/widgets/explorer.py:828
+#: spyder/widgets/reporterror.py:285
+#: spyder/widgets/variableexplorer/arrayeditor.py:586
+#: spyder/widgets/variableexplorer/collectionseditor.py:460
+#: spyder/widgets/variableexplorer/dataframeeditor.py:797
+#: spyder/widgets/variableexplorer/dataframeeditor.py:801
+#: spyder/widgets/variableexplorer/namespacebrowser.py:311
msgid "Error"
msgstr "Error"
-#: spyder/app/mainwindow.py:1323
+#: spyder/app/mainwindow.py:1299
msgid ""
"You have missing dependencies!
%s
Please "
"install them to avoid this message.
Note: Spyder could "
@@ -490,38 +482,41 @@ msgstr ""
"favor asegúrese de que cualquier error que encuentre no sea el resultado "
"directo de las dependencias faltantes, antes de reportar un nuevo problema."
-#: spyder/app/mainwindow.py:1779
+#: spyder/app/mainwindow.py:1756
msgid "Spyder Default Layout"
msgstr "Disposición por defecto"
-#: spyder/app/mainwindow.py:1797
+#: spyder/app/mainwindow.py:1774
msgid "Save current layout"
msgstr "Guardar la disposición actual"
-#: spyder/app/mainwindow.py:1801
+#: spyder/app/mainwindow.py:1778
msgid "Layout preferences"
msgstr "Preferencias de disposición"
-#: spyder/app/mainwindow.py:1805
+#: spyder/app/mainwindow.py:1782
msgid "Reset to spyder default"
msgstr "Restaurar la disposición por defecto"
-#: spyder/app/mainwindow.py:1825 spyder/app/mainwindow.py:1847
-#: spyder/app/mainwindow.py:1913 spyder/app/mainwindow.py:1921
-#: spyder/app/mainwindow.py:2799 spyder/plugins/configdialog.py:1345
-#: spyder/plugins/ipythonconsole.py:131 spyder/plugins/ipythonconsole.py:927
-#: spyder/plugins/ipythonconsole.py:1386 spyder/plugins/maininterpreter.py:149
-#: spyder/plugins/maininterpreter.py:174 spyder/plugins/maininterpreter.py:203
-#: spyder/utils/environ.py:95 spyder/utils/environ.py:108
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:131
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:149
-#: spyder/widgets/variableexplorer/arrayeditor.py:510
-#: spyder/widgets/variableexplorer/collectionseditor.py:416
-#: spyder/widgets/variableexplorer/collectionseditor.py:1095
+#: spyder/app/mainwindow.py:1802 spyder/app/mainwindow.py:1824
+#: spyder/app/mainwindow.py:1890 spyder/app/mainwindow.py:1898
+#: spyder/app/mainwindow.py:2843 spyder/plugins/configdialog.py:1415
+#: spyder/plugins/ipythonconsole.py:134 spyder/plugins/ipythonconsole.py:987
+#: spyder/plugins/ipythonconsole.py:1439 spyder/plugins/maininterpreter.py:162
+#: spyder/plugins/maininterpreter.py:183 spyder/plugins/maininterpreter.py:212
+#: spyder/utils/environ.py:56 spyder/utils/environ.py:107
+#: spyder/utils/environ.py:120
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:140
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:158
+#: spyder/widgets/variableexplorer/arrayeditor.py:508
+#: spyder/widgets/variableexplorer/collectionseditor.py:449
+#: spyder/widgets/variableexplorer/collectionseditor.py:1131
+#: spyder/widgets/variableexplorer/collectionseditor.py:1143
+#: spyder/widgets/variableexplorer/namespacebrowser.py:305
msgid "Warning"
msgstr "Advertencia"
-#: spyder/app/mainwindow.py:1826
+#: spyder/app/mainwindow.py:1803
msgid ""
"Window layout will be reset to default settings: this affects window "
"position, size and dockwidgets.\n"
@@ -531,14 +526,14 @@ msgstr ""
"Esto afecta a la posición y tamaño de la ventana y los componentes.\n"
"¿Desea continuar?"
-#: spyder/app/mainwindow.py:1848
+#: spyder/app/mainwindow.py:1825
msgid ""
"Layout %s will be "
"overwritten. Do you want to "
"continue?"
msgstr "La disposición %s será sobrescrita. Desea continuar?"
-#: spyder/app/mainwindow.py:1914
+#: spyder/app/mainwindow.py:1891
msgid ""
"Error opening the custom layout. Please close Spyder and try again. If the "
"issue persists, then you must use 'Reset to Spyder default' from the layout "
@@ -549,43 +544,53 @@ msgstr ""
"utilice 'Restaurar la disposición por defecto' del menú 'Disposiciones de "
"componentes'."
-#: spyder/app/mainwindow.py:1922
+#: spyder/app/mainwindow.py:1899
msgid "Quick switch layout #%s has not yet been defined."
-msgstr "Aún no se ha definido la disposición de componentes #%d"
+msgstr "Aún no se ha definido la disposición de componentes #%d."
-#: spyder/app/mainwindow.py:1940 spyder/app/mainwindow.py:1941
+#: spyder/app/mainwindow.py:1917 spyder/app/mainwindow.py:1918
msgid "Hide toolbars"
msgstr "Ocultar las barras de herramientas"
-#: spyder/app/mainwindow.py:2256 spyder/app/mainwindow.py:2257
+#: spyder/app/mainwindow.py:1989
+msgid ""
+"{} is no longer a valid Spyder project! Since it is the current "
+"active project, it will be closed automatically."
+msgstr ""
+"{} ya no es un proyecto válido de Spyder! Puesto que es el actual "
+"proyecto activo, se cerrará automáticamente."
+
+#: spyder/app/mainwindow.py:2252 spyder/app/mainwindow.py:2253
msgid "Maximize current pane"
msgstr "Maximizar el panel actual"
-#: spyder/app/mainwindow.py:2260
+#: spyder/app/mainwindow.py:2256
msgid "Restore current pane"
msgstr "Restaurar el panel actual"
-#: spyder/app/mainwindow.py:2261
+#: spyder/app/mainwindow.py:2257
msgid "Restore pane to its original size"
msgstr "Restaurar el panel a su tamaño original"
-#: spyder/app/mainwindow.py:2359
+#: spyder/app/mainwindow.py:2439
msgid "About %s"
msgstr "Acerca de %s"
-#: spyder/app/mainwindow.py:2538 spyder/plugins/editor.py:168
+#: spyder/app/mainwindow.py:2579 spyder/plugins/editor.py:168
#: spyder/plugins/runconfig.py:354 spyder/plugins/runconfig.py:476
-#: spyder/utils/programs.py:286 spyder/widgets/explorer.py:344
+#: spyder/utils/programs.py:307 spyder/widgets/explorer.py:347
+#: spyder/widgets/explorer.py:271
+#: spyder/widgets/externalshell/baseshell.py:127
msgid "Run"
msgstr "Ejecutar"
-#: spyder/app/mainwindow.py:2539
+#: spyder/app/mainwindow.py:2580
msgid "Running an external system terminal is not supported on platform %s."
msgstr ""
"Ejecutar en una terminal externa del sistema no está soportado en la "
"plataforma %s."
-#: spyder/app/mainwindow.py:2800
+#: spyder/app/mainwindow.py:2844
msgid ""
"Spyder will restart and reset to default settings:
Do you want to "
"continue?"
@@ -593,15 +598,15 @@ msgstr ""
"Spyder se reiniciará y volverá a su configuración por defecto: "
"
¿Desea continuar?"
-#: spyder/app/mainwindow.py:2928 spyder/widgets/helperwidgets.py:254
+#: spyder/app/mainwindow.py:2973 spyder/widgets/helperwidgets.py:254
msgid "Spyder updates"
msgstr "Actualizaciones de Spyder"
-#: spyder/app/mainwindow.py:2929 spyder/plugins/configdialog.py:835
+#: spyder/app/mainwindow.py:2974 spyder/plugins/configdialog.py:888
msgid "Check for updates on startup"
msgstr "Buscar actualizaciones al inicio"
-#: spyder/app/mainwindow.py:2948
+#: spyder/app/mainwindow.py:2993
msgid ""
"
IMPORTANT NOTE: It seems that you are using Spyder with "
"Anaconda/Miniconda. Please don't use pip
to "
@@ -615,7 +620,7 @@ msgstr ""
"lugar, por favor espere hasta que nuevos paquetes de conda estén disponibles "
"y utilice conda
para realizar la actualización.
"
-#: spyder/app/mainwindow.py:2958
+#: spyder/app/mainwindow.py:3003
msgid ""
"Spyder %s is available!
Please use your package manager to "
"update Spyder or go to our Releases page to download this "
@@ -628,7 +633,7 @@ msgstr ""
"seguro de cómo proceder para actualizar Spyder, por favor lea nuestra "
"instrucciones de Instalación (en inglés)."
-#: spyder/app/mainwindow.py:2971
+#: spyder/app/mainwindow.py:3016
msgid "Spyder is up to date."
msgstr "Spyder está actualizado."
@@ -682,7 +687,7 @@ msgstr "Reiniciando"
#: spyder/app/tour.py:123
msgid "Welcome to the Introduction tour"
-msgstr "Bienvenido al Tour introductorio!"
+msgstr "Bienvenido al Tour introductorio"
#: spyder/app/tour.py:124
msgid ""
@@ -764,8 +769,9 @@ msgstr ""
"mostrará una nueva ventana, en la cual se pueden inspeccionar y modificar "
"sus contenidos."
-#: spyder/app/tour.py:179 spyder/plugins/help.py:484 spyder/plugins/help.py:937
-#: spyder/widgets/internalshell.py:270
+#: spyder/app/tour.py:179 spyder/plugins/help.py:482 spyder/plugins/help.py:931
+#: spyder/widgets/internalshell.py:271
+#: spyder/plugins/help.py:929 spyder/widgets/internalshell.py:270
msgid "Help"
msgstr "Ayuda"
@@ -816,7 +822,7 @@ msgstr "Spyder es un ambiente interactivo de desarrollo basado en bla"
#: spyder/app/tour.py:254
msgid "Welcome to Spyder introduction tour"
-msgstr "Bienvenido al Tour Introductorio de Spyder!"
+msgstr "Bienvenido al Tour Introductorio de Spyder"
#: spyder/app/tour.py:255
msgid "Spyder is an interactive development environment based on bla"
@@ -830,216 +836,213 @@ msgstr "Tour Introductorio"
msgid "New features in version 3.0"
msgstr "Nuevas características en Spyder 3.0"
-#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:446
+#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:474
msgid "Run code"
msgstr "Ejecutar código"
#: spyder/app/tour.py:830
msgid "Go to step: "
-msgstr "Ir al paso:"
+msgstr "Ir al paso: "
-#: spyder/config/base.py:269
-msgid ""
-"Update LANGUAGE_CODES (inside config/base.py) if a new translation has been "
-"added to Spyder"
-msgstr ""
-"Actualice LANGUAGE_CODES (en config/base.py) si una nueva traducción se "
-"añadió a Spyder"
-
-#: spyder/config/utils.py:24
+#: spyder/config/utils.py:25
msgid "Python files"
msgstr "Archivos Python"
-#: spyder/config/utils.py:25
+#: spyder/config/utils.py:26
msgid "Cython/Pyrex files"
msgstr "Archivos Cython/Pyrex"
-#: spyder/config/utils.py:26
+#: spyder/config/utils.py:27
msgid "C files"
msgstr "Archivos C"
-#: spyder/config/utils.py:27
+#: spyder/config/utils.py:28
msgid "C++ files"
msgstr "Archivos C++"
-#: spyder/config/utils.py:28
+#: spyder/config/utils.py:29
msgid "OpenCL files"
msgstr "Archivos OpenCL"
-#: spyder/config/utils.py:29
+#: spyder/config/utils.py:30
msgid "Fortran files"
msgstr "Archivos Fortran"
-#: spyder/config/utils.py:30
+#: spyder/config/utils.py:31
msgid "IDL files"
msgstr "Archivos IDL"
-#: spyder/config/utils.py:31
+#: spyder/config/utils.py:32
msgid "MATLAB files"
msgstr "Archivos MATLAB"
-#: spyder/config/utils.py:32
+#: spyder/config/utils.py:33
msgid "Julia files"
msgstr "Archivos Julia"
-#: spyder/config/utils.py:33
+#: spyder/config/utils.py:34
msgid "Yaml files"
msgstr "Archivos Yaml"
-#: spyder/config/utils.py:34
+#: spyder/config/utils.py:35
msgid "Patch and diff files"
msgstr "Archivos Patch y diff"
-#: spyder/config/utils.py:35
+#: spyder/config/utils.py:36
msgid "Batch files"
msgstr "Archivos Batch"
-#: spyder/config/utils.py:36 spyder/utils/iofuncs.py:426
+#: spyder/config/utils.py:37
msgid "Text files"
msgstr "Archivos de Texto"
-#: spyder/config/utils.py:37
+#: spyder/config/utils.py:38
msgid "reStructuredText files"
-msgstr "Archivos de Texto reStructurado"
+msgstr "Archivos de Texto restructurado"
-#: spyder/config/utils.py:38
+#: spyder/config/utils.py:39
msgid "gettext files"
msgstr "Archivos gettext"
-#: spyder/config/utils.py:39
+#: spyder/config/utils.py:40
msgid "NSIS files"
msgstr "Archivos NSIS"
-#: spyder/config/utils.py:40
+#: spyder/config/utils.py:41
msgid "Web page files"
msgstr "Archivos de Páginas web"
-#: spyder/config/utils.py:41
+#: spyder/config/utils.py:42
msgid "XML files"
msgstr "Archivos XML"
-#: spyder/config/utils.py:42
+#: spyder/config/utils.py:43
msgid "Javascript files"
msgstr "Archivos Javascript"
-#: spyder/config/utils.py:43
+#: spyder/config/utils.py:44
msgid "Json files"
msgstr "Archivos Json"
-#: spyder/config/utils.py:44
+#: spyder/config/utils.py:45
msgid "IPython notebooks"
msgstr "Notebooks de IPython"
-#: spyder/config/utils.py:45
+#: spyder/config/utils.py:46
msgid "Enaml files"
msgstr "Archivos Enaml"
-#: spyder/config/utils.py:46
+#: spyder/config/utils.py:47
msgid "Configuration files"
msgstr "Archivos de Configuración"
-#: spyder/config/utils.py:48
+#: spyder/config/utils.py:49
msgid "Markdown files"
msgstr "Archivos Markdown"
-#: spyder/config/utils.py:52 spyder/widgets/explorer.py:794
+#: spyder/config/utils.py:53 spyder/widgets/explorer.py:796
msgid "All files"
msgstr "Todos los archivos"
-#: spyder/config/utils.py:134
+#: spyder/config/utils.py:138
msgid "Supported text files"
msgstr "Archivos de texto soportados"
-#: spyder/plugins/__init__.py:511 spyder/plugins/editor.py:105
-#: spyder/plugins/editor.py:568 spyder/plugins/editor.py:1816
-#: spyder/plugins/help.py:117 spyder/plugins/help.py:385
-#: spyder/widgets/editor.py:534 spyder/widgets/sourcecode/codeeditor.py:98
-#: spyder/widgets/sourcecode/codeeditor.py:3222
+#: spyder/plugins/__init__.py:512 spyder/plugins/editor.py:105
+#: spyder/plugins/editor.py:568 spyder/plugins/editor.py:1830
+#: spyder/plugins/help.py:117 spyder/plugins/help.py:383
+#: spyder/widgets/editor.py:544 spyder/widgets/sourcecode/codeeditor.py:98
+#: spyder/widgets/sourcecode/codeeditor.py:3229
msgid "Editor"
msgstr "Editor"
-#: spyder/plugins/configdialog.py:144
+#: spyder/plugins/configdialog.py:146
msgid "Reset to defaults"
msgstr "Restaurar los valores por defecto"
-#: spyder/plugins/configdialog.py:156
+#: spyder/plugins/configdialog.py:158
msgid "Preferences"
msgstr "Preferencias"
-#: spyder/plugins/configdialog.py:508
+#: spyder/plugins/configdialog.py:514
msgid "Invalid directory path"
msgstr "Ruta de directorio inválida"
-#: spyder/plugins/configdialog.py:511 spyder/plugins/configdialog.py:526
+#: spyder/plugins/configdialog.py:517 spyder/plugins/configdialog.py:532
#: spyder/plugins/runconfig.py:220 spyder/plugins/runconfig.py:268
-#: spyder/plugins/workingdirectory.py:240 spyder/widgets/explorer.py:705
-#: spyder/widgets/findinfiles.py:332 spyder/widgets/pathmanager.py:258
+#: spyder/plugins/workingdirectory.py:241 spyder/widgets/explorer.py:707
+#: spyder/widgets/findinfiles.py:347 spyder/widgets/pathmanager.py:259
#: spyder/widgets/projects/projectdialog.py:155
msgid "Select directory"
msgstr "Seleccionar directorio"
-#: spyder/plugins/configdialog.py:538
+#: spyder/plugins/configdialog.py:544 spyder/plugins/configdialog.py:704
msgid "Invalid file path"
msgstr "Ruta de archivo inválida"
-#: spyder/plugins/configdialog.py:541 spyder/plugins/configdialog.py:558
+#: spyder/plugins/configdialog.py:547 spyder/plugins/configdialog.py:564
+#: spyder/plugins/configdialog.py:707
msgid "Select file"
msgstr "Seleccionar archivo"
-#: spyder/plugins/configdialog.py:557
+#: spyder/plugins/configdialog.py:563
msgid "All files (*)"
msgstr "Todos los archivos (*)"
-#: spyder/plugins/configdialog.py:630
+#: spyder/plugins/configdialog.py:636
msgid "Bold"
msgstr "Negrita"
-#: spyder/plugins/configdialog.py:633
+#: spyder/plugins/configdialog.py:639
msgid "Italic"
msgstr "Cursiva"
-#: spyder/plugins/configdialog.py:687
+#: spyder/plugins/configdialog.py:728
msgid "Font: "
-msgstr "Tipo de letra"
+msgstr "Tipo de letra: "
-#: spyder/plugins/configdialog.py:693
+#: spyder/plugins/configdialog.py:734
msgid "Size: "
-msgstr "Tamaño:"
+msgstr "Tamaño: "
-#: spyder/plugins/configdialog.py:712
+#: spyder/plugins/configdialog.py:753
msgid "Font style"
msgstr "Fuente"
-#: spyder/plugins/configdialog.py:789
+#: spyder/plugins/configdialog.py:830
msgid "Spyder needs to restart to change the following setting:"
msgstr "Spyder necesita reiniciar para cambiar la siguiente configuración:"
-#: spyder/plugins/configdialog.py:792
+#: spyder/plugins/configdialog.py:833
msgid "Spyder needs to restart to change the following settings:"
msgstr "Spyder necesita reiniciar para cambiar las siguientes configuraciones:"
-#: spyder/plugins/configdialog.py:794
+#: spyder/plugins/configdialog.py:835
msgid "Do you wish to restart now?"
msgstr "¿Desea reiniciar ahora?"
-#: spyder/plugins/configdialog.py:800
+#: spyder/plugins/configdialog.py:841
msgid "Information"
msgstr "Información"
-#: spyder/plugins/configdialog.py:814 spyder/plugins/configdialog.py:821
+#: spyder/plugins/configdialog.py:855 spyder/plugins/configdialog.py:862
#: spyder/widgets/projects/configdialog.py:74
msgid "General"
msgstr "General"
-#: spyder/plugins/configdialog.py:824
-msgid "Language"
-msgstr "Lenguaje"
+#: spyder/plugins/configdialog.py:866
+msgid "Language:"
+msgstr "Lenguaje:"
+
+#: spyder/plugins/configdialog.py:874
+msgid "Rendering engine:"
+msgstr "Motor de renderización:"
-#: spyder/plugins/configdialog.py:827
+#: spyder/plugins/configdialog.py:879
msgid "Use a single instance"
msgstr "Utilizar una única instancia"
-#: spyder/plugins/configdialog.py:829
+#: spyder/plugins/configdialog.py:881
msgid ""
"Set this to open external
Python files in an already running instance "
"(Requires a restart)"
@@ -1047,91 +1050,91 @@ msgstr ""
"Seleccione esta opción
para abrir archivos externos de Python en la "
"ventana actual (Requiere reiniciar)"
-#: spyder/plugins/configdialog.py:832
+#: spyder/plugins/configdialog.py:885
msgid "Prompt when exiting"
msgstr "Preguntar antes de salir"
-#: spyder/plugins/configdialog.py:833
+#: spyder/plugins/configdialog.py:886
msgid "Show internal Spyder errors to report them to Github"
msgstr "Mostrar errores internos de Spyder para reportarlos en Github"
-#: spyder/plugins/configdialog.py:852 spyder/plugins/editor.py:114
-#: spyder/plugins/ipythonconsole.py:290
+#: spyder/plugins/configdialog.py:914 spyder/plugins/editor.py:114
+#: spyder/plugins/ipythonconsole.py:301
#: spyder/widgets/projects/configdialog.py:81
msgid "Interface"
msgstr "Interfaz"
-#: spyder/plugins/configdialog.py:860
+#: spyder/plugins/configdialog.py:922
msgid "Qt windows style"
msgstr "Estilo de Qt"
-#: spyder/plugins/configdialog.py:866
+#: spyder/plugins/configdialog.py:928
msgid "Icon theme"
msgstr "Tema de iconos"
-#: spyder/plugins/configdialog.py:870
+#: spyder/plugins/configdialog.py:932
msgid "Vertical title bars in panes"
msgstr "Barras de título verticales para los paneles"
-#: spyder/plugins/configdialog.py:872
+#: spyder/plugins/configdialog.py:934
msgid "Vertical tabs in panes"
msgstr "Pestañas verticales en los paneles"
-#: spyder/plugins/configdialog.py:874
+#: spyder/plugins/configdialog.py:936
msgid "Animated toolbars and panes"
msgstr "Barras de herramientas y paneles animados"
-#: spyder/plugins/configdialog.py:876
+#: spyder/plugins/configdialog.py:938
msgid "Tear off menus"
msgstr "Separar los menús"
-#: spyder/plugins/configdialog.py:877
+#: spyder/plugins/configdialog.py:939
msgid "Set this to detach any
menu from the main window"
msgstr ""
"Establezca esta opción
si desea separar los menús de la ventana principal"
-#: spyder/plugins/configdialog.py:879
+#: spyder/plugins/configdialog.py:941
msgid "Custom margin for panes:"
msgstr "Márgenes personalizadas para los paneles:"
-#: spyder/plugins/configdialog.py:881
+#: spyder/plugins/configdialog.py:943
msgid "pixels"
msgstr "pixels"
-#: spyder/plugins/configdialog.py:888
+#: spyder/plugins/configdialog.py:950
msgid "Cursor blinking:"
msgstr "Parpadeo del cursor:"
-#: spyder/plugins/configdialog.py:890
+#: spyder/plugins/configdialog.py:952
msgid "ms"
msgstr "ms"
-#: spyder/plugins/configdialog.py:929
+#: spyder/plugins/configdialog.py:991
msgid "Status bar"
msgstr "Barra de estado"
-#: spyder/plugins/configdialog.py:930
+#: spyder/plugins/configdialog.py:992
msgid "Show status bar"
msgstr "Mostrar la barra de estatus"
-#: spyder/plugins/configdialog.py:932
+#: spyder/plugins/configdialog.py:994
msgid "Show memory usage every"
msgstr "Mostrar la memoria usada cada"
-#: spyder/plugins/configdialog.py:934 spyder/plugins/configdialog.py:943
+#: spyder/plugins/configdialog.py:996 spyder/plugins/configdialog.py:1005
#: spyder/plugins/editor.py:139 spyder/plugins/editor.py:283
msgid " ms"
-msgstr "ms"
+msgstr " ms"
-#: spyder/plugins/configdialog.py:941
+#: spyder/plugins/configdialog.py:1003
msgid "Show CPU usage every"
msgstr "Mostrar el uso de CPU cada"
-#: spyder/plugins/configdialog.py:974
+#: spyder/plugins/configdialog.py:1036
msgid "Screen resolution"
msgstr "Resolución de la pantalla"
-#: spyder/plugins/configdialog.py:976
+#: spyder/plugins/configdialog.py:1038
msgid ""
"Configuration for high DPI screens
Please see {0}"
"a><> for more information about these options (in English)."
@@ -1140,31 +1143,31 @@ msgstr ""
"href=\"{0}\">{0}<> para obtener más información sobre estas opciones (en "
"inglés)."
-#: spyder/plugins/configdialog.py:986
+#: spyder/plugins/configdialog.py:1048
msgid "Normal"
msgstr "Normal"
-#: spyder/plugins/configdialog.py:990
+#: spyder/plugins/configdialog.py:1052
msgid "Enable auto high DPI scaling"
msgstr "Activar el escalado para pantallas de alta resolución"
-#: spyder/plugins/configdialog.py:993
+#: spyder/plugins/configdialog.py:1055
msgid "Set this for high DPI displays"
msgstr ""
"Activar esta opción para escalar la interfaz \n"
"a pantallas de alta resolución"
-#: spyder/plugins/configdialog.py:997
+#: spyder/plugins/configdialog.py:1059
msgid "Set a custom high DPI scaling"
msgstr "Defina el valor del escalado para pantallas de alta resolución"
-#: spyder/plugins/configdialog.py:1000
+#: spyder/plugins/configdialog.py:1062
msgid "Set this for high DPI displays when auto scaling does not work"
msgstr ""
"Activar esta opción en pantallas de alta resolución cuando el auto-escalado "
"de la interfaz no funcione"
-#: spyder/plugins/configdialog.py:1006
+#: spyder/plugins/configdialog.py:1068
msgid ""
"Enter values for different screens separated by semicolons ';', float values "
"are supported"
@@ -1172,31 +1175,39 @@ msgstr ""
"Introduzca los valores para las diferentes pantallas separadas por punto y "
"coma ';', es posible utilizar tanto números reales como enteros"
-#: spyder/plugins/configdialog.py:1033
+#: spyder/plugins/configdialog.py:1095
msgid "Plain text font"
msgstr "Texto plano"
-#: spyder/plugins/configdialog.py:1039
+#: spyder/plugins/configdialog.py:1101
msgid "Rich text font"
msgstr "Texto enriquecido"
-#: spyder/plugins/configdialog.py:1042
+#: spyder/plugins/configdialog.py:1104
msgid "Fonts"
msgstr "Tipo de letra"
-#: spyder/plugins/configdialog.py:1056
+#: spyder/plugins/configdialog.py:1118
msgid "Appearance"
msgstr "Apariencia"
-#: spyder/plugins/configdialog.py:1058 spyder/plugins/ipythonconsole.py:579
+#: spyder/plugins/configdialog.py:1120 spyder/plugins/ipythonconsole.py:633
msgid "Advanced Settings"
msgstr "Opciones avanzadas"
-#: spyder/plugins/configdialog.py:1094
+#: spyder/plugins/configdialog.py:1155
+msgid ""
+"We're sorry but the following error occurred while trying to set your "
+"selected language:
{}"
+msgstr ""
+"Lo lamentamos pero ocurrió el siguiente error mientras se establecía el "
+"lenguaje seleccionado:
{}"
+
+#: spyder/plugins/configdialog.py:1164
msgid "Syntax coloring"
msgstr "Coloreado de sintaxis"
-#: spyder/plugins/configdialog.py:1107
+#: spyder/plugins/configdialog.py:1177
msgid ""
"Here you can select the color scheme used in the Editor and all other Spyder "
"plugins.
You can also edit the color schemes provided by Spyder or "
@@ -1207,52 +1218,52 @@ msgstr ""
"que vienen con Spyder o crear los suyos al usar las opciones que aparecen a "
"continuación.
"
-#: spyder/plugins/configdialog.py:1112
+#: spyder/plugins/configdialog.py:1182
msgid "Edit selected"
msgstr "Editar esquema"
-#: spyder/plugins/configdialog.py:1113
+#: spyder/plugins/configdialog.py:1183
msgid "Create new scheme"
msgstr "Crear nuevo esquema"
-#: spyder/plugins/configdialog.py:1114 spyder/widgets/explorer.py:583
+#: spyder/plugins/configdialog.py:1184 spyder/widgets/explorer.py:582
#: spyder/widgets/projects/explorer.py:243 spyder/widgets/shell.py:136
msgid "Delete"
msgstr "Eliminar"
-#: spyder/plugins/configdialog.py:1117
+#: spyder/plugins/configdialog.py:1187
msgid "Reset"
msgstr "Restaurar"
-#: spyder/plugins/configdialog.py:1124
+#: spyder/plugins/configdialog.py:1194
msgid "Scheme:"
msgstr "Esquema:"
-#: spyder/plugins/configdialog.py:1155
+#: spyder/plugins/configdialog.py:1225
msgid "Manage color schemes"
msgstr "Manejar esquemas de coloreado"
-#: spyder/plugins/configdialog.py:1346
+#: spyder/plugins/configdialog.py:1416
msgid "Are you sure you want to delete this scheme?"
msgstr "¿Está seguro de que borrar este esquema?"
-#: spyder/plugins/configdialog.py:1463
+#: spyder/plugins/configdialog.py:1533
msgid "Text"
msgstr "Texto"
-#: spyder/plugins/configdialog.py:1465
+#: spyder/plugins/configdialog.py:1535
msgid "Highlight"
msgstr "Resaltar"
-#: spyder/plugins/configdialog.py:1467
+#: spyder/plugins/configdialog.py:1537
msgid "Background"
msgstr "Fondo"
-#: spyder/plugins/configdialog.py:1471
+#: spyder/plugins/configdialog.py:1541
msgid "Scheme name:"
msgstr "Nombre del esquema:"
-#: spyder/plugins/configdialog.py:1478
+#: spyder/plugins/configdialog.py:1548
msgid "Color scheme editor"
msgstr "Editor de esquemas"
@@ -1278,7 +1289,7 @@ msgstr "Muestra y edita las variables de entorno (para la sesión actual)"
#: spyder/plugins/console.py:157
msgid "Show sys.path contents..."
-msgstr "Contenidos del sys.path"
+msgstr "Contenidos del sys.path..."
#: spyder/plugins/console.py:159
msgid "Show (read-only) sys.path"
@@ -1288,7 +1299,7 @@ msgstr "Muestra los contenidos del sys.path en modo lectura"
msgid "Buffer..."
msgstr "Mostrar líneas..."
-#: spyder/plugins/console.py:163 spyder/plugins/history.py:43
+#: spyder/plugins/console.py:163 spyder/plugins/history.py:45
msgid "Set maximum line count"
msgstr "Establece el máximo número de líneas a mostrar en la terminal"
@@ -1301,13 +1312,13 @@ msgid "Set external editor executable path"
msgstr "Establece la ruta del editor externo"
#: spyder/plugins/console.py:170 spyder/plugins/editor.py:149
-#: spyder/plugins/help.py:152 spyder/plugins/help.py:360
-#: spyder/plugins/history.py:46 spyder/plugins/history.py:157
+#: spyder/plugins/help.py:152 spyder/plugins/help.py:358
+#: spyder/plugins/history.py:48 spyder/plugins/history.py:159
msgid "Wrap lines"
msgstr "Ajuste de línea automático"
#: spyder/plugins/console.py:173 spyder/plugins/editor.py:185
-#: spyder/plugins/ipythonconsole.py:300
+#: spyder/plugins/ipythonconsole.py:311
msgid "Display balloon tips"
msgstr "Mostrar globos de sugerencias"
@@ -1327,7 +1338,7 @@ msgstr "Opciones"
msgid "Run Python script"
msgstr "Ejecutar archivo de Python"
-#: spyder/plugins/console.py:266 spyder/widgets/explorer.py:809
+#: spyder/plugins/console.py:266 spyder/widgets/explorer.py:811
msgid "Python scripts"
msgstr "Archivos de Python"
@@ -1360,8 +1371,8 @@ msgid "Show tab bar"
msgstr "Mostrar barra de pestañas"
#: spyder/plugins/editor.py:122 spyder/plugins/editor.py:199
-#: spyder/plugins/help.py:151 spyder/plugins/history.py:45
-#: spyder/plugins/ipythonconsole.py:332
+#: spyder/plugins/help.py:151 spyder/plugins/history.py:47
+#: spyder/plugins/ipythonconsole.py:349
msgid "Source code"
msgstr "Código fuente"
@@ -1456,7 +1467,7 @@ msgstr "Indentación automática después de 'else', 'elif', etc."
#: spyder/plugins/editor.py:210
msgid "Indentation characters: "
-msgstr "Caracteres de indentación:"
+msgstr "Caracteres de indentación: "
#: spyder/plugins/editor.py:211
msgid "2 spaces"
@@ -1602,8 +1613,8 @@ msgstr ""
msgid "Fix automatically and show warning message box"
msgstr "Arreglar automáticamente y mostrar un mensaje de advertencia"
-#: spyder/plugins/editor.py:357 spyder/plugins/ipythonconsole.py:573
-#: spyder/plugins/variableexplorer.py:35
+#: spyder/plugins/editor.py:357 spyder/plugins/ipythonconsole.py:627
+#: spyder/plugins/variableexplorer.py:47
msgid "Display"
msgstr "Visualización"
@@ -1617,10 +1628,10 @@ msgstr "Opciones avanzadas"
#: spyder/plugins/editor.py:644
msgid "&New file..."
-msgstr "&Nuevo"
+msgstr "&Nuevo archivo..."
-#: spyder/plugins/editor.py:645 spyder/widgets/explorer.py:786
-#: spyder/widgets/explorer.py:793
+#: spyder/plugins/editor.py:645 spyder/widgets/explorer.py:788
+#: spyder/widgets/explorer.py:795
msgid "New file"
msgstr "Nuevo archivo"
@@ -1634,10 +1645,10 @@ msgstr "Abrir el último archivo cerrado"
#: spyder/plugins/editor.py:661
msgid "&Open..."
-msgstr "&Abrir"
+msgstr "&Abrir..."
-#: spyder/plugins/editor.py:662 spyder/plugins/editor.py:1867
-#: spyder/plugins/editor.py:1873
+#: spyder/plugins/editor.py:662 spyder/plugins/editor.py:1881
+#: spyder/plugins/editor.py:1887
msgid "Open file"
msgstr "Abrir archivo"
@@ -1653,7 +1664,7 @@ msgstr "Restaurar archivo desde el disco"
msgid "&Save"
msgstr "&Guardar"
-#: spyder/plugins/editor.py:673 spyder/widgets/editor.py:1672
+#: spyder/plugins/editor.py:673 spyder/widgets/editor.py:1675
msgid "Save file"
msgstr "Guardar archivo"
@@ -1687,7 +1698,7 @@ msgstr "Presentación preliminar..."
#: spyder/plugins/editor.py:698
msgid "&Print..."
-msgstr "Im&primir"
+msgstr "Im&primir..."
#: spyder/plugins/editor.py:699
msgid "Print current file..."
@@ -1734,6 +1745,7 @@ msgid "Set/Edit conditional breakpoint"
msgstr "Añadir o editar un punto de interrupción condicional"
#: spyder/plugins/editor.py:755
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:180
msgid "Clear breakpoints in all files"
msgstr "Eliminar los puntos de interrupción de todos los archivos"
@@ -1777,8 +1789,8 @@ msgstr "Salir de la función/método"
msgid "Run until current function or method returns"
msgstr "Ejecutar hasta que la función o método actual termine"
-#: spyder/plugins/editor.py:796 spyder/widgets/findinfiles.py:438
-#: spyder/widgets/ipythonconsole/client.py:354
+#: spyder/plugins/editor.py:796 spyder/widgets/findinfiles.py:450
+#: spyder/widgets/ipythonconsole/client.py:393
msgid "Stop"
msgstr "Detener"
@@ -1795,6 +1807,7 @@ msgid "&Configuration per file..."
msgstr "&Configuración por archivo..."
#: spyder/plugins/editor.py:811
+#: spyder/widgets/externalshell/pythonshell.py:309
msgid "Run settings"
msgstr "Ajustes de ejecución"
@@ -1806,7 +1819,7 @@ msgstr "Ejecutar de &nuevo el último archivo"
msgid "Run again last file"
msgstr "Ejecutar de nuevo el mismo archivo"
-#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2720
+#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2727
msgid "Run &selection or current line"
msgstr "Ejecutar la &selección o la línea actual"
@@ -1814,7 +1827,7 @@ msgstr "Ejecutar la &selección o la línea actual"
msgid "Run selection or current line"
msgstr "Ejecutar la &selección o línea actual"
-#: spyder/plugins/editor.py:836 spyder/widgets/sourcecode/codeeditor.py:2708
+#: spyder/plugins/editor.py:836 spyder/widgets/sourcecode/codeeditor.py:2715
msgid "Run cell"
msgstr "Ejecutar la celda"
@@ -1826,7 +1839,7 @@ msgstr ""
"Ejecutar la celda actual (Ctrl+Enter)\n"
"[Usar #%% para crear celdas]"
-#: spyder/plugins/editor.py:845 spyder/widgets/sourcecode/codeeditor.py:2712
+#: spyder/plugins/editor.py:845 spyder/widgets/sourcecode/codeeditor.py:2719
msgid "Run cell and advance"
msgstr "Ejecutar la celda y avanzar"
@@ -1834,7 +1847,7 @@ msgstr "Ejecutar la celda y avanzar"
msgid "Run current cell and go to the next one (Shift+Enter)"
msgstr "Ejecutar la celda actual y avanzar a la siguiente (Shift+Enter)"
-#: spyder/plugins/editor.py:854 spyder/widgets/sourcecode/codeeditor.py:2716
+#: spyder/plugins/editor.py:854 spyder/widgets/sourcecode/codeeditor.py:2723
msgid "Re-run last cell"
msgstr "Ejecutar de nuevo la última celda"
@@ -1911,11 +1924,11 @@ msgstr "Siguiente posición del cursor"
msgid "Go to next cursor position"
msgstr "Ir a la siguiente posición del cursor"
-#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Comment"
msgstr "Comentar"
-#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Uncomment"
msgstr "Descomentar"
@@ -2024,8 +2037,8 @@ msgstr "Máximo número de archivos recientes..."
msgid "Clear recent files list"
msgstr "Limpiar la lista de archivos recientes"
-#: spyder/plugins/editor.py:1009 spyder/plugins/projects.py:107
-#: spyder/widgets/findinfiles.py:246
+#: spyder/plugins/editor.py:1009 spyder/plugins/projects.py:101
+#: spyder/widgets/findinfiles.py:261
msgid "Clear this list"
msgstr "Limpiar esta lista"
@@ -2033,39 +2046,39 @@ msgstr "Limpiar esta lista"
msgid "Open &recent"
msgstr "Abrir &reciente"
-#: spyder/plugins/editor.py:1675
+#: spyder/plugins/editor.py:1674
msgid "Spyder Editor"
msgstr "Editor de Spyder"
-#: spyder/plugins/editor.py:1676
+#: spyder/plugins/editor.py:1675
msgid "This is a temporary script file."
-msgstr "Este es un archivo temporal"
+msgstr "Este es un archivo temporal."
-#: spyder/plugins/editor.py:1745
+#: spyder/plugins/editor.py:1758
msgid "untitled"
-msgstr "Sin título "
+msgstr "Sin título"
-#: spyder/plugins/editor.py:1817
+#: spyder/plugins/editor.py:1831
msgid "Maximum number of recent files"
msgstr "Máximo número de archivos recientes"
-#: spyder/plugins/editor.py:1963
+#: spyder/plugins/editor.py:1977
msgid "Printing..."
msgstr "Imprimir..."
-#: spyder/plugins/explorer.py:54
+#: spyder/plugins/explorer.py:55
msgid "File explorer"
msgstr "Explorador de archivos"
-#: spyder/plugins/findinfiles.py:120 spyder/widgets/findinfiles.py:913
+#: spyder/plugins/findinfiles.py:117 spyder/widgets/findinfiles.py:949
msgid "Find in files"
msgstr "Buscar en archivos"
-#: spyder/plugins/findinfiles.py:145
+#: spyder/plugins/findinfiles.py:141
msgid "&Find in files"
msgstr "Bus&car en archivos"
-#: spyder/plugins/findinfiles.py:150
+#: spyder/plugins/findinfiles.py:146
msgid "Search text in multiple files"
msgstr "Buscar en varios archivos a la vez"
@@ -2119,47 +2132,48 @@ msgstr "Sphinx %s está instalado actualmente."
msgid "No further documentation available"
msgstr "No existe más documentación disponible"
-#: spyder/plugins/help.py:307 spyder/plugins/help.py:347
+#: spyder/plugins/help.py:307 spyder/plugins/help.py:345
msgid "No documentation available"
msgstr "No existe documentación disponible"
-#: spyder/plugins/help.py:378
+#: spyder/plugins/help.py:376
msgid "Source"
msgstr "Origen"
-#: spyder/plugins/help.py:385 spyder/plugins/runconfig.py:170
-#: spyder/plugins/runconfig.py:486 spyder/widgets/ipythonconsole/client.py:288
+#: spyder/plugins/help.py:383 spyder/plugins/runconfig.py:170
+#: spyder/plugins/runconfig.py:486 spyder/widgets/ipythonconsole/client.py:327
+#: spyder/widgets/externalshell/baseshell.py:94
msgid "Console"
msgstr "Terminal"
-#: spyder/plugins/help.py:393
+#: spyder/plugins/help.py:391
msgid "Object"
msgstr "Objeto"
-#: spyder/plugins/help.py:407
+#: spyder/plugins/help.py:405
msgid "Plain Text"
msgstr "Texto plano"
-#: spyder/plugins/help.py:411
+#: spyder/plugins/help.py:409
msgid "Show Source"
msgstr "Mostrar código fuente"
-#: spyder/plugins/help.py:415
+#: spyder/plugins/help.py:413
msgid "Rich Text"
msgstr "Texto enriquecido"
-#: spyder/plugins/help.py:425
+#: spyder/plugins/help.py:423
msgid "Automatic import"
msgstr "Importar automáticamente"
-#: spyder/plugins/help.py:437 spyder/plugins/history.py:106
-#: spyder/widgets/editor.py:728 spyder/widgets/explorer.py:1200
-#: spyder/widgets/ipythonconsole/client.py:378
-#: spyder/widgets/variableexplorer/namespacebrowser.py:148
+#: spyder/plugins/help.py:435 spyder/plugins/history.py:108
+#: spyder/widgets/editor.py:738 spyder/widgets/explorer.py:1205
+#: spyder/widgets/ipythonconsole/client.py:417
+#: spyder/widgets/variableexplorer/namespacebrowser.py:151
msgid "Options"
msgstr "Opciones"
-#: spyder/plugins/help.py:696
+#: spyder/plugins/help.py:692
msgid ""
"Here you can get help of any object by pressing %s in front of it, either on "
"the Editor or the Console.%sHelp can also be shown automatically after "
@@ -2171,38 +2185,38 @@ msgstr ""
"ayuda también se puede mostrar automáticamente después de escribir un "
"paréntesis junto a un objeto. Este comportamiento puede activarse en %s."
-#: spyder/plugins/help.py:702
+#: spyder/plugins/help.py:698
msgid "Preferences > Help"
msgstr "Preferencias > Ayuda"
-#: spyder/plugins/help.py:709
+#: spyder/plugins/help.py:705
msgid "Usage"
msgstr "Uso"
-#: spyder/plugins/help.py:710
+#: spyder/plugins/help.py:706
msgid "New to Spyder? Read our"
msgstr "Nuevo en Spyder? Lee nuestro"
-#: spyder/plugins/help.py:711
+#: spyder/plugins/help.py:707
msgid "tutorial"
msgstr "tutorial"
-#: spyder/plugins/help.py:718
+#: spyder/plugins/help.py:714
msgid ""
"Please consider installing Sphinx to get documentation rendered in rich text."
msgstr ""
"Por favor considere instalar Sphinx para obtener la documentación en texto "
-"enriquecido "
+"enriquecido."
-#: spyder/plugins/help.py:891
+#: spyder/plugins/help.py:885
msgid "Lock"
msgstr "Bloquear"
-#: spyder/plugins/help.py:891
+#: spyder/plugins/help.py:885
msgid "Unlock"
msgstr "Desbloquear"
-#: spyder/plugins/help.py:938
+#: spyder/plugins/help.py:932
msgid ""
"The following error occured when calling Sphinx %s.
Incompatible "
"Sphinx version or doc string decoding failed.
Error message:
%s"
@@ -2211,63 +2225,68 @@ msgstr ""
"
Ello se debe a una versión incompatible de Sphinx o bien a que no fue "
"posible leer la documentación solicitada.
Mensaje de error:
%s"
-#: spyder/plugins/help.py:982
+#: spyder/plugins/help.py:976
msgid "No source code available."
-msgstr "No está disponible el código fuente"
+msgstr "No está disponible el código fuente."
-#: spyder/plugins/history.py:39
+#: spyder/plugins/history.py:41
msgid "Settings"
msgstr "Ajustes"
-#: spyder/plugins/history.py:41
+#: spyder/plugins/history.py:43
msgid " entries"
-msgstr "entradas"
+msgstr " entradas"
-#: spyder/plugins/history.py:41
+#: spyder/plugins/history.py:43
msgid "History depth: "
-msgstr "Longitud del historial"
+msgstr "Longitud del historial: "
-#: spyder/plugins/history.py:48
+#: spyder/plugins/history.py:50
msgid "Scroll automatically to last entry"
msgstr "Desplazarse automáticamente a la última entrada"
-#: spyder/plugins/history.py:126
+#: spyder/plugins/history.py:128
msgid "History log"
msgstr "Historial de comandos"
-#: spyder/plugins/history.py:153
+#: spyder/plugins/history.py:155
msgid "History..."
msgstr "Historial..."
-#: spyder/plugins/history.py:155
+#: spyder/plugins/history.py:157
msgid "Set history maximum entries"
msgstr "Establece el máximo número de entradas a almacenar"
-#: spyder/plugins/history.py:260
+#: spyder/plugins/history.py:268
+#: spyder/plugins/pylint/plugin.py:160
msgid "History"
msgstr "Historial"
-#: spyder/plugins/history.py:261
+#: spyder/plugins/history.py:269
msgid "Maximum entries"
msgstr "Máximo número de entradas"
-#: spyder/plugins/ipythonconsole.py:65
+#: spyder/plugins/ipythonconsole.py:64
msgid "Symbolic mathematics in the IPython Console"
msgstr "Matemática simbólica en la terminal de IPython"
-#: spyder/plugins/ipythonconsole.py:69
+#: spyder/plugins/ipythonconsole.py:68
msgid "Run Cython files in the IPython Console"
msgstr "Ejecute archivos de Cython en la terminal de IPython"
-#: spyder/plugins/ipythonconsole.py:73
+#: spyder/plugins/ipythonconsole.py:72
msgid "Integrate the IPython console"
msgstr "Integración con la Terminal de IPython"
-#: spyder/plugins/ipythonconsole.py:77
+#: spyder/plugins/ipythonconsole.py:76
msgid "IPython interactive python environment"
msgstr "Entorno interactivo IPython"
-#: spyder/plugins/ipythonconsole.py:128
+#: spyder/plugins/ipythonconsole.py:80
+msgid "Display 2D graphics in the IPython Console"
+msgstr "Mostrar gráficas 2D en la terminal de IPython"
+
+#: spyder/plugins/ipythonconsole.py:131
msgid ""
"The authenticity of host %s can't be established. Are you sure you "
"want to continue connecting?"
@@ -2275,92 +2294,102 @@ msgstr ""
"La autenticidad del servidor %s no puede ser establecida. ¿Está "
"seguro de que desea continuar conectándose?"
-#: spyder/plugins/ipythonconsole.py:140
+#: spyder/plugins/ipythonconsole.py:143
msgid "The authenticity of the host can't be established"
msgstr "La autenticidad del servidor no puede ser establecida"
-#: spyder/plugins/ipythonconsole.py:147
+#: spyder/plugins/ipythonconsole.py:150
msgid "Tunnel '%s' failed to start"
msgstr "El túnel '%s' falló en ser iniciado"
-#: spyder/plugins/ipythonconsole.py:152
+#: spyder/plugins/ipythonconsole.py:155
msgid "Could not connect to remote host"
msgstr "No fue posible conectarse al servidor remoto"
-#: spyder/plugins/ipythonconsole.py:169 spyder/plugins/ipythonconsole.py:799
+#: spyder/plugins/ipythonconsole.py:172 spyder/plugins/ipythonconsole.py:846
msgid "Connect to an existing kernel"
msgstr "Conectarse a un núcleo existente"
-#: spyder/plugins/ipythonconsole.py:171
+#: spyder/plugins/ipythonconsole.py:174
msgid ""
-"Please enter the connection info of the kernel you want to connect to. For "
-"that you can either select its JSON connection file using the Browse"
-"tt> button, or write directly its id, in case it's a local kernel (for "
-"example kernel-3764.json or just 3764)."
-msgstr ""
-"Por favor introduzca la información de conexión del núcleo al cual desea "
-"conectarse. Para ello puede seleccionar su archivo de conexión JSON, usando "
-"el botón Seleccionar, o escribir directamente su id, en caso de que "
-"sea un núcleo local (por ejemplo, kernel-3764.json o sólo 3764"
-"tt>)"
-
-#: spyder/plugins/ipythonconsole.py:182
-msgid "Connection info:"
-msgstr "Información de conexión:"
-
-#: spyder/plugins/ipythonconsole.py:184
-msgid "Path to connection file or kernel id"
-msgstr "Ruta al archivo de conexión o id del núcleo"
-
-#: spyder/plugins/ipythonconsole.py:186 spyder/plugins/ipythonconsole.py:203
+"Please select the JSON connection file (e.g. kernel-3764.json"
+"tt>) or enter the 4-digit ID (e.g. 3764) of the existing "
+"kernel to connect to, and enter the SSH host name and credentials if a "
+"remote kernel."
+msgstr ""
+"Por favor seleccione el archivo de conexión JSON (e.g. "
+"kernel-3764.json) o introduzca la identificación de 4 dígitos (e."
+"g. 3764) de un núcleo existente al cual conectarse, e "
+"introduzca el nombre del servidor SSH y sus respectivas credenciales, en "
+"caso de tratarse de un núcleo remoto."
+
+#: spyder/plugins/ipythonconsole.py:183
+msgid "Kernel ID/Connection file:"
+msgstr "ID del núcleo o archivo de conexión:"
+
+#: spyder/plugins/ipythonconsole.py:185
+msgid "ID number or path to connection file"
+msgstr "Número de ID o ruta al archivo de conexión"
+
+#: spyder/plugins/ipythonconsole.py:187 spyder/plugins/ipythonconsole.py:216
msgid "Browse"
msgstr "Seleccionar"
-#: spyder/plugins/ipythonconsole.py:195
-msgid "This is a remote kernel"
-msgstr "Este es un núcleo remoto"
+#: spyder/plugins/ipythonconsole.py:196
+msgid "This is a remote kernel (via SSH)"
+msgstr "Este es un núcleo remoto (via SSH)"
#: spyder/plugins/ipythonconsole.py:199
+msgid ""
+"Note: If connecting to a remote kernel, only the SSH keyfile or"
+"i> the Password field need to be completed, unless the keyfile is protected "
+"with a passphrase."
+msgstr ""
+"Nota: Si está conectándose a un núcleo remoto, sólo necesita "
+"introducir el archivo clave SSH o la contraseña, a menos que el "
+"archivo clave esté protegido con una frase de contraseña."
+
+#: spyder/plugins/ipythonconsole.py:207
msgid "username@hostname:port"
msgstr "usuario@servidor:puerto"
-#: spyder/plugins/ipythonconsole.py:202
-msgid "Path to ssh key file"
-msgstr "Ruta al archivo de clave ssh"
-
-#: spyder/plugins/ipythonconsole.py:211
-msgid "Password or ssh key passphrase"
-msgstr "Contraseña o frase de contraseña de la clave ssh"
+#: spyder/plugins/ipythonconsole.py:210
+msgid "Remote user password or SSH keyfile passphrase"
+msgstr "Contraseña del usuario remoto o frase de contraseña de la clave SSH"
#: spyder/plugins/ipythonconsole.py:215
-msgid "Host name"
-msgstr "Servidor"
+msgid "Path to SSH keyfile (optional)"
+msgstr "Ruta al archivo de clave SSH (opcional)"
-#: spyder/plugins/ipythonconsole.py:216
-msgid "Ssh key"
-msgstr "Clave ssh"
+#: spyder/plugins/ipythonconsole.py:224
+msgid "Host name:"
+msgstr "Servidor:"
-#: spyder/plugins/ipythonconsole.py:217
-msgid "Password"
-msgstr "Contraseña"
+#: spyder/plugins/ipythonconsole.py:225
+msgid "Password:"
+msgstr "Contraseña:"
-#: spyder/plugins/ipythonconsole.py:246
-msgid "Open connection file"
-msgstr "Abrir un archivo de conexión"
+#: spyder/plugins/ipythonconsole.py:226
+msgid "SSH keyfile:"
+msgstr "Archivos clave de SSH:"
-#: spyder/plugins/ipythonconsole.py:251
-msgid "Select ssh key"
-msgstr "Seleccionar clave ssh"
+#: spyder/plugins/ipythonconsole.py:257
+msgid "Select kernel connection file"
+msgstr "Seleccionar un archivo de conexión"
-#: spyder/plugins/ipythonconsole.py:284 spyder/plugins/ipythonconsole.py:734
+#: spyder/plugins/ipythonconsole.py:262
+msgid "Select SSH keyfile"
+msgstr "Seleccionar un archivo de clave SSH"
+
+#: spyder/plugins/ipythonconsole.py:295 spyder/plugins/ipythonconsole.py:780
msgid "IPython console"
msgstr "Terminal de IPython"
-#: spyder/plugins/ipythonconsole.py:291
+#: spyder/plugins/ipythonconsole.py:302
msgid "Display initial banner"
msgstr "Mostrar el banner inicial"
-#: spyder/plugins/ipythonconsole.py:292
+#: spyder/plugins/ipythonconsole.py:303
msgid ""
"This option lets you hide the message shown at\n"
"the top of the console when it's opened."
@@ -2369,29 +2398,29 @@ msgstr ""
"aparece al principio de la terminal cuando se abre\n"
"por primera vez."
-#: spyder/plugins/ipythonconsole.py:294
+#: spyder/plugins/ipythonconsole.py:305
msgid "Use a pager to display additional text inside the console"
msgstr "Usar un paginador para mostrar textos dentro de la terminal"
-#: spyder/plugins/ipythonconsole.py:296
+#: spyder/plugins/ipythonconsole.py:307
msgid ""
"Useful if you don't want to fill the console with long help or completion "
"texts.\n"
"Note: Use the Q key to get out of the pager."
msgstr ""
"Es útil si no desea llenar la terminal con largos textos de ayuda.\n"
-"Nota: Debe usar la tecla Q para salir del paginador"
+"Nota: Debe usar la tecla Q para salir del paginador."
-#: spyder/plugins/ipythonconsole.py:301
+#: spyder/plugins/ipythonconsole.py:312
msgid "Ask for confirmation before closing"
msgstr "Mostrar un diálogo de confirmación antes de cerrar una terminal"
-#: spyder/plugins/ipythonconsole.py:304
+#: spyder/plugins/ipythonconsole.py:315
msgid "Ask for confirmation before removing all user-defined variables"
msgstr ""
"Preguntar antes de eliminar todas las variables definidas por el usuario"
-#: spyder/plugins/ipythonconsole.py:307
+#: spyder/plugins/ipythonconsole.py:318
msgid ""
"This option lets you hide the warning message shown\n"
"when resetting the namespace from Spyder."
@@ -2400,44 +2429,57 @@ msgstr ""
"aparece cuando se van a eliminar todas las \n"
"variables definidas por el usuario."
-#: spyder/plugins/ipythonconsole.py:309
-#: spyder/widgets/ipythonconsole/client.py:317
+#: spyder/plugins/ipythonconsole.py:320
+#: spyder/widgets/ipythonconsole/client.py:356
msgid "Show elapsed time"
msgstr "Mostrar el tiempo transcurrido"
-#: spyder/plugins/ipythonconsole.py:320
+#: spyder/plugins/ipythonconsole.py:322
+msgid "Ask for confirmation before restarting"
+msgstr "Pedir confirmación antes de reiniciar"
+
+#: spyder/plugins/ipythonconsole.py:324
+msgid ""
+"This option lets you hide the warning message shown\n"
+"when restarting the kernel."
+msgstr ""
+"Esta opción le permite ocultar el mensaje de \n"
+"advertencia que se muestra cuando se va a \n"
+"reiniciar el núcleo."
+
+#: spyder/plugins/ipythonconsole.py:337
msgid "Completion Type"
msgstr "Tipo de completado"
-#: spyder/plugins/ipythonconsole.py:321
+#: spyder/plugins/ipythonconsole.py:338
msgid "Decide what type of completion to use"
msgstr "Decidir que tipo de completado utilizar"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Graphical"
msgstr "Gráfico"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Plain"
msgstr "Plano"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Terminal"
msgstr "Terminal"
-#: spyder/plugins/ipythonconsole.py:324
+#: spyder/plugins/ipythonconsole.py:341
msgid "Completion:"
msgstr "Completado:"
-#: spyder/plugins/ipythonconsole.py:334
+#: spyder/plugins/ipythonconsole.py:351
msgid " lines"
-msgstr "líneas"
+msgstr " líneas"
-#: spyder/plugins/ipythonconsole.py:334
+#: spyder/plugins/ipythonconsole.py:351
msgid "Buffer: "
-msgstr "Mostrar"
+msgstr "Mostrar: "
-#: spyder/plugins/ipythonconsole.py:336
+#: spyder/plugins/ipythonconsole.py:353
msgid ""
"Set the maximum number of lines of text shown in the\n"
"console before truncation. Specifying -1 disables it\n"
@@ -2447,19 +2489,19 @@ msgstr ""
"en la terminal en cualquier momento. Si se introduce -1 se\n"
"mostrarán todas las líneas (no se recomienda!)"
-#: spyder/plugins/ipythonconsole.py:345
+#: spyder/plugins/ipythonconsole.py:362
msgid "Support for graphics (Matplotlib)"
msgstr "Soporte para crear gráficas (Matplotlib)"
-#: spyder/plugins/ipythonconsole.py:346
+#: spyder/plugins/ipythonconsole.py:363
msgid "Activate support"
msgstr "Activar el soporte"
-#: spyder/plugins/ipythonconsole.py:347
+#: spyder/plugins/ipythonconsole.py:364
msgid "Automatically load Pylab and NumPy modules"
msgstr "Cargar automáticamente los módulos de Pylab y NumPy"
-#: spyder/plugins/ipythonconsole.py:350
+#: spyder/plugins/ipythonconsole.py:367
msgid ""
"This lets you load graphics support without importing \n"
"the commands to do plots. Useful to work with other\n"
@@ -2471,19 +2513,19 @@ msgstr ""
"otras librerías gráficas diferentes a Matplotlib o para\n"
"desarrollar interfaces gráficas con Spyder."
-#: spyder/plugins/ipythonconsole.py:365
+#: spyder/plugins/ipythonconsole.py:382
msgid "Inline"
msgstr "En línea"
-#: spyder/plugins/ipythonconsole.py:366
+#: spyder/plugins/ipythonconsole.py:383
msgid "Automatic"
msgstr "Automático"
-#: spyder/plugins/ipythonconsole.py:367
+#: spyder/plugins/ipythonconsole.py:384
msgid "Graphics backend"
-msgstr "Salida gráfica:"
+msgstr "Salida gráfica"
-#: spyder/plugins/ipythonconsole.py:368
+#: spyder/plugins/ipythonconsole.py:385
msgid ""
"Decide how graphics are going to be displayed in the console. If unsure, "
"please select %s to put graphics inside the console or %s to "
@@ -2494,60 +2536,78 @@ msgstr ""
"%s para interactuar con ellas (a través de acercamientos y paneos) en "
"una ventana aparte."
-#: spyder/plugins/ipythonconsole.py:388
+#: spyder/plugins/ipythonconsole.py:405
msgid "Backend:"
msgstr "Salida:"
-#: spyder/plugins/ipythonconsole.py:390
+#: spyder/plugins/ipythonconsole.py:407
msgid "This option will be applied the next time a console is opened."
msgstr "Esta opción será aplicada la próxima vez que una terminal sea abierta."
-#: spyder/plugins/ipythonconsole.py:401
+#: spyder/plugins/ipythonconsole.py:418
msgid "Inline backend"
-msgstr "Salida en línea:"
+msgstr "Salida en línea"
-#: spyder/plugins/ipythonconsole.py:402
+#: spyder/plugins/ipythonconsole.py:419
msgid "Decide how to render the figures created by this backend"
msgstr ""
"Decida como renderizar las figuras creadas por este tipo de salida gráfica"
-#: spyder/plugins/ipythonconsole.py:406
+#: spyder/plugins/ipythonconsole.py:423
msgid "Format:"
msgstr "Formato:"
-#: spyder/plugins/ipythonconsole.py:409
+#: spyder/plugins/ipythonconsole.py:427
msgid "Resolution:"
msgstr "Resolución:"
-#: spyder/plugins/ipythonconsole.py:409
+#: spyder/plugins/ipythonconsole.py:427
msgid "dpi"
msgstr "dpi"
-#: spyder/plugins/ipythonconsole.py:411
+#: spyder/plugins/ipythonconsole.py:429
msgid "Only used when the format is PNG. Default is 72"
-msgstr "Sólo se usa cuando el formato es PNG. Por defecto es 72."
+msgstr "Sólo se usa cuando el formato es PNG. Por defecto es 72"
-#: spyder/plugins/ipythonconsole.py:414
+#: spyder/plugins/ipythonconsole.py:432
msgid "Width:"
msgstr "Ancho:"
-#: spyder/plugins/ipythonconsole.py:414 spyder/plugins/ipythonconsole.py:418
+#: spyder/plugins/ipythonconsole.py:432 spyder/plugins/ipythonconsole.py:436
msgid "inches"
msgstr "pulgadas"
-#: spyder/plugins/ipythonconsole.py:416
+#: spyder/plugins/ipythonconsole.py:434
msgid "Default is 6"
msgstr "Por defecto es 6"
-#: spyder/plugins/ipythonconsole.py:418
+#: spyder/plugins/ipythonconsole.py:436
msgid "Height:"
msgstr "Alto:"
-#: spyder/plugins/ipythonconsole.py:420
+#: spyder/plugins/ipythonconsole.py:438
msgid "Default is 4"
msgstr "Por defecto es 4"
-#: spyder/plugins/ipythonconsole.py:447
+#: spyder/plugins/ipythonconsole.py:440
+msgid "Use a tight layout for inline plots"
+msgstr "Usar una disposición ajustada ('tight') para los gráficos en línea"
+
+#: spyder/plugins/ipythonconsole.py:442
+msgid ""
+"Sets bbox_inches to \"tight\" when\n"
+"plotting inline with matplotlib.\n"
+"When enabled, can cause discrepancies\n"
+"between the image displayed inline and\n"
+"that created using savefig."
+msgstr ""
+"Establece el valor de bbox_inches en \"tight\" cuando\n"
+"se generan gráficos en línea con Matplotlib.\n"
+"Al estar activado puede causar discrepancias\n"
+"entre la imagen mostrada entre la imagen mostrada\n"
+"en línea y la que se crea usando savefig."
+
+#: spyder/plugins/ipythonconsole.py:475
msgid ""
"You can run several lines of code when a console is started. Please "
"introduce each one separated by commas, for example:
import os, import "
@@ -2557,15 +2617,15 @@ msgstr ""
"introduzca cada una separada por comas, por ejemplo:
import os, import "
"sys"
-#: spyder/plugins/ipythonconsole.py:453
+#: spyder/plugins/ipythonconsole.py:481
msgid "Lines:"
msgstr "Líneas:"
-#: spyder/plugins/ipythonconsole.py:462
+#: spyder/plugins/ipythonconsole.py:490
msgid "Run a file"
msgstr "Ejecutar un archivo"
-#: spyder/plugins/ipythonconsole.py:463
+#: spyder/plugins/ipythonconsole.py:491
msgid ""
"You can also run a whole file at startup instead of just some lines (This is "
"similar to have a PYTHONSTARTUP file)."
@@ -2573,35 +2633,60 @@ msgstr ""
"También se puede ejecutar un archivo completo al inicio, en lugar de unas "
"pocas líneas (Esto es similar a tener un archivo PYTHONSTARTUP)."
-#: spyder/plugins/ipythonconsole.py:467
+#: spyder/plugins/ipythonconsole.py:495
msgid "Use the following file:"
msgstr "Usar el siguiente archivo:"
-#: spyder/plugins/ipythonconsole.py:481
+#: spyder/plugins/ipythonconsole.py:509
+msgid "Jedi completion"
+msgstr "Completado con Jedi"
+
+#: spyder/plugins/ipythonconsole.py:510
+msgid ""
+"Enable Jedi-based Tab completion in the IPython console; similar to "
+"the greedy completer, but without evaluating the code.
Warning: "
+"Slows down your console when working with large dataframes!"
+msgstr ""
+"Activa el completado basado en Jedi en la terminal de IPython. Este "
+"completado es similar al completado ambicioso, pero sin evaluar el código."
+"
Advertencia: Esta opción ralentiza las operaciones en la terminal "
+"cuando se está trabajando con dataframes muy grandes!"
+
+#: spyder/plugins/ipythonconsole.py:517
+msgid "Use Jedi completion in the IPython console"
+msgstr "Usar el completado con Jedi en la terminal de IPython"
+
+#: spyder/plugins/ipythonconsole.py:530
msgid "Greedy completion"
msgstr "Completado ambicioso"
-#: spyder/plugins/ipythonconsole.py:482
+#: spyder/plugins/ipythonconsole.py:531
msgid ""
"Enable Tab completion on elements of lists, results of function "
-"calls, etc, without assigning them to a variable.
For example, you "
-"can get completions on things like li[0].<Tab> or ins."
-"meth().<Tab>"
+"calls, etc, without assigning them to a variable, like li[0].<"
+"Tab> or ins.meth().<Tab>
Warning: Due to a "
+"bug, IPython's greedy completer requires a leading <Space> "
+"for some completions; e.g. np.sin(<Space>np.<Tab> "
+"works while np.sin(np.<Tab> doesn't."
msgstr ""
"Habilita el completado usando la tecla Tab en elementos de listas, "
"resultados de llamadas de funciones, etc, sin asignarlos a una "
"variable.
De esta forma se pueden obtener sugerencias de completado en "
-"cosas como li[0].<Tab> o ins.meth().<Tab>"
+"expresiones como li[0].<Tab> o ins.meth().<Tab>"
+"tt>
Advertencia: Debido a un error, el completado ambicioso de "
+"IPython requiere de un <Espacio> inicial en algunas "
+"expresiones; por ejemplo, np.sin(<Espacio>np.<Tab> "
+"funciona, mientras que np.sin(np.<Tab> no."
-#: spyder/plugins/ipythonconsole.py:490
-msgid "Use the greedy completer"
-msgstr "Usar el completado ambicioso"
+#: spyder/plugins/ipythonconsole.py:543
+msgid "Use greedy completion in the IPython console"
+msgstr "Usar el completado ambicioso en la Terminal de IPython"
-#: spyder/plugins/ipythonconsole.py:501
+#: spyder/plugins/ipythonconsole.py:555
msgid "Autocall"
msgstr "Autollamar"
-#: spyder/plugins/ipythonconsole.py:502
+#: spyder/plugins/ipythonconsole.py:556
msgid ""
"Autocall makes IPython automatically call any callable object even if you "
"didn't type explicit parentheses.
For example, if you type str 43 "
@@ -2612,23 +2697,23 @@ msgstr ""
"
Por ejemplo, al escribir str 43, se convertirá automáticamente en "
"str(43)."
-#: spyder/plugins/ipythonconsole.py:509
+#: spyder/plugins/ipythonconsole.py:563
msgid "Smart"
msgstr "Inteligente"
-#: spyder/plugins/ipythonconsole.py:510
+#: spyder/plugins/ipythonconsole.py:564
msgid "Full"
msgstr "Total"
-#: spyder/plugins/ipythonconsole.py:511
+#: spyder/plugins/ipythonconsole.py:565
msgid "Off"
msgstr "Desactivado"
-#: spyder/plugins/ipythonconsole.py:513
+#: spyder/plugins/ipythonconsole.py:567
msgid "Autocall: "
-msgstr "Autollamar:"
+msgstr "Autollamar: "
-#: spyder/plugins/ipythonconsole.py:514
+#: spyder/plugins/ipythonconsole.py:568
msgid ""
"On %s mode, Autocall is not applied if there are no arguments after "
"the callable. On %s mode, all callable objects are automatically "
@@ -2638,11 +2723,11 @@ msgstr ""
"objeto llamable. En modo %s, todos los objetos llamables son llamados "
"automáticamente (aún si no hay argumentos presentes)."
-#: spyder/plugins/ipythonconsole.py:526
+#: spyder/plugins/ipythonconsole.py:580
msgid "Symbolic Mathematics"
msgstr "Matemática simbólica"
-#: spyder/plugins/ipythonconsole.py:527
+#: spyder/plugins/ipythonconsole.py:581
msgid ""
"Perfom symbolic operations in the console (e.g. integrals, derivatives, "
"vector calculus, etc) and get the outputs in a beautifully printed style (it "
@@ -2652,11 +2737,11 @@ msgstr ""
"cálculo vectorial) y obtenga los resultados en un bello estilo impreso "
"(requiere el módulo Sympy)."
-#: spyder/plugins/ipythonconsole.py:532
+#: spyder/plugins/ipythonconsole.py:586
msgid "Use symbolic math"
msgstr "Usar matemática simbólica"
-#: spyder/plugins/ipythonconsole.py:533
+#: spyder/plugins/ipythonconsole.py:587
msgid ""
"This option loads the Sympy library to work with.
Please refer to its "
"documentation to learn how to use it."
@@ -2664,46 +2749,46 @@ msgstr ""
"Esta opción carga la librería Sympy para trabajar
con ella. Por favor lea "
"su documentación para aprender como usarla."
-#: spyder/plugins/ipythonconsole.py:543
+#: spyder/plugins/ipythonconsole.py:597
msgid "Prompts"
msgstr "Prompts"
-#: spyder/plugins/ipythonconsole.py:544
+#: spyder/plugins/ipythonconsole.py:598
msgid "Modify how Input and Output prompts are shown in the console."
msgstr ""
"Modifique como se muestran los prompts de entrada y salida en la terminal."
-#: spyder/plugins/ipythonconsole.py:547
+#: spyder/plugins/ipythonconsole.py:601
msgid "Input prompt:"
msgstr "Prompt de entrada:"
-#: spyder/plugins/ipythonconsole.py:549
+#: spyder/plugins/ipythonconsole.py:603
msgid ""
"Default is
In [<span class=\"in-prompt-number\">%i</span>]:"
msgstr ""
"Por defecto es
In [<span class=\"in-prompt-number\">%i</"
"span>]:"
-#: spyder/plugins/ipythonconsole.py:553
+#: spyder/plugins/ipythonconsole.py:607
msgid "Output prompt:"
msgstr "Prompt de salida:"
-#: spyder/plugins/ipythonconsole.py:555
+#: spyder/plugins/ipythonconsole.py:609
msgid ""
"Default is
Out[<span class=\"out-prompt-number\">%i</span>]:"
msgstr ""
"Por defecto es
Out[<span class=\"out-prompt-number\">%i</"
"span>]:"
-#: spyder/plugins/ipythonconsole.py:575
+#: spyder/plugins/ipythonconsole.py:629
msgid "Graphics"
msgstr "Gráficas"
-#: spyder/plugins/ipythonconsole.py:577
+#: spyder/plugins/ipythonconsole.py:631
msgid "Startup"
msgstr "Inicialización"
-#: spyder/plugins/ipythonconsole.py:604
+#: spyder/plugins/ipythonconsole.py:658
msgid ""
"The directory {} is not writable and it is required to create IPython "
"consoles. Please make it writable."
@@ -2711,23 +2796,33 @@ msgstr ""
"El directorio {} no tiene permisos de escritura, lo cual es requerido para "
"crear terminales de IPython. Por favor cambie sus permisos."
-#: spyder/plugins/ipythonconsole.py:784
+#: spyder/plugins/ipythonconsole.py:831
msgid "Open an &IPython console"
msgstr "Abrir una terminal de IPython"
-#: spyder/plugins/ipythonconsole.py:791
+#: spyder/plugins/ipythonconsole.py:838
msgid "Restart kernel"
msgstr "Reiniciar el núcleo"
-#: spyder/plugins/ipythonconsole.py:800
+#: spyder/plugins/ipythonconsole.py:847
msgid "Open a new IPython console connected to an existing kernel"
msgstr "Abrir una nueva terminal de IPython conectada a un núcleo existente"
-#: spyder/plugins/ipythonconsole.py:803
+#: spyder/plugins/ipythonconsole.py:850
msgid "Rename tab"
msgstr "Renombrar la pestaña"
-#: spyder/plugins/ipythonconsole.py:928
+#: spyder/plugins/ipythonconsole.py:968
+msgid ""
+"
Please exit from debugging before trying to run a file in this "
+"console.\n"
+"
"
+msgstr ""
+"
Por favor salga del modo de depuración antes de ejecutar un archivo "
+"en esta terminal.\n"
+"
"
+
+#: spyder/plugins/ipythonconsole.py:988
msgid ""
"No IPython console is currently available to run %s.
Please "
"open a new one and try again."
@@ -2735,65 +2830,57 @@ msgstr ""
"No existe un intérprete de IPython para ejecutar %s.
Por favor "
"abra uno nuevo e intente otra vez."
-#: spyder/plugins/ipythonconsole.py:1023
+#: spyder/plugins/ipythonconsole.py:1096
msgid ""
-"Your Python environment or installation doesn't have the ipykernel "
-"and cloudpickle modules installed on it. Without these modules is "
-"not possible for Spyder to create a console for you.
You can install "
-"them by running in a system terminal:
pip install ipykernel "
-"cloudpickle
or
conda install ipykernel cloudpickle"
-"tt>"
-msgstr ""
-"Su entorno o instalación de Python no cuenta con los módulos ipykernel"
-"tt> y cloudpickle. Sin estos módulos no es posible para Spyder el "
-"crear una terminal.
Puede instalarlos al ejecutar en una consola de "
-"comandos del sistema:
pip install ipykernel cloudpickle"
-"tt>
o
conda install ipykernel cloudpickle"
-
-#: spyder/plugins/ipythonconsole.py:1316
+"Your Python environment or installation doesn't have the spyder-kernels"
+"tt> module or the right version of it installed. Without this module is not "
+"possible for Spyder to create a console for you.
You can install it "
+"by running in a system terminal:
conda install spyder-kernels=0."
+"*
or
pip install spyder-kernels==0.*"
+msgstr ""
+"Su entorno o instalación de Python no cuenta con el módulo spyder-"
+"kernels o con la versión correcta del mismo, si está instalado. Sin "
+"este módulo no es posible para Spyder crear una terminal.
Puede "
+"instalarlo al ejecutar en una consola de comandos del sistema:"
+"
conda install spyder-kernels=0.*
o
pip "
+"install spyder-kernels==0.*"
+
+#: spyder/plugins/ipythonconsole.py:1362
msgid "Do you want to close this console?"
msgstr "¿Desea cerrar esta terminal?"
-#: spyder/plugins/ipythonconsole.py:1322
+#: spyder/plugins/ipythonconsole.py:1368
msgid ""
"Do you want to close all other consoles connected to the same kernel as this "
"one?"
msgstr ""
"¿Desea cerrar todas las otras terminales conectadas al mismo núcleo que ésta?"
-#: spyder/plugins/ipythonconsole.py:1387
+#: spyder/plugins/ipythonconsole.py:1440
msgid ""
"It was not possible to restart the IPython console when switching to this "
-"project. The error was {0}"
+"project. The error was
{0}"
msgstr ""
"No fue posible reiniciar la terminal de IPython al abrir este proyecto. El "
-"error fue {0}"
+"error fue
{0}"
-#: spyder/plugins/ipythonconsole.py:1488
-msgid ""
-"This error was most probably caused by installing Spyder in a directory with "
-"non-ascii characters (i.e. characters with tildes, apostrophes or non-latin "
-"symbols).
To fix it, please reinstall Spyder in a different "
-"location."
-msgstr ""
-"Este error fue causado probablemente por la instalación de Spyder en un "
-"directorio con caracteres no ascii (es decir, caracteres con tildes, "
-"apóstrofes o símbolos no latinos). Para solucionarlo, por favor "
-"reinstale Spyder en un lugar diferente."
+#: spyder/plugins/ipythonconsole.py:1546 spyder/plugins/ipythonconsole.py:1556
+msgid "The error is:
{}"
+msgstr "El error es:
{}"
-#: spyder/plugins/ipythonconsole.py:1694
+#: spyder/plugins/ipythonconsole.py:1742
msgid "IPython"
msgstr "IPython"
-#: spyder/plugins/ipythonconsole.py:1695
+#: spyder/plugins/ipythonconsole.py:1743
msgid "Unable to connect to %s"
msgstr "No se pudo establecer conexión con `%s`"
-#: spyder/plugins/ipythonconsole.py:1765
+#: spyder/plugins/ipythonconsole.py:1819
msgid "Connection error"
msgstr "Error de conexión"
-#: spyder/plugins/ipythonconsole.py:1766
+#: spyder/plugins/ipythonconsole.py:1820
msgid ""
"Could not open ssh tunnel. The error was:\n"
"\n"
@@ -2817,32 +2904,36 @@ msgstr "Eliminar disposición"
msgid "Layout Display and Order"
msgstr "Orden y visualización de las disposiciones"
-#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:66
+#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:71
msgid "Python interpreter"
msgstr "Intérprete de Python"
-#: spyder/plugins/maininterpreter.py:68
+#: spyder/plugins/maininterpreter.py:73
msgid "Select the Python interpreter for all Spyder consoles"
msgstr ""
"Seleccionar el intérprete de Python para todas las terminales de Spyder"
-#: spyder/plugins/maininterpreter.py:71
+#: spyder/plugins/maininterpreter.py:76
msgid "Default (i.e. the same as Spyder's)"
msgstr "Por defecto (es decir, el mismo de Spyder)"
-#: spyder/plugins/maininterpreter.py:74
+#: spyder/plugins/maininterpreter.py:79
msgid "Use the following Python interpreter:"
msgstr "Usar el siguiente intérprete:"
-#: spyder/plugins/maininterpreter.py:77
+#: spyder/plugins/maininterpreter.py:82
msgid "Executables"
msgstr "Ejecutables"
-#: spyder/plugins/maininterpreter.py:94
+#: spyder/plugins/maininterpreter.py:92
+msgid "Recent custom interpreters"
+msgstr "Intérpretes personalizados recientes"
+
+#: spyder/plugins/maininterpreter.py:107
msgid "User Module Reloader (UMR)"
msgstr "Recargador de Módulos del Usuario (RMU)"
-#: spyder/plugins/maininterpreter.py:95
+#: spyder/plugins/maininterpreter.py:108
msgid ""
"UMR forces Python to reload modules which were imported when executing a "
"file in a Python or IPython console with the runfile function."
@@ -2850,11 +2941,11 @@ msgstr ""
"El RMU obliga a Python a recargar los módulos que fueron importados durante "
"la ejecución de un archivo en la terminal con la función 'runfile'."
-#: spyder/plugins/maininterpreter.py:100
+#: spyder/plugins/maininterpreter.py:113
msgid "Enable UMR"
msgstr "Activar el RMU"
-#: spyder/plugins/maininterpreter.py:101
+#: spyder/plugins/maininterpreter.py:114
msgid ""
"This option will enable the User Module Reloader (UMR) in Python/IPython "
"consoles. UMR forces Python to reload deeply modules during import when "
@@ -2878,21 +2969,21 @@ msgstr ""
"puede tener que usar el atributo Qt.WA_DeleteOnClose en su ventana "
"principal, utilizando para ello el método setAttribute)."
-#: spyder/plugins/maininterpreter.py:117
+#: spyder/plugins/maininterpreter.py:130
msgid "Show reloaded modules list"
msgstr "Mostrar la lista de módulos que fueron recargados"
-#: spyder/plugins/maininterpreter.py:118
+#: spyder/plugins/maininterpreter.py:131
msgid "Please note that these changes will be applied only to new consoles"
msgstr ""
"Por favor tenga en cuenta que estos cambios sólo se aplicarán a nuevas "
"terminales"
-#: spyder/plugins/maininterpreter.py:122
+#: spyder/plugins/maininterpreter.py:135
msgid "Set UMR excluded (not reloaded) modules"
msgstr "Establecer la lista de módulos excluidos por el RMU"
-#: spyder/plugins/maininterpreter.py:150
+#: spyder/plugins/maininterpreter.py:163
msgid ""
"You selected an invalid Python interpreter for the console so the previous "
"interpreter will stay. Please make sure to select a valid one."
@@ -2900,7 +2991,7 @@ msgstr ""
"Se seleccionó un interprete de Python inválido así que se dejará el "
"anterior. Por favor asegúrese de seleccionar un intérprete válido."
-#: spyder/plugins/maininterpreter.py:175
+#: spyder/plugins/maininterpreter.py:184
msgid ""
"You selected a Python %d interpreter for the console but Spyder is "
"running on Python %d!.
Although this is possible, we recommend "
@@ -2914,16 +3005,16 @@ msgstr ""
"seleccionado, para evitar ver falsos errores y alarmas en el Editor debido a "
"la sintaxis incompatible entre estas dos versiones de Python."
-#: spyder/plugins/maininterpreter.py:186 spyder/plugins/maininterpreter.py:213
-#: spyder/plugins/maininterpreter.py:217
+#: spyder/plugins/maininterpreter.py:195 spyder/plugins/maininterpreter.py:222
+#: spyder/plugins/maininterpreter.py:226
msgid "UMR"
msgstr "RMU"
-#: spyder/plugins/maininterpreter.py:187
+#: spyder/plugins/maininterpreter.py:196
msgid "Set the list of excluded modules as this: numpy, scipy"
msgstr "Establezca la lista de módulos excluidos como: numpy, scipy"
-#: spyder/plugins/maininterpreter.py:204
+#: spyder/plugins/maininterpreter.py:213
msgid ""
"You are working with Python 2, this means that you can not import a module "
"that contains non-ascii characters."
@@ -2931,7 +3022,7 @@ msgstr ""
"No es posible importar un módulo con caracteres que no son ascii en Python "
"2. Por favor introduzca un módulo diferente."
-#: spyder/plugins/maininterpreter.py:214
+#: spyder/plugins/maininterpreter.py:223
msgid ""
"The following modules are not installed on your machine:\n"
"%s"
@@ -2939,7 +3030,7 @@ msgstr ""
"Los siguientes módulos no están instalados en su computador:\n"
"%s"
-#: spyder/plugins/maininterpreter.py:218
+#: spyder/plugins/maininterpreter.py:227
msgid ""
"Please note that these changes will be applied only to new Python/IPython "
"consoles"
@@ -2955,40 +3046,40 @@ msgstr "Ayuda en línea"
msgid "Outline"
msgstr "Explorador de código"
-#: spyder/plugins/projects.py:83 spyder/widgets/projects/explorer.py:112
+#: spyder/plugins/projects.py:77 spyder/widgets/projects/explorer.py:112
#: spyder/widgets/projects/explorer.py:126
msgid "Project explorer"
msgstr "Explorador de proyectos"
-#: spyder/plugins/projects.py:95
+#: spyder/plugins/projects.py:89
msgid "New Project..."
msgstr "Nuevo proyecto..."
-#: spyder/plugins/projects.py:98
+#: spyder/plugins/projects.py:92
msgid "Open Project..."
msgstr "Abrir proyecto..."
-#: spyder/plugins/projects.py:101
+#: spyder/plugins/projects.py:95
msgid "Close Project"
msgstr "Cerrar proyecto"
-#: spyder/plugins/projects.py:104
+#: spyder/plugins/projects.py:98
msgid "Delete Project"
msgstr "Eliminar proyecto"
-#: spyder/plugins/projects.py:110
+#: spyder/plugins/projects.py:104
msgid "Project Preferences"
msgstr "Preferencias del proyecto"
-#: spyder/plugins/projects.py:112
+#: spyder/plugins/projects.py:106
msgid "Recent Projects"
msgstr "Proyectos recientes"
-#: spyder/plugins/projects.py:249
+#: spyder/plugins/projects.py:264
msgid "Open project"
msgstr "Abrir proyecto"
-#: spyder/plugins/projects.py:255
+#: spyder/plugins/projects.py:270
msgid "%s is not a Spyder project!"
msgstr "%s no es un proyecto de Spyder!"
@@ -3142,7 +3233,7 @@ msgstr "El nuevo atajo tiene entra en conflicto con:"
#: spyder/plugins/shortcuts.py:353 spyder/plugins/shortcuts.py:362
msgid "Forbidden key sequence!"
-msgstr "Secuencia de teclas prohibida"
+msgstr "Secuencia de teclas prohibida!"
#: spyder/plugins/shortcuts.py:373
msgid ""
@@ -3160,7 +3251,7 @@ msgid "Context"
msgstr "Contexto"
#: spyder/plugins/shortcuts.py:587
-#: spyder/widgets/variableexplorer/collectionseditor.py:128
+#: spyder/widgets/variableexplorer/collectionseditor.py:153
msgid "Name"
msgstr "Nombre"
@@ -3186,7 +3277,7 @@ msgstr "Atajos de teclado"
#: spyder/plugins/shortcuts.py:846
msgid "Search: "
-msgstr "Buscar:"
+msgstr "Buscar: "
#: spyder/plugins/shortcuts.py:847
msgid "Reset to default values"
@@ -3200,36 +3291,45 @@ msgstr "Restaurar los atajos"
msgid "Do you want to reset to default values?"
msgstr "¿Desea restaurar los valores por defecto?"
-#: spyder/plugins/variableexplorer.py:25
+#: spyder/plugins/variableexplorer.py:24
+msgid "View and edit DataFrames and Series in the Variable Explorer"
+msgstr "Ver y editar DataFrames y Series en el Explorador de Variables"
+
+#: spyder/plugins/variableexplorer.py:29
+msgid "View and edit two and three dimensional arrays in the Variable Explorer"
+msgstr ""
+"Ver y editar arreglos bi y tridimensionales en el Explorador de Variables"
+
+#: spyder/plugins/variableexplorer.py:37
msgid "Filter"
msgstr "Filtrar"
-#: spyder/plugins/variableexplorer.py:27
-#: spyder/widgets/variableexplorer/namespacebrowser.py:200
+#: spyder/plugins/variableexplorer.py:39
+#: spyder/widgets/variableexplorer/namespacebrowser.py:203
msgid "Exclude private references"
msgstr "Excluir variables privadas"
-#: spyder/plugins/variableexplorer.py:28
-#: spyder/widgets/variableexplorer/namespacebrowser.py:215
+#: spyder/plugins/variableexplorer.py:40
+#: spyder/widgets/variableexplorer/namespacebrowser.py:218
msgid "Exclude capitalized references"
msgstr "Excluir variables que comienzan en mayúsculas"
-#: spyder/plugins/variableexplorer.py:29
-#: spyder/widgets/variableexplorer/namespacebrowser.py:208
+#: spyder/plugins/variableexplorer.py:41
+#: spyder/widgets/variableexplorer/namespacebrowser.py:211
msgid "Exclude all-uppercase references"
msgstr "Excluir variables en mayúsculas"
-#: spyder/plugins/variableexplorer.py:30
-#: spyder/widgets/variableexplorer/namespacebrowser.py:223
+#: spyder/plugins/variableexplorer.py:42
+#: spyder/widgets/variableexplorer/namespacebrowser.py:226
msgid "Exclude unsupported data types"
msgstr "Excluir tipos de datos no soportados"
-#: spyder/plugins/variableexplorer.py:36
-#: spyder/widgets/variableexplorer/collectionseditor.py:702
+#: spyder/plugins/variableexplorer.py:48
+#: spyder/widgets/variableexplorer/collectionseditor.py:738
msgid "Show arrays min/max"
msgstr "Mostrar el máximo y mínimo de arreglos"
-#: spyder/plugins/variableexplorer.py:178
+#: spyder/plugins/variableexplorer.py:202
msgid "Variable explorer"
msgstr "Explorador de variables"
@@ -3269,12 +3369,12 @@ msgstr "El directorio cuando una nueva consola se abre será el siguiente"
msgid "Back"
msgstr "Anterior"
-#: spyder/plugins/workingdirectory.py:132 spyder/widgets/explorer.py:1194
+#: spyder/plugins/workingdirectory.py:130 spyder/widgets/explorer.py:1199
#: spyder/widgets/variableexplorer/importwizard.py:539
msgid "Next"
msgstr "Siguiente"
-#: spyder/plugins/workingdirectory.py:143
+#: spyder/plugins/workingdirectory.py:141
msgid ""
"This is the working directory for newly\n"
"opened consoles (Python/IPython consoles and\n"
@@ -3289,31 +3389,39 @@ msgstr ""
"y Buscar en archivos y para los nuevos\n"
"archivos creados en el Editor"
-#: spyder/plugins/workingdirectory.py:168
+#: spyder/plugins/workingdirectory.py:166
msgid "Browse a working directory"
msgstr "Seleccionar un directorio de trabajo"
-#: spyder/plugins/workingdirectory.py:175
+#: spyder/plugins/workingdirectory.py:173
msgid "Change to parent directory"
msgstr "Moverse al directorio superior"
-#: spyder/plugins/workingdirectory.py:182 spyder/widgets/findinfiles.py:225
+#: spyder/plugins/workingdirectory.py:180 spyder/widgets/findinfiles.py:240
msgid "Current working directory"
msgstr "Directorio de trabajo actual"
-#: spyder/utils/codeanalysis.py:92
+#: spyder/utils/codeanalysis.py:94
msgid "Real-time code analysis on the Editor"
msgstr "Análisis del código en tiempo real en el Editor"
-#: spyder/utils/codeanalysis.py:96
+#: spyder/utils/codeanalysis.py:98
msgid "Real-time code style analysis on the Editor"
msgstr "Análisis de estilo del código en el Editor"
-#: spyder/utils/environ.py:46
+#: spyder/utils/environ.py:48
msgid "Environment variables"
msgstr "Variables de entorno"
-#: spyder/utils/environ.py:96
+#: spyder/utils/environ.py:57
+msgid ""
+"An error occurred while trying to show your environment variables. The error "
+"was
{0}"
+msgstr ""
+"Ocurrió in error al tratar de mostrar sus variables de entorno. El error "
+"fue
{0}"
+
+#: spyder/utils/environ.py:108
msgid ""
"Module pywin32 was not found.
Please restart this Windows "
"session (not the computer) for changes to take effect."
@@ -3322,7 +3430,7 @@ msgstr ""
"sesión de Windows (no el computador) para que los cambios surtan "
"efecto."
-#: spyder/utils/environ.py:109
+#: spyder/utils/environ.py:121
msgid ""
"If you accept changes, this will modify the current user environment "
"variables directly in Windows registry. Use it with precautions, at "
@@ -3340,7 +3448,7 @@ msgstr ""
"forma reinicie la aplicación desde la cual lo inició, como por ejemplo "
"Python(x,y) Home)"
-#: spyder/utils/help/sphinxify.py:217 spyder/utils/help/sphinxify.py:227
+#: spyder/utils/help/sphinxify.py:216 spyder/utils/help/sphinxify.py:226
msgid ""
"It was not possible to generate rich text help for this object.Please "
"see it in plain text."
@@ -3353,134 +3461,77 @@ msgstr ""
msgid "Editor's code completion, go-to-definition and help"
msgstr "Completado del código y ayuda en el Editor"
-#: spyder/utils/iofuncs.py:408
-msgid "Supported files"
-msgstr "Archivos soportados"
-
-#: spyder/utils/iofuncs.py:410
-msgid "All files (*.*)"
-msgstr "Todos los archivos (*.*)"
-
-#: spyder/utils/iofuncs.py:420
-msgid "Spyder data files"
-msgstr "Archivos de datos de Spyder"
-
-#: spyder/utils/iofuncs.py:422
-#: spyder/widgets/variableexplorer/collectionseditor.py:1061
-msgid "NumPy arrays"
-msgstr "Arreglos de NumPy"
-
-#: spyder/utils/iofuncs.py:423
-msgid "NumPy zip arrays"
-msgstr "Arreglos comprimidos de NumPy"
-
-#: spyder/utils/iofuncs.py:424
-msgid "Matlab files"
-msgstr "Archivos de Matlab"
-
-#: spyder/utils/iofuncs.py:425
-msgid "CSV text files"
-msgstr "Archivos de texto CSV"
-
-#: spyder/utils/iofuncs.py:427
-msgid "JPEG images"
-msgstr "Imágenes JPEG"
-
-#: spyder/utils/iofuncs.py:428
-msgid "PNG images"
-msgstr "Imágenes PNG"
-
-#: spyder/utils/iofuncs.py:429
-msgid "GIF images"
-msgstr "Imágenes GIF"
-
-#: spyder/utils/iofuncs.py:430
-msgid "TIFF images"
-msgstr "Imágenes TIFF"
-
-#: spyder/utils/iofuncs.py:431 spyder/utils/iofuncs.py:432
-msgid "Pickle files"
-msgstr "Archivos pickle"
-
-#: spyder/utils/iofuncs.py:433
-msgid "JSON files"
-msgstr "Archivos JSON"
-
-#: spyder/utils/iofuncs.py:452 spyder/utils/iofuncs.py:459
-msgid "Unsupported file type '%s'"
-msgstr "Tipo de archivo no soportado '%s'"
-
-#: spyder/utils/programs.py:287
+#: spyder/utils/programs.py:308
msgid "It was not possible to run this file in an external terminal"
msgstr "No fue posible ejecutar este archivo en una terminal del sistema"
-#: spyder/utils/syntaxhighlighters.py:34
+#: spyder/utils/syntaxhighlighters.py:35
msgid "Syntax highlighting for Matlab, Julia and other file types"
msgstr ""
"Coloreado del código para archivos tipo Matlab, Julia y varios otros tipos"
-#: spyder/utils/syntaxhighlighters.py:43
+#: spyder/utils/syntaxhighlighters.py:44
msgid "Background:"
msgstr "Fondo:"
-#: spyder/utils/syntaxhighlighters.py:44
+#: spyder/utils/syntaxhighlighters.py:45
#: spyder/widgets/sourcecode/codeeditor.py:107
msgid "Current line:"
msgstr "Línea seleccionada:"
-#: spyder/utils/syntaxhighlighters.py:45
+#: spyder/utils/syntaxhighlighters.py:46
msgid "Current cell:"
msgstr "Celda seleccionada:"
-#: spyder/utils/syntaxhighlighters.py:46
+#: spyder/utils/syntaxhighlighters.py:47
msgid "Occurrence:"
msgstr "Ocurrencia:"
-#: spyder/utils/syntaxhighlighters.py:47
+#: spyder/utils/syntaxhighlighters.py:48
msgid "Link:"
msgstr "Enlace:"
-#: spyder/utils/syntaxhighlighters.py:48
+#: spyder/utils/syntaxhighlighters.py:49
msgid "Side areas:"
msgstr "Áreas laterales:"
-#: spyder/utils/syntaxhighlighters.py:49
+#: spyder/utils/syntaxhighlighters.py:50
msgid "Matched
parens:"
msgstr "Paréntesis
emparejados:"
-#: spyder/utils/syntaxhighlighters.py:50
+#: spyder/utils/syntaxhighlighters.py:51
msgid "Unmatched
parens:"
msgstr "Paréntesis
desemparejados:"
-#: spyder/utils/syntaxhighlighters.py:51
+#: spyder/utils/syntaxhighlighters.py:52
msgid "Normal text:"
msgstr "Texto normal:"
-#: spyder/utils/syntaxhighlighters.py:52
+#: spyder/utils/syntaxhighlighters.py:53
msgid "Keyword:"
msgstr "Palabra clave:"
-#: spyder/utils/syntaxhighlighters.py:53
+#: spyder/utils/syntaxhighlighters.py:54
msgid "Builtin:"
msgstr "Objeto integrado:"
-#: spyder/utils/syntaxhighlighters.py:54
+#: spyder/utils/syntaxhighlighters.py:55
msgid "Definition:"
msgstr "Definición:"
-#: spyder/utils/syntaxhighlighters.py:55
+#: spyder/utils/syntaxhighlighters.py:56
msgid "Comment:"
msgstr "Comentario:"
-#: spyder/utils/syntaxhighlighters.py:56
+#: spyder/utils/syntaxhighlighters.py:57
msgid "String:"
msgstr "Cadena:"
-#: spyder/utils/syntaxhighlighters.py:57
+#: spyder/utils/syntaxhighlighters.py:58
msgid "Number:"
msgstr "Número:"
-#: spyder/utils/syntaxhighlighters.py:58
+#: spyder/utils/syntaxhighlighters.py:59
msgid "Instance:"
msgstr "Instancia:"
@@ -3536,45 +3587,45 @@ msgstr ""
msgid "Array dimensions not valid"
msgstr "Las dimensiones del arreglo no son válidas"
-#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2731
+#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2738
msgid "Zoom out"
msgstr "Alejar"
-#: spyder/widgets/browser.py:61 spyder/widgets/sourcecode/codeeditor.py:2727
+#: spyder/widgets/browser.py:61 spyder/widgets/sourcecode/codeeditor.py:2734
msgid "Zoom in"
msgstr "Acercar"
-#: spyder/widgets/browser.py:213
+#: spyder/widgets/browser.py:216
msgid "Home"
msgstr "Página de inicio"
-#: spyder/widgets/browser.py:249
+#: spyder/widgets/browser.py:252
msgid "Find text"
msgstr "Encontrar texto"
-#: spyder/widgets/browser.py:266
+#: spyder/widgets/browser.py:269
msgid "Address:"
msgstr "Dirección:"
-#: spyder/widgets/browser.py:302
+#: spyder/widgets/browser.py:305
msgid "Unable to load page"
msgstr "No fue posible cargar la página"
-#: spyder/widgets/comboboxes.py:164
+#: spyder/widgets/comboboxes.py:165
msgid "Press enter to validate this entry"
msgstr "Presione Enter para validar esta entrada"
-#: spyder/widgets/comboboxes.py:165
+#: spyder/widgets/comboboxes.py:166
msgid "This entry is incorrect"
msgstr "Esta entrada es incorrecta"
-#: spyder/widgets/comboboxes.py:208
+#: spyder/widgets/comboboxes.py:209
msgid "Press enter to validate this path"
msgstr "Presione Enter para validar esta ruta"
#: spyder/widgets/dependencies.py:63
msgid " Required "
-msgstr "Requerido"
+msgstr " Requerido"
#: spyder/widgets/dependencies.py:63
msgid "Module"
@@ -3582,7 +3633,7 @@ msgstr "Módulo"
#: spyder/widgets/dependencies.py:64
msgid " Installed "
-msgstr "Instalado"
+msgstr " Instalado "
#: spyder/widgets/dependencies.py:64
msgid "Provided features"
@@ -3614,77 +3665,78 @@ msgstr ""
msgid "Copy to clipboard"
msgstr "Copiar al portapapeles"
-#: spyder/widgets/editor.py:501
+#: spyder/widgets/editor.py:511
msgid "Find symbols in file..."
msgstr "Buscar símbolos en el archivo..."
-#: spyder/widgets/editor.py:504
+#: spyder/widgets/editor.py:514
msgid "Copy path to clipboard"
msgstr "Copiar la ruta al portapapeles"
-#: spyder/widgets/editor.py:508
+#: spyder/widgets/editor.py:518
msgid "Close all to the right"
msgstr "Cerrar todos a la derecha"
-#: spyder/widgets/editor.py:510
+#: spyder/widgets/editor.py:520
msgid "Close all but this"
msgstr "Cerrar todos menos éste"
-#: spyder/widgets/editor.py:514 spyder/widgets/explorer.py:370
+#: spyder/widgets/editor.py:524 spyder/widgets/explorer.py:373
msgid "Show in Finder"
msgstr "Mostrar en explorador del sistema"
-#: spyder/widgets/editor.py:516 spyder/widgets/explorer.py:372
+#: spyder/widgets/editor.py:526 spyder/widgets/explorer.py:375
msgid "Show in external file explorer"
msgstr "Mostrar en el explorador de archivos del sistema"
-#: spyder/widgets/editor.py:1193
+#: spyder/widgets/editor.py:1201
msgid "Temporary file"
msgstr "Archivo temporal"
-#: spyder/widgets/editor.py:1279
+#: spyder/widgets/editor.py:1287
msgid "New window"
msgstr "Nueva ventana"
-#: spyder/widgets/editor.py:1280
+#: spyder/widgets/editor.py:1288
msgid "Create a new editor window"
msgstr "Crear una nueva ventana de edición"
-#: spyder/widgets/editor.py:1283
+#: spyder/widgets/editor.py:1291
msgid "Split vertically"
msgstr "Dividir verticalmente"
-#: spyder/widgets/editor.py:1285
+#: spyder/widgets/editor.py:1293
msgid "Split vertically this editor window"
msgstr "Dividir verticalmente esta panel o ventana de edición"
-#: spyder/widgets/editor.py:1287
+#: spyder/widgets/editor.py:1295
msgid "Split horizontally"
msgstr "Dividir horizontalmente"
-#: spyder/widgets/editor.py:1289
+#: spyder/widgets/editor.py:1297
msgid "Split horizontally this editor window"
msgstr "Dividir horizontalmente esta ventana o panel de edición"
-#: spyder/widgets/editor.py:1291
+#: spyder/widgets/editor.py:1299
msgid "Close this panel"
msgstr "Cerrar este panel"
-#: spyder/widgets/editor.py:1531
+#: spyder/widgets/editor.py:1534
msgid "%s has been modified.
Do you want to save changes?"
msgstr "%s ha sido modificado.
¿Desea guardar los cambios?"
-#: spyder/widgets/editor.py:1617 spyder/widgets/editor.py:1780
-msgid "Save"
-msgstr "Guardar"
+#: spyder/widgets/editor.py:1620 spyder/widgets/editor.py:1783
+#: spyder/widgets/explorer.py:82
+msgid "Save Error"
+msgstr "Error de salvado"
-#: spyder/widgets/editor.py:1618 spyder/widgets/editor.py:1781
-#: spyder/widgets/shell.py:267
+#: spyder/widgets/editor.py:1621 spyder/widgets/editor.py:1784
+#: spyder/widgets/explorer.py:83
msgid "Unable to save file '%s'
Error message:
%s"
msgstr ""
"No fue posible guardar el archivo '%s'
Mensaje de error:
%s"
-#: spyder/widgets/editor.py:1968
+#: spyder/widgets/editor.py:1971
msgid ""
"%s is unavailable (this file may have been removed, moved or renamed "
"outside Spyder).
Do you want to close it?"
@@ -3692,7 +3744,7 @@ msgstr ""
"%s no está disponible (el archivo puede haber sido eliminado, movido "
"o renombrado por fuera de Spyder).
¿Desea cerrarlo?"
-#: spyder/widgets/editor.py:1991
+#: spyder/widgets/editor.py:1994
msgid ""
"%s has been modified outside Spyder.
Do you want to reload it and "
"lose all your changes?"
@@ -3700,7 +3752,7 @@ msgstr ""
"%s fue modificado por fuera de Spyder.
¿Desea recargarlo y perder "
"todos sus cambios?"
-#: spyder/widgets/editor.py:2101
+#: spyder/widgets/editor.py:2104
msgid ""
"All changes to %s will be lost.
Do you want to revert file from "
"disk?"
@@ -3708,11 +3760,11 @@ msgstr ""
"Todos los cambios a %s se perderán.
Desea revertir el archivo del "
"disco?"
-#: spyder/widgets/editor.py:2245
+#: spyder/widgets/editor.py:2250
msgid "Loading %s..."
msgstr "Cargando %s..."
-#: spyder/widgets/editor.py:2257
+#: spyder/widgets/editor.py:2262
msgid ""
"%s contains mixed end-of-line characters.
Spyder will fix this "
"automatically."
@@ -3720,11 +3772,11 @@ msgstr ""
"%s contiene varios tipos de caracteres de fin de línea.
Spyder lo "
"arreglará automáticamente."
-#: spyder/widgets/editor.py:2664
+#: spyder/widgets/editor.py:2672
msgid "Close window"
msgstr "Cerrar ventana"
-#: spyder/widgets/editor.py:2666
+#: spyder/widgets/editor.py:2674
msgid "Close this window"
msgstr "Cierra esta ventana"
@@ -3756,7 +3808,7 @@ msgstr "Ir a la posición del cursor"
msgid "Show absolute path"
msgstr "Mostrar la ruta completa"
-#: spyder/widgets/editortools.py:207 spyder/widgets/explorer.py:283
+#: spyder/widgets/editortools.py:207 spyder/widgets/explorer.py:286
msgid "Show all files"
msgstr "Mostrar todos los archivos"
@@ -3770,109 +3822,109 @@ msgstr ""
"Mostrar u ocultar el\n"
"explorador de código"
-#: spyder/widgets/explorer.py:279
+#: spyder/widgets/explorer.py:282
msgid "Edit filename filters..."
msgstr "Editar filtros..."
-#: spyder/widgets/explorer.py:293
+#: spyder/widgets/explorer.py:296
msgid "Edit filename filters"
msgstr "Editar los filtros para nombres de archivo"
-#: spyder/widgets/explorer.py:294
+#: spyder/widgets/explorer.py:297
msgid "Name filters:"
msgstr "Nombres de los filtros:"
-#: spyder/widgets/explorer.py:313
+#: spyder/widgets/explorer.py:316
msgid "File..."
msgstr "Archivo..."
-#: spyder/widgets/explorer.py:317
+#: spyder/widgets/explorer.py:320
msgid "Module..."
-msgstr "Módulo"
+msgstr "Módulo..."
-#: spyder/widgets/explorer.py:321
+#: spyder/widgets/explorer.py:324
msgid "Folder..."
msgstr "Carpeta..."
-#: spyder/widgets/explorer.py:325
+#: spyder/widgets/explorer.py:328
msgid "Package..."
msgstr "Paquete..."
-#: spyder/widgets/explorer.py:346
-#: spyder/widgets/variableexplorer/collectionseditor.py:677
+#: spyder/widgets/explorer.py:349
+#: spyder/widgets/variableexplorer/collectionseditor.py:713
msgid "Edit"
msgstr "Editar"
-#: spyder/widgets/explorer.py:348
+#: spyder/widgets/explorer.py:351
msgid "Move..."
msgstr "Mover a..."
-#: spyder/widgets/explorer.py:351
+#: spyder/widgets/explorer.py:354
msgid "Delete..."
msgstr "Eliminar..."
-#: spyder/widgets/explorer.py:354
+#: spyder/widgets/explorer.py:357
msgid "Rename..."
msgstr "Renombrar..."
-#: spyder/widgets/explorer.py:357
+#: spyder/widgets/explorer.py:360
msgid "Open"
msgstr "Abrir"
-#: spyder/widgets/explorer.py:358 spyder/widgets/sourcecode/codeeditor.py:2699
+#: spyder/widgets/explorer.py:361 spyder/widgets/sourcecode/codeeditor.py:2706
msgid "Convert to Python script"
msgstr "Convertir a un archivo de Python"
-#: spyder/widgets/explorer.py:399
+#: spyder/widgets/explorer.py:393
msgid "Commit"
msgstr "Consignar"
-#: spyder/widgets/explorer.py:402
+#: spyder/widgets/explorer.py:396
msgid "Browse repository"
-msgstr "Explorar repositorio "
+msgstr "Explorar repositorio"
-#: spyder/widgets/explorer.py:413
+#: spyder/widgets/explorer.py:407
msgid "Open command prompt here"
msgstr "Abrir símbolo del sistema aquí"
-#: spyder/widgets/explorer.py:415
+#: spyder/widgets/explorer.py:409
msgid "Open terminal here"
msgstr "Abrir terminal del sistema aquí"
-#: spyder/widgets/explorer.py:416
+#: spyder/widgets/explorer.py:410
msgid "Open IPython console here"
msgstr "Abrir una terminal de Python aquí"
-#: spyder/widgets/explorer.py:430
+#: spyder/widgets/explorer.py:424
msgid "New"
msgstr "Crear nuevo"
-#: spyder/widgets/explorer.py:438
+#: spyder/widgets/explorer.py:432
msgid "Import"
msgstr "Importar"
-#: spyder/widgets/explorer.py:584
+#: spyder/widgets/explorer.py:583
msgid "Do you really want to delete %s?"
msgstr "¿Realmente desea eliminar %s?"
-#: spyder/widgets/explorer.py:602
+#: spyder/widgets/explorer.py:601
msgid "delete"
msgstr "eliminar"
-#: spyder/widgets/explorer.py:603 spyder/widgets/projects/explorer.py:148
+#: spyder/widgets/explorer.py:602 spyder/widgets/projects/explorer.py:148
#: spyder/widgets/projects/explorer.py:256
msgid "Project Explorer"
msgstr "Explorador de proyectos"
-#: spyder/widgets/explorer.py:604 spyder/widgets/projects/explorer.py:149
+#: spyder/widgets/explorer.py:603 spyder/widgets/projects/explorer.py:149
msgid "Unable to %s %s
Error message:
%s"
msgstr "No fue posible %s %s
Mensaje de error:
%s"
-#: spyder/widgets/explorer.py:619
+#: spyder/widgets/explorer.py:618
msgid "File Explorer"
msgstr "Explorador de archivos"
-#: spyder/widgets/explorer.py:620
+#: spyder/widgets/explorer.py:619
msgid ""
"The current directory contains a project.
If you want to delete the "
"project, please go to Projects » Delete Project"
@@ -3881,11 +3933,11 @@ msgstr ""
"proyecto, por favor diríjase a Proyectos » Eliminar "
"proyecto"
-#: spyder/widgets/explorer.py:637 spyder/widgets/sourcecode/codeeditor.py:2160
+#: spyder/widgets/explorer.py:636 spyder/widgets/sourcecode/codeeditor.py:2167
msgid "Conversion error"
msgstr "Error de conversión"
-#: spyder/widgets/explorer.py:638 spyder/widgets/sourcecode/codeeditor.py:2161
+#: spyder/widgets/explorer.py:637 spyder/widgets/sourcecode/codeeditor.py:2168
msgid ""
"It was not possible to convert this notebook. The error is:\n"
"\n"
@@ -3893,18 +3945,18 @@ msgstr ""
"No fue posible convertir este notebook. El error es:\n"
"\n"
-#: spyder/widgets/explorer.py:655 spyder/widgets/explorer.py:663
-#: spyder/widgets/explorer.py:674
-#: spyder/widgets/variableexplorer/collectionseditor.py:706
-#: spyder/widgets/variableexplorer/collectionseditor.py:952
+#: spyder/widgets/explorer.py:654 spyder/widgets/explorer.py:662
+#: spyder/widgets/explorer.py:676
+#: spyder/widgets/variableexplorer/collectionseditor.py:742
+#: spyder/widgets/variableexplorer/collectionseditor.py:988
msgid "Rename"
msgstr "Renombrar"
-#: spyder/widgets/explorer.py:656
+#: spyder/widgets/explorer.py:655
msgid "New name:"
msgstr "Nuevo nombre:"
-#: spyder/widgets/explorer.py:664
+#: spyder/widgets/explorer.py:663
msgid ""
"Do you really want to rename %s and overwrite the existing file "
"%s?"
@@ -3912,77 +3964,77 @@ msgstr ""
"¿Realmente desea renombrar %s y sobrescribir el archivo existente "
"%s?"
-#: spyder/widgets/explorer.py:675
+#: spyder/widgets/explorer.py:677
msgid "Unable to rename file %s
Error message:
%s"
msgstr ""
"No fue posible renombrar el archivo %s
Mensaje de error:"
"
%s"
-#: spyder/widgets/explorer.py:722
+#: spyder/widgets/explorer.py:724
msgid "Unable to move %s
Error message:
%s"
msgstr "No fue posible mover %s
Mensaje de error:
%s"
-#: spyder/widgets/explorer.py:740
+#: spyder/widgets/explorer.py:742
msgid "Unable to create folder %s
Error message:
%s"
msgstr ""
"No fue posible crear la carpeta %s
Mensaje de error:
"
"%s"
-#: spyder/widgets/explorer.py:753 spyder/widgets/explorer.py:787
+#: spyder/widgets/explorer.py:755 spyder/widgets/explorer.py:789
msgid "Unable to create file %s
Error message:
%s"
msgstr ""
"No fue posible crear el archivo %s
Mensaje de error:
"
"%s"
-#: spyder/widgets/explorer.py:761
+#: spyder/widgets/explorer.py:763
msgid "New folder"
msgstr "Nueva carpeta"
-#: spyder/widgets/explorer.py:762
+#: spyder/widgets/explorer.py:764
msgid "Folder name:"
msgstr "Nombre de la carpeta:"
-#: spyder/widgets/explorer.py:767
+#: spyder/widgets/explorer.py:769
msgid "New package"
msgstr "Nuevo paquete"
-#: spyder/widgets/explorer.py:768
+#: spyder/widgets/explorer.py:770
msgid "Package name:"
msgstr "Nombre del paquete:"
-#: spyder/widgets/explorer.py:808
+#: spyder/widgets/explorer.py:810
msgid "New module"
msgstr "Nuevo módulo"
-#: spyder/widgets/explorer.py:823
+#: spyder/widgets/explorer.py:825
msgid ""
"For %s support, please install one of the
following tools:
%s"
msgstr ""
"Para contar con soporte de %s, por favor instale una de
las siguientes "
"herramientas:
%s"
-#: spyder/widgets/explorer.py:827
+#: spyder/widgets/explorer.py:829
msgid "Unable to find external program.
%s"
msgstr "No fue posible encontrar el programa externo.
%s"
-#: spyder/widgets/explorer.py:1048
+#: spyder/widgets/explorer.py:1049
msgid "Show current directory only"
msgstr "Mostrar sólo el directorio actual"
-#: spyder/widgets/explorer.py:1158
+#: spyder/widgets/explorer.py:1163
msgid "You don't have the right permissions to open this directory"
msgstr "No tiene con permisos para abrir este directorio"
-#: spyder/widgets/explorer.py:1189
+#: spyder/widgets/explorer.py:1194
msgid "Show icons and text"
-msgstr "Mostrar iconos y texto "
+msgstr "Mostrar iconos y texto"
-#: spyder/widgets/explorer.py:1191
+#: spyder/widgets/explorer.py:1196
#: spyder/widgets/variableexplorer/importwizard.py:535
msgid "Previous"
msgstr "Anterior"
-#: spyder/widgets/explorer.py:1197
+#: spyder/widgets/explorer.py:1202
msgid "Parent"
msgstr "Directorio superior"
@@ -4008,27 +4060,27 @@ msgstr ""
msgid "lines"
msgstr "líneas"
-#: spyder/widgets/findinfiles.py:124
+#: spyder/widgets/findinfiles.py:121
msgid "Unexpected error: see internal console"
-msgstr "Error inesperado. Por favor vea la terminal interna."
+msgstr "Error inesperado. Por favor vea la terminal interna"
-#: spyder/widgets/findinfiles.py:152
+#: spyder/widgets/findinfiles.py:158
msgid "invalid regular expression"
msgstr "expresión regular inválida"
-#: spyder/widgets/findinfiles.py:202
+#: spyder/widgets/findinfiles.py:217
msgid "permission denied errors were encountered"
msgstr "permiso denegado, se encontraron errores"
-#: spyder/widgets/findinfiles.py:217
+#: spyder/widgets/findinfiles.py:232
msgid "Search directory"
msgstr "Directorio de búsqueda"
-#: spyder/widgets/findinfiles.py:230
+#: spyder/widgets/findinfiles.py:245
msgid "Project"
msgstr "Proyecto"
-#: spyder/widgets/findinfiles.py:231
+#: spyder/widgets/findinfiles.py:246
msgid ""
"Search in all files and directories present on the current project path (if "
"opened)"
@@ -4036,253 +4088,395 @@ msgstr ""
"Buscar en todos los archivos y directorios presentes en la ruta del proyecto "
"actual (si está abierto)"
-#: spyder/widgets/findinfiles.py:236
+#: spyder/widgets/findinfiles.py:251
msgid "File"
msgstr "&Archivo"
-#: spyder/widgets/findinfiles.py:237
+#: spyder/widgets/findinfiles.py:252
msgid "Search in current opened file"
msgstr "Buscar en el archivo abierto"
-#: spyder/widgets/findinfiles.py:242
+#: spyder/widgets/findinfiles.py:257
msgid "Select other directory"
msgstr "Seleccionar otro directorio"
-#: spyder/widgets/findinfiles.py:243
+#: spyder/widgets/findinfiles.py:258
msgid "Search in other folder present on the file system"
msgstr "Buscar en otro directorio del sistema de archivos"
-#: spyder/widgets/findinfiles.py:247
+#: spyder/widgets/findinfiles.py:262
msgid "Clear the list of other directories"
msgstr "Limpiar la lista de otros directorios"
-#: spyder/widgets/findinfiles.py:318
+#: spyder/widgets/findinfiles.py:333
msgid "Clear other directories"
msgstr "Limpiar los otros directorios"
-#: spyder/widgets/findinfiles.py:319
+#: spyder/widgets/findinfiles.py:334
msgid "Do you want to clear the list of other directories?"
msgstr "¿Desea limpiar la lista de otros directorios?"
-#: spyder/widgets/findinfiles.py:415
+#: spyder/widgets/findinfiles.py:404 spyder/widgets/findreplace.py:52
+msgid "Regular expression error"
+msgstr "Error en la expresión regular"
+
+#: spyder/widgets/findinfiles.py:427
msgid "Search pattern"
msgstr "Patrón de búsqueda"
-#: spyder/widgets/findinfiles.py:418 spyder/widgets/findinfiles.py:458
-#: spyder/widgets/findreplace.py:99
+#: spyder/widgets/findinfiles.py:430 spyder/widgets/findinfiles.py:470
+#: spyder/widgets/findreplace.py:100
msgid "Regular expression"
msgstr "Expresión regular"
-#: spyder/widgets/findinfiles.py:421 spyder/widgets/findreplace.py:105
+#: spyder/widgets/findinfiles.py:433 spyder/widgets/findreplace.py:106
msgid "Case Sensitive"
msgstr ""
"Distinguir mayúsculas\n"
"de minúsculas"
-#: spyder/widgets/findinfiles.py:432
+#: spyder/widgets/findinfiles.py:444
msgid "Search"
msgstr "Buscar"
-#: spyder/widgets/findinfiles.py:435
+#: spyder/widgets/findinfiles.py:447
msgid "Start search"
msgstr "Comenzar la búsqueda"
-#: spyder/widgets/findinfiles.py:442
+#: spyder/widgets/findinfiles.py:454
msgid "Stop search"
msgstr "Detener la búsqueda"
-#: spyder/widgets/findinfiles.py:452
-msgid "Excluded filenames pattern"
-msgstr ""
-"Patrones de nombres de\n"
-"archivo a excluir"
+#: spyder/widgets/findinfiles.py:464
+msgid "Exclude pattern"
+msgstr "Patrón de exclusión"
-#: spyder/widgets/findinfiles.py:461
+#: spyder/widgets/findinfiles.py:473
msgid "Exclude:"
msgstr "Excluir:"
-#: spyder/widgets/findinfiles.py:470
+#: spyder/widgets/findinfiles.py:482
msgid "Search in:"
msgstr "Buscar en:"
-#: spyder/widgets/findinfiles.py:499
+#: spyder/widgets/findinfiles.py:511
msgid "Hide advanced options"
msgstr "Ocultar opciones avanzadas"
-#: spyder/widgets/findinfiles.py:502
+#: spyder/widgets/findinfiles.py:514
msgid "Show advanced options"
msgstr "Mostrar opciones avanzadas"
-#: spyder/widgets/findinfiles.py:759 spyder/widgets/findinfiles.py:843
+#: spyder/widgets/findinfiles.py:790 spyder/widgets/findinfiles.py:877
msgid "String not found"
msgstr "Texto no encontrado"
-#: spyder/widgets/findinfiles.py:845
+#: spyder/widgets/findinfiles.py:879
msgid "matches in"
msgstr "coincidencias en"
-#: spyder/widgets/findinfiles.py:846
+#: spyder/widgets/findinfiles.py:880
msgid "file"
msgstr "archivo"
-#: spyder/widgets/findinfiles.py:878
+#: spyder/widgets/findinfiles.py:912
msgid " Scanning: {0}"
msgstr " Escaneando: {0}"
-#: spyder/widgets/findinfiles.py:880
+#: spyder/widgets/findinfiles.py:914
msgid " Searching for files in folder: {0}"
msgstr " Buscando archivos en la carpeta: {0}"
-#: spyder/widgets/findinfiles.py:884
+#: spyder/widgets/findinfiles.py:918
msgid " Searching for files..."
msgstr " Buscando archivos..."
-#: spyder/widgets/findreplace.py:48
+#: spyder/widgets/findreplace.py:49
msgid "No matches"
msgstr "Sin coincidencias"
-#: spyder/widgets/findreplace.py:49 spyder/widgets/findreplace.py:50
-#: spyder/widgets/findreplace.py:72
+#: spyder/widgets/findreplace.py:50 spyder/widgets/findreplace.py:51
+#: spyder/widgets/findreplace.py:73
msgid "Search string"
msgstr "Buscar texto"
-#: spyder/widgets/findreplace.py:51
-msgid "Regular expression error"
-msgstr "Error en la expresión regular"
-
-#: spyder/widgets/findreplace.py:111
+#: spyder/widgets/findreplace.py:112
msgid "Whole words"
msgstr ""
"Solamente palabras\n"
"completas"
-#: spyder/widgets/findreplace.py:117
+#: spyder/widgets/findreplace.py:118
msgid "Highlight matches"
msgstr "Resaltar coincidencias"
-#: spyder/widgets/findreplace.py:131
+#: spyder/widgets/findreplace.py:132
msgid "Replace with:"
msgstr "Reemplazar con:"
-#: spyder/widgets/findreplace.py:133
+#: spyder/widgets/findreplace.py:134
msgid "Replace string"
msgstr "Reemplazar texto"
-#: spyder/widgets/findreplace.py:137
+#: spyder/widgets/findreplace.py:138
msgid "Replace/find next"
msgstr "Buscar/reemplazar siguiente"
-#: spyder/widgets/findreplace.py:142
+#: spyder/widgets/findreplace.py:143
msgid "Replace selection"
msgstr "Reemplazar la selección"
-#: spyder/widgets/findreplace.py:150
+#: spyder/widgets/findreplace.py:151
msgid "Replace all"
msgstr "Reemplazar todo"
-#: spyder/widgets/findreplace.py:577
+#: spyder/widgets/findreplace.py:583
msgid "of"
msgstr "de"
-#: spyder/widgets/findreplace.py:581
+#: spyder/widgets/findreplace.py:587
msgid "matches"
msgstr "coincidencias"
-#: spyder/widgets/findreplace.py:584
+#: spyder/widgets/findreplace.py:590
msgid "no matches"
msgstr "sin coincidencias"
-#: spyder/widgets/internalshell.py:262
+#: spyder/widgets/github/backend.py:151
+msgid "Invalid credentials"
+msgstr "Credenciales inválidas"
+
+#: spyder/widgets/github/backend.py:152
+msgid "Failed to create Github issue, invalid credentials..."
+msgstr ""
+"No fue posible crear el reporte de error en Github pues sus credenciales son "
+"inválidas."
+
+#: spyder/widgets/github/backend.py:159
+msgid "Failed to create issue"
+msgstr "Ocurrió un problema al generar el reporte de error"
+
+#: spyder/widgets/github/backend.py:160
+msgid "Failed to create Github issue. Error %d"
+msgstr "No fue posible crear el reporte de error en Github. El error es %d"
+
+#: spyder/widgets/github/backend.py:167
+msgid "Issue created on Github"
+msgstr "El reporte de error fue creado en Github"
+
+#: spyder/widgets/github/backend.py:168
+msgid ""
+"Issue successfully created. Would you like to open the issue in your web "
+"browser?"
+msgstr ""
+"El reporte de error fue creado exitosamente ¿Desea abrir el reporte en su "
+"navegador web?"
+
+#: spyder/widgets/github/backend.py:195
+msgid "Failed to store password"
+msgstr "Error al guardar su contraseña"
+
+#: spyder/widgets/github/backend.py:196
+msgid ""
+"It was not possible to securely save your password. You will be prompted for "
+"your Github credentials next time you want to report an issue."
+msgstr ""
+"No fue posible guardar de forma segura su contraseña. Por tanto, la próxima "
+"vez que desee crear un reporte de error se le pedirán nuevamente sus "
+"credenciales de Github."
+
+#: spyder/widgets/github/backend.py:212
+msgid "Failed to store token"
+msgstr "Error al guardar su token"
+
+#: spyder/widgets/github/backend.py:213
+msgid ""
+"It was not possible to securely save your token. You will be prompted for "
+"your Github token next time you want to report an issue."
+msgstr ""
+"No fue posible guardar de forma segura su token. Por tanto, la próxima vez "
+"que desee crear un reporte de error se le pedirá nuevamente su token de "
+"Github."
+
+#: spyder/widgets/github/backend.py:237
+msgid "Failed to retrieve password"
+msgstr "No fue posible recuperar su contraseña"
+
+#: spyder/widgets/github/backend.py:238
+msgid ""
+"It was not possible to retrieve your password. Please introduce it again."
+msgstr ""
+"No fue posible recuperar su contraseña. Por favor introdúzcala de nuevo."
+
+#: spyder/widgets/github/backend.py:249
+msgid "Failed to retrieve token"
+msgstr "No fue posible recuperar su token"
+
+#: spyder/widgets/github/backend.py:250
+msgid "It was not possible to retrieve your token. Please introduce it again."
+msgstr "No fue posible recuperar su token. Por favor introdúzcalo de nuevo."
+
+#: spyder/widgets/github/gh_login.py:38
+msgid "Sign in to Github"
+msgstr "Registrarse en Github"
+
+#: spyder/widgets/github/gh_login.py:57
+msgid ""
+"For regular users, i.e. users without two-factor authentication "
+"enabled"
+msgstr ""
+"Para usuarios regulares, es decir, usuarios que no tienen activada la "
+"autenticación de dos pasos"
+
+#: spyder/widgets/github/gh_login.py:62
+msgid "Username:"
+msgstr "Nombre de usuario:"
+
+#: spyder/widgets/github/gh_login.py:69
+msgid "Password: "
+msgstr "Contraseña: "
+
+#: spyder/widgets/github/gh_login.py:81
+msgid "Remember me"
+msgstr "Recordarme"
+
+#: spyder/widgets/github/gh_login.py:82
+msgid "Spyder will save your credentials safely"
+msgstr "Spyder guardará sus credenciales de forma segura"
+
+#: spyder/widgets/github/gh_login.py:99
+msgid "Password Only"
+msgstr "Sólo contraseña"
+
+#: spyder/widgets/github/gh_login.py:105
+msgid ""
+"For users with two-factor authentication enabled, or who prefer a per-"
+"app token authentication.
You can go here "
+"and click \"Generate token\" at the bottom to create a new token to use for "
+"this, with the appropriate permissions."
+msgstr ""
+"Para usuarios que cuentan con autenticación de dos pasos o que "
+"prefieren autenticación de token por aplicación.
Puede dirigirse a "
+"este sitio y oprimir \"Generate token\" al final "
+"de la página para crear un nuevo token para usar en este caso, con los "
+"permisos apropiados."
+
+#: spyder/widgets/github/gh_login.py:127
+msgid "Remember token"
+msgstr "Recordar token"
+
+#: spyder/widgets/github/gh_login.py:128
+msgid "Spyder will save your token safely"
+msgstr "Spyder guardará su token de forma segura"
+
+#: spyder/widgets/github/gh_login.py:145
+msgid "Access Token"
+msgstr "Acceso por token"
+
+#: spyder/widgets/github/gh_login.py:148
+msgid "Sign in"
+msgstr "Registrarse"
+
+#: spyder/widgets/internalshell.py:263
msgid "Help..."
msgstr "Ayuda..."
-#: spyder/widgets/internalshell.py:279
+#: spyder/widgets/internalshell.py:280
msgid "Shell special commands:"
msgstr "Comandos especiales:"
-#: spyder/widgets/internalshell.py:280
+#: spyder/widgets/internalshell.py:281
msgid "Internal editor:"
msgstr "Editor interno:"
-#: spyder/widgets/internalshell.py:281
+#: spyder/widgets/internalshell.py:282
msgid "External editor:"
msgstr "Editor externo:"
-#: spyder/widgets/internalshell.py:282
+#: spyder/widgets/internalshell.py:283
msgid "Run script:"
msgstr "Ejecutar un archivo:"
-#: spyder/widgets/internalshell.py:283
+#: spyder/widgets/internalshell.py:284
msgid "Remove references:"
msgstr "Eliminar referencias:"
-#: spyder/widgets/internalshell.py:284
+#: spyder/widgets/internalshell.py:285
msgid "System commands:"
msgstr "Comandos del sistema:"
-#: spyder/widgets/internalshell.py:285
+#: spyder/widgets/internalshell.py:286
msgid "Python help:"
msgstr "Ayuda de Python:"
-#: spyder/widgets/internalshell.py:286
+#: spyder/widgets/internalshell.py:287
msgid "GUI-based editor:"
msgstr "Editor gráfico:"
-#: spyder/widgets/ipythonconsole/client.py:272
+#: spyder/widgets/internalshell.py:418
+msgid ""
+"In order to use commands like \"raw_input\" or \"input\" run Spyder with the "
+"multithread option (--multithread) from a system terminal"
+msgstr ""
+"Para utilizar comandos como \"raw_input\" o \"input\", por favor ejecute "
+"Spyder con la opción multithread (--multithread) desde una terminal del "
+"sistema"
+
+#: spyder/widgets/ipythonconsole/client.py:308
msgid "An error ocurred while starting the kernel"
msgstr "Ocurrió un error mientras iniciaba el núcleo"
-#: spyder/widgets/ipythonconsole/client.py:313
-#: spyder/widgets/ipythonconsole/client.py:369
-#: spyder/widgets/ipythonconsole/client.py:402
-#: spyder/widgets/ipythonconsole/shell.py:233
-#: spyder/widgets/variableexplorer/namespacebrowser.py:193
+#: spyder/widgets/ipythonconsole/client.py:352
+#: spyder/widgets/ipythonconsole/client.py:408
+#: spyder/widgets/ipythonconsole/client.py:441
+#: spyder/widgets/ipythonconsole/shell.py:234
+#: spyder/widgets/variableexplorer/namespacebrowser.py:196
msgid "Remove all variables"
msgstr "Eliminar todas las variables"
-#: spyder/widgets/ipythonconsole/client.py:322
+#: spyder/widgets/ipythonconsole/client.py:361
msgid "Show environment variables"
msgstr "Mostrar las variables de entorno"
-#: spyder/widgets/ipythonconsole/client.py:329
+#: spyder/widgets/ipythonconsole/client.py:368
msgid "Show sys.path contents"
msgstr "Contenidos del sys.path"
-#: spyder/widgets/ipythonconsole/client.py:356
+#: spyder/widgets/ipythonconsole/client.py:395
msgid "Stop the current command"
msgstr "Detener el comando actual"
-#: spyder/widgets/ipythonconsole/client.py:367
-#: spyder/widgets/variableexplorer/collectionseditor.py:699
-#: spyder/widgets/variableexplorer/collectionseditor.py:934
+#: spyder/widgets/ipythonconsole/client.py:406
+#: spyder/widgets/variableexplorer/collectionseditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:970
msgid "Remove"
msgstr "Eliminar"
-#: spyder/widgets/ipythonconsole/client.py:390
+#: spyder/widgets/ipythonconsole/client.py:429
msgid "Inspect current object"
msgstr "Inspeccionar objeto"
-#: spyder/widgets/ipythonconsole/client.py:396
+#: spyder/widgets/ipythonconsole/client.py:435
msgid "Clear line or block"
msgstr "Limpiar línea o bloque"
-#: spyder/widgets/ipythonconsole/client.py:409
+#: spyder/widgets/ipythonconsole/client.py:448
msgid "Clear console"
msgstr "Limpiar la terminal"
-#: spyder/widgets/ipythonconsole/client.py:462
+#: spyder/widgets/ipythonconsole/client.py:507
msgid "Are you sure you want to restart the kernel?"
msgstr "Está seguro de que desea reiniciar el núcleo?"
-#: spyder/widgets/ipythonconsole/client.py:464
+#: spyder/widgets/ipythonconsole/client.py:509
msgid "Restart kernel?"
msgstr "Reiniciar el núcleo?"
-#: spyder/widgets/ipythonconsole/client.py:476
+#: spyder/widgets/ipythonconsole/client.py:526
msgid "Error restarting kernel: %s\n"
msgstr "Ocurrió un error al reiniciar el núcleo: %s\n"
-#: spyder/widgets/ipythonconsole/client.py:484
+#: spyder/widgets/ipythonconsole/client.py:534
msgid ""
"
Restarting kernel...\n"
"
"
@@ -4290,41 +4484,41 @@ msgstr ""
"
Reiniciando el núcleo...\n"
"
"
-#: spyder/widgets/ipythonconsole/client.py:488
+#: spyder/widgets/ipythonconsole/client.py:538
msgid "Cannot restart a kernel not started by Spyder\n"
msgstr "No es posible reiniciar un núcleo que no fue iniciado por Spyder\n"
-#: spyder/widgets/ipythonconsole/client.py:597
+#: spyder/widgets/ipythonconsole/client.py:649
msgid "Connecting to kernel..."
msgstr "Conectándose al núcleo..."
-#: spyder/widgets/ipythonconsole/help.py:128 spyder/widgets/mixins.py:712
+#: spyder/widgets/ipythonconsole/help.py:128 spyder/widgets/mixins.py:726
msgid "Arguments"
msgstr "Argumentos"
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:129
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:138
msgid "Loading this kind of data while debugging is not supported."
msgstr ""
"No se admite la carga de este tipo de datos mientras se ejecuta el depurador "
"de código."
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:148
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:157
msgid "Saving data while debugging is not supported."
msgstr ""
"No es posible guardar datos durante la ejecución del depurador de código."
-#: spyder/widgets/ipythonconsole/shell.py:234
+#: spyder/widgets/ipythonconsole/shell.py:235
msgid ""
"All user-defined variables will be removed. Are you sure you want to proceed?"
msgstr ""
"Todas las variables definidas por el usuario serán eliminadas. ¿Está seguro "
"de que desea continuar?"
-#: spyder/widgets/ipythonconsole/shell.py:240
+#: spyder/widgets/ipythonconsole/shell.py:241
msgid "Don't show again."
msgstr "No mostrar de nuevo."
-#: spyder/widgets/ipythonconsole/shell.py:264
+#: spyder/widgets/ipythonconsole/shell.py:266
msgid ""
"
Removing all variables...\n"
"
"
@@ -4332,15 +4526,15 @@ msgstr ""
"
Eliminando todas las variables...\n"
"
"
-#: spyder/widgets/ipythonconsole/shell.py:430
-msgid "Changing backend to Qt for Mayavi"
-msgstr "Cambiando la salida gráfica a Qt por Mayavi"
+#: spyder/widgets/ipythonconsole/shell.py:432
+msgid "Changing backend to Qt4 for Mayavi"
+msgstr "Cambiando la salida gráfica a Qt4 por Mayavi"
-#: spyder/widgets/ipythonconsole/shell.py:475
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel died, restarting"
msgstr "El núcleo dejó de funcionar, reiniciándolo"
-#: spyder/widgets/ipythonconsole/shell.py:475
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel restarting"
msgstr "Reiniciando el núcleo"
@@ -4368,45 +4562,46 @@ msgstr "Colapsar selección"
msgid "Expand selection"
msgstr "Expandir selección"
-#: spyder/widgets/pathmanager.py:97
+#: spyder/widgets/pathmanager.py:98
msgid "Move to top"
msgstr "Mover al principio"
-#: spyder/widgets/pathmanager.py:103
+#: spyder/widgets/pathmanager.py:104
msgid "Move up"
msgstr "Mover arriba"
-#: spyder/widgets/pathmanager.py:109
+#: spyder/widgets/pathmanager.py:110
msgid "Move down"
msgstr "Mover abajo"
-#: spyder/widgets/pathmanager.py:115
+#: spyder/widgets/pathmanager.py:116
msgid "Move to bottom"
msgstr "Mover al final"
-#: spyder/widgets/pathmanager.py:126 spyder/widgets/pathmanager.py:267
+#: spyder/widgets/pathmanager.py:127 spyder/widgets/pathmanager.py:270
+#: spyder/widgets/pathmanager.py:282
msgid "Add path"
msgstr "Añadir ruta"
-#: spyder/widgets/pathmanager.py:131 spyder/widgets/pathmanager.py:246
+#: spyder/widgets/pathmanager.py:132 spyder/widgets/pathmanager.py:247
msgid "Remove path"
msgstr "Eliminar ruta"
-#: spyder/widgets/pathmanager.py:141
+#: spyder/widgets/pathmanager.py:142
msgid "Synchronize..."
msgstr "Sincronizar..."
-#: spyder/widgets/pathmanager.py:143
+#: spyder/widgets/pathmanager.py:144
msgid "Synchronize Spyder's path list with PYTHONPATH environment variable"
msgstr ""
"Sincronizar la lista de rutas de Spyder con la variable\n"
"de entorno PYTHONPATH"
-#: spyder/widgets/pathmanager.py:155
+#: spyder/widgets/pathmanager.py:156
msgid "Synchronize"
msgstr "Sincronizar"
-#: spyder/widgets/pathmanager.py:156
+#: spyder/widgets/pathmanager.py:157
msgid ""
"This will synchronize Spyder's path list with PYTHONPATH environment "
"variable for current user, allowing you to run your Python modules outside "
@@ -4419,11 +4614,19 @@ msgstr ""
"
¿Desea borrar los contenidos del PYTHONPATH antes de añadir la lista de "
"rutas de Spyder?"
-#: spyder/widgets/pathmanager.py:247
+#: spyder/widgets/pathmanager.py:248
msgid "Do you really want to remove selected path?"
msgstr "¿Realmente desea eliminar la ruta seleccionada?"
-#: spyder/widgets/pathmanager.py:268
+#: spyder/widgets/pathmanager.py:271
+msgid ""
+"You are using Python 2 and the path selected has Unicode characters. The new "
+"path will not be added."
+msgstr ""
+"Se encuentra usando Python 2 y la ruta seleccionada contiene caracteres "
+"Unicode. Su nueva ruta no será añadida."
+
+#: spyder/widgets/pathmanager.py:283
msgid ""
"This directory is already included in Spyder path list.
Do you want to "
"move it to the top of the list?"
@@ -4551,7 +4754,7 @@ msgstr "Crear"
msgid "Create new project"
msgstr "Crear nuevo proyecto"
-#: spyder/widgets/projects/type/__init__.py:216
+#: spyder/widgets/projects/type/__init__.py:223
msgid "Empty project"
msgstr "Proyecto vacío"
@@ -4563,80 +4766,107 @@ msgstr "Proyecto de Python"
msgid "Python package"
msgstr "Paquete de Python"
-#: spyder/widgets/pydocgui.py:110
+#: spyder/widgets/pydocgui.py:117
msgid "Module or package:"
msgstr "Módulo o paquete:"
-#: spyder/widgets/reporterror.py:121
-msgid "Spyder internal error"
-msgstr "Error interno de Spyder"
-
-#: spyder/widgets/reporterror.py:129
-msgid ""
-"Spyder has encountered an internal problem
\n"
-" Before reporting it, please consult our comprehensive \n"
-" Troubleshooting Guide \n"
-" which should help solve most issues, and search for \n"
-" known bugs matching your error \n"
-" message or problem description for a quicker solution.\n"
-"
\n"
-" If you don't find anything, please enter a detailed step-by-"
-"step \n"
-" description (in English) of what led up to the problem "
-"below. \n"
-" Issue reports without a clear way to reproduce them will be \n"
-" closed.
\n"
-" Thanks for helping us making Spyder better for everyone!\n"
-" "
-msgstr ""
-"Spyder a encontrado un problema interno
\n"
-" Antes de reportarlo, por favor consulte nuestra "
-"completa \n"
-" Guía de solución de problemas, \n"
-" la cual debería ayudarle a resolver la mayoría de problemas, y "
-"busqué \n"
-" reportes pasados que coincidan "
-"con su \n"
-" mensaje de error o problema para obtener una solución más "
-"rápida.\n"
-"
\n"
-" Si no encuentra nada relacionado, por favor introduzca una "
-"descripción \n"
-" paso a paso (en inglés) de que lo que pudo haber causado el "
-"problema \n"
-" en la parte de abajo. Los reportes que no tengan una forma "
-"clara de \n"
-" reproducirlos, serán cerrados.
\n"
-" Gracias por ayudarnos a hacer mejor Spyder para todos!\n"
-" "
-
-#: spyder/widgets/reporterror.py:163
-msgid "Hide all future errors this session"
-msgstr "Ocultar errores futuros en esta sesión"
-
-#: spyder/widgets/reporterror.py:171
+#: spyder/widgets/reporterror.py:128
+msgid "Issue reporter"
+msgstr "Reporte de error"
+
+#: spyder/widgets/reporterror.py:136
+msgid "Please fill the following information"
+msgstr "Por favor complete la siguiente información"
+
+#: spyder/widgets/reporterror.py:138
+msgid "Spyder has encountered an internal problem!"
+msgstr "Spyder ha encontrado un problema interno!"
+
+#: spyder/widgets/reporterror.py:140
+msgid ""
+"{title}
Before reporting this problem, please consult our "
+"comprehensive Troubleshooting Guide "
+"which should help solve most issues, and search for known bugs matching your error message or problem "
+"description for a quicker solution."
+msgstr ""
+"{title}
Antes de reportar este problema, por favor consulte "
+"nuestra comprehensiva Guía de solución de "
+"problemas, la cual debería ayudarle a resolver la mayoría de "
+"errores, y busque por problemas anteriores"
+"b> que sean similares a su mensaje de error o descripción del problema, para "
+"una solución más rápida."
+
+#: spyder/widgets/reporterror.py:158 spyder/widgets/reporterror.py:190
+msgid "{} more characters to go..."
+msgstr "{} más caracteres para terminar..."
+
+#: spyder/widgets/reporterror.py:162
+msgid "Title: {}"
+msgstr "Título: {}"
+
+#: spyder/widgets/reporterror.py:168
+msgid "Steps to reproduce: {}"
+msgstr "Pasos para reproducir: {}"
+
+#: spyder/widgets/reporterror.py:169
+msgid ""
+"Please enter a detailed step-by-step description (in English) of what led up "
+"to the problem below. Issue reports without a clear way to reproduce them "
+"will be closed."
+msgstr ""
+"Por favor introduzca una descripción detallada paso a paso (en Inglés) de lo "
+"que generó el problema en la parte de abajo. Los reportes de errores sin una "
+"forma clara de ser reproducidos serán cerrados."
+
+#: spyder/widgets/reporterror.py:194
+msgid "Hide all future errors during this session"
+msgstr "Ocultar todos los errores futuros durante esta sesión"
+
+#: spyder/widgets/reporterror.py:201
msgid "Submit to Github"
msgstr "Enviar a Github"
-#: spyder/widgets/reporterror.py:175 spyder/widgets/reporterror.py:227
+#: spyder/widgets/reporterror.py:205 spyder/widgets/reporterror.py:312
msgid "Show details"
msgstr "Mostrar detalles"
-#: spyder/widgets/reporterror.py:178
+#: spyder/widgets/reporterror.py:210
+#: spyder/widgets/variableexplorer/arrayeditor.py:740
+#: spyder/widgets/variableexplorer/collectionseditor.py:1397
+#: spyder/widgets/variableexplorer/dataframeeditor.py:756
+#: spyder/widgets/variableexplorer/texteditor.py:72
msgid "Close"
msgstr "Cerrar"
-#: spyder/widgets/reporterror.py:235
+#: spyder/widgets/reporterror.py:286
+msgid ""
+"An error occurred while trying to send the issue to Github automatically. "
+"Would you like to open it manually?
If so, please make sure to paste "
+"your clipboard into the issue report box that will appear in a new browser "
+"tab before clicking Submit on that page."
+msgstr ""
+"Ocurrió un error mientras se intentaba enviar el reporte automáticamente a "
+"Github. ¿Le gustaría abrir este reporte manualmente?
De ser así, por "
+"favor asegúrese de copiar el contenido de su portapapeles en el cuadro de "
+"reporte de errores que aparecerá en una nueva pestaña de su navegador web, "
+"antes de oprimir Submit en dicha página."
+
+#: spyder/widgets/reporterror.py:320
msgid "Hide details"
msgstr "Ocultar detalles"
-#: spyder/widgets/reporterror.py:243
+#: spyder/widgets/reporterror.py:329 spyder/widgets/reporterror.py:337
msgid "more characters to go..."
msgstr "más caracteres para terminar..."
-#: spyder/widgets/reporterror.py:245
-msgid "Submission enabled; thanks!"
-msgstr "Envío habilitado, gracias!"
+#: spyder/widgets/reporterror.py:331
+msgid "Description complete; thanks!"
+msgstr "La descripción está completa. Gracias!"
+
+#: spyder/widgets/reporterror.py:339
+msgid "Title complete; thanks!"
+msgstr "El título está completo. Gracias!"
#: spyder/widgets/shell.py:131
msgid "Save history log..."
@@ -4679,33 +4909,33 @@ msgstr "Atajos de teclado de Spyder"
#: spyder/widgets/sourcecode/codeeditor.py:101
msgid "Go to line:"
-msgstr "Ir a la línea"
+msgstr "Ir a la línea:"
#: spyder/widgets/sourcecode/codeeditor.py:109
msgid "Line count:"
msgstr "Número total de líneas:"
-#: spyder/widgets/sourcecode/codeeditor.py:1327
+#: spyder/widgets/sourcecode/codeeditor.py:1334
msgid "Breakpoint"
msgstr "Punto de interrupción"
-#: spyder/widgets/sourcecode/codeeditor.py:1328
+#: spyder/widgets/sourcecode/codeeditor.py:1335
msgid "Condition:"
msgstr "Condición:"
-#: spyder/widgets/sourcecode/codeeditor.py:1733
+#: spyder/widgets/sourcecode/codeeditor.py:1740
msgid "Code analysis"
msgstr "Análisis del código"
-#: spyder/widgets/sourcecode/codeeditor.py:1787
+#: spyder/widgets/sourcecode/codeeditor.py:1794
msgid "To do"
msgstr "To do"
-#: spyder/widgets/sourcecode/codeeditor.py:2147
+#: spyder/widgets/sourcecode/codeeditor.py:2154
msgid "Removal error"
msgstr "Error de remoción"
-#: spyder/widgets/sourcecode/codeeditor.py:2148
+#: spyder/widgets/sourcecode/codeeditor.py:2155
msgid ""
"It was not possible to remove outputs from this notebook. The error is:\n"
"\n"
@@ -4713,15 +4943,15 @@ msgstr ""
"No fue posible remover las outputs de este notebook. El error es:\n"
"\n"
-#: spyder/widgets/sourcecode/codeeditor.py:2696
+#: spyder/widgets/sourcecode/codeeditor.py:2703
msgid "Clear all ouput"
msgstr "Eliminar todas las salidas"
-#: spyder/widgets/sourcecode/codeeditor.py:2702
+#: spyder/widgets/sourcecode/codeeditor.py:2709
msgid "Go to definition"
msgstr "Ir a la definición"
-#: spyder/widgets/sourcecode/codeeditor.py:2735
+#: spyder/widgets/sourcecode/codeeditor.py:2742
msgid "Zoom reset"
msgstr "Restaurar"
@@ -4782,102 +5012,102 @@ msgstr ""
msgid "Close current tab"
msgstr "Cerrar pestaña actual"
-#: spyder/widgets/variableexplorer/arrayeditor.py:511
+#: spyder/widgets/variableexplorer/arrayeditor.py:509
msgid "It was not possible to copy values for this array"
msgstr "No fue posible copiar valores para este arreglo"
-#: spyder/widgets/variableexplorer/arrayeditor.py:546
-#: spyder/widgets/variableexplorer/arrayeditor.py:579
-#: spyder/widgets/variableexplorer/dataframeeditor.py:703
-#: spyder/widgets/variableexplorer/dataframeeditor.py:748
+#: spyder/widgets/variableexplorer/arrayeditor.py:545
+#: spyder/widgets/variableexplorer/arrayeditor.py:578
+#: spyder/widgets/variableexplorer/dataframeeditor.py:728
+#: spyder/widgets/variableexplorer/dataframeeditor.py:787
msgid "Format"
msgstr "Formato"
-#: spyder/widgets/variableexplorer/arrayeditor.py:551
-#: spyder/widgets/variableexplorer/dataframeeditor.py:707
+#: spyder/widgets/variableexplorer/arrayeditor.py:550
+#: spyder/widgets/variableexplorer/dataframeeditor.py:732
msgid "Resize"
msgstr "Redimensionar"
-#: spyder/widgets/variableexplorer/arrayeditor.py:554
-#: spyder/widgets/variableexplorer/dataframeeditor.py:711
+#: spyder/widgets/variableexplorer/arrayeditor.py:553
+#: spyder/widgets/variableexplorer/dataframeeditor.py:736
msgid "Background color"
msgstr "Color de fondo"
-#: spyder/widgets/variableexplorer/arrayeditor.py:580
-#: spyder/widgets/variableexplorer/dataframeeditor.py:749
+#: spyder/widgets/variableexplorer/arrayeditor.py:579
+#: spyder/widgets/variableexplorer/dataframeeditor.py:788
msgid "Float formatting"
msgstr "Formato de punto flotante"
-#: spyder/widgets/variableexplorer/arrayeditor.py:588
+#: spyder/widgets/variableexplorer/arrayeditor.py:587
msgid "Format (%s) is incorrect"
msgstr "El formato (%s) es incorrecto"
-#: spyder/widgets/variableexplorer/arrayeditor.py:624
+#: spyder/widgets/variableexplorer/arrayeditor.py:625
msgid "Arrays with more than 3 dimensions are not supported"
msgstr "Los arreglos de más de tres dimensiones no están soportados"
-#: spyder/widgets/variableexplorer/arrayeditor.py:628
+#: spyder/widgets/variableexplorer/arrayeditor.py:629
msgid "The 'xlabels' argument length do no match array column number"
msgstr ""
"El argumento de longitud 'xlabels' no coincide con el número de columnas del "
"arreglo"
-#: spyder/widgets/variableexplorer/arrayeditor.py:632
+#: spyder/widgets/variableexplorer/arrayeditor.py:633
msgid "The 'ylabels' argument length do no match array row number"
msgstr ""
"El argumento de longitud 'ylabels' no coincide con el número de filas del "
"arreglo"
-#: spyder/widgets/variableexplorer/arrayeditor.py:639
+#: spyder/widgets/variableexplorer/arrayeditor.py:640
msgid "%s arrays"
msgstr "Los arreglos %s"
-#: spyder/widgets/variableexplorer/arrayeditor.py:640
+#: spyder/widgets/variableexplorer/arrayeditor.py:641
msgid "%s are currently not supported"
msgstr "%s no están soportados por el momento"
-#: spyder/widgets/variableexplorer/arrayeditor.py:647
+#: spyder/widgets/variableexplorer/arrayeditor.py:648
msgid "NumPy array"
msgstr "Arreglo de NumPy"
-#: spyder/widgets/variableexplorer/arrayeditor.py:649
-#: spyder/widgets/variableexplorer/arrayeditor.py:806
+#: spyder/widgets/variableexplorer/arrayeditor.py:650
+#: spyder/widgets/variableexplorer/arrayeditor.py:828
msgid "Array editor"
msgstr "Editor de arreglos"
-#: spyder/widgets/variableexplorer/arrayeditor.py:651
+#: spyder/widgets/variableexplorer/arrayeditor.py:652
msgid "read only"
msgstr "sólo lectura"
-#: spyder/widgets/variableexplorer/arrayeditor.py:681
+#: spyder/widgets/variableexplorer/arrayeditor.py:685
msgid "Record array fields:"
msgstr "Campos del arreglo de records:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Data"
msgstr "Datos"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Mask"
msgstr "Máscara"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Masked data"
msgstr "Datos enmascarados"
-#: spyder/widgets/variableexplorer/arrayeditor.py:704
+#: spyder/widgets/variableexplorer/arrayeditor.py:708
msgid "Axis:"
msgstr "Eje:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:709
+#: spyder/widgets/variableexplorer/arrayeditor.py:713
msgid "Index:"
msgstr "Índice:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:722
+#: spyder/widgets/variableexplorer/arrayeditor.py:726
msgid "Warning: changes are applied separately"
msgstr "Advertencia: los cambios son aplicados de forma separada"
-#: spyder/widgets/variableexplorer/arrayeditor.py:723
+#: spyder/widgets/variableexplorer/arrayeditor.py:727
msgid ""
"For performance reasons, changes applied to masked array won't be reflected "
"in array's data (and vice-versa)."
@@ -4887,47 +5117,54 @@ msgstr ""
"verán reflejados en los datos del arreglo\n"
"(y viceversa)."
-#: spyder/widgets/variableexplorer/collectionseditor.py:126
+#: spyder/widgets/variableexplorer/arrayeditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:1392
+#: spyder/widgets/variableexplorer/dataframeeditor.py:751
+#: spyder/widgets/variableexplorer/texteditor.py:67
+msgid "Save and Close"
+msgstr "Guardar y Cerrar"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:151
msgid "Index"
msgstr "Índice"
-#: spyder/widgets/variableexplorer/collectionseditor.py:131
+#: spyder/widgets/variableexplorer/collectionseditor.py:156
msgid "Tuple"
msgstr "Tupla"
-#: spyder/widgets/variableexplorer/collectionseditor.py:134
+#: spyder/widgets/variableexplorer/collectionseditor.py:159
msgid "List"
msgstr "Lista"
-#: spyder/widgets/variableexplorer/collectionseditor.py:137
+#: spyder/widgets/variableexplorer/collectionseditor.py:162
msgid "Dictionary"
msgstr "Diccionario"
-#: spyder/widgets/variableexplorer/collectionseditor.py:139
+#: spyder/widgets/variableexplorer/collectionseditor.py:164
msgid "Key"
msgstr "Clave/Tecla"
-#: spyder/widgets/variableexplorer/collectionseditor.py:144
+#: spyder/widgets/variableexplorer/collectionseditor.py:169
msgid "Attribute"
msgstr "Atributo"
-#: spyder/widgets/variableexplorer/collectionseditor.py:148
+#: spyder/widgets/variableexplorer/collectionseditor.py:173
msgid "elements"
msgstr "elementos"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Size"
msgstr "Tamaño"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Type"
msgstr "Tipo"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Value"
msgstr "Valor"
-#: spyder/widgets/variableexplorer/collectionseditor.py:417
+#: spyder/widgets/variableexplorer/collectionseditor.py:450
msgid ""
"Opening this variable can be slow\n"
"\n"
@@ -4937,7 +5174,7 @@ msgstr ""
"\n"
"¿Desea continuar de todas formas?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:428
+#: spyder/widgets/variableexplorer/collectionseditor.py:461
msgid ""
"Spyder was unable to retrieve the value of this variable from the console."
"
The error mesage was:
%s"
@@ -4945,150 +5182,166 @@ msgstr ""
"Spyder no fue capaz de extraer el valor de esta variable de la terminal."
"
El mensaje de error fue:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:608
+#: spyder/widgets/variableexplorer/collectionseditor.py:643
msgid "Edit item"
msgstr "Editar ítem"
-#: spyder/widgets/variableexplorer/collectionseditor.py:609
+#: spyder/widgets/variableexplorer/collectionseditor.py:644
msgid "Unable to assign data to item.
Error message:
%s"
msgstr ""
"No fue posible asignarle los datos al ítem.
Mensaje de error:"
"
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:669
+#: spyder/widgets/variableexplorer/collectionseditor.py:705
msgid "Resize rows to contents"
msgstr "Ajustar filas a los contenidos"
-#: spyder/widgets/variableexplorer/collectionseditor.py:680
-#: spyder/widgets/variableexplorer/collectionseditor.py:1030
-#: spyder/widgets/variableexplorer/collectionseditor.py:1047
+#: spyder/widgets/variableexplorer/collectionseditor.py:716
+#: spyder/widgets/variableexplorer/collectionseditor.py:1066
+#: spyder/widgets/variableexplorer/collectionseditor.py:1083
msgid "Plot"
msgstr "Graficar"
-#: spyder/widgets/variableexplorer/collectionseditor.py:684
+#: spyder/widgets/variableexplorer/collectionseditor.py:720
msgid "Histogram"
msgstr "Histograma"
-#: spyder/widgets/variableexplorer/collectionseditor.py:688
+#: spyder/widgets/variableexplorer/collectionseditor.py:724
msgid "Show image"
msgstr "Mostrar como imagen"
-#: spyder/widgets/variableexplorer/collectionseditor.py:692
-#: spyder/widgets/variableexplorer/collectionseditor.py:1055
+#: spyder/widgets/variableexplorer/collectionseditor.py:728
+#: spyder/widgets/variableexplorer/collectionseditor.py:1091
msgid "Save array"
msgstr "Guardar arreglo"
-#: spyder/widgets/variableexplorer/collectionseditor.py:696
-#: spyder/widgets/variableexplorer/collectionseditor.py:994
-#: spyder/widgets/variableexplorer/collectionseditor.py:1002
+#: spyder/widgets/variableexplorer/collectionseditor.py:732
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Insert"
msgstr "Insertar"
-#: spyder/widgets/variableexplorer/collectionseditor.py:709
-#: spyder/widgets/variableexplorer/collectionseditor.py:955
+#: spyder/widgets/variableexplorer/collectionseditor.py:745
+#: spyder/widgets/variableexplorer/collectionseditor.py:991
msgid "Duplicate"
msgstr "Duplicar"
-#: spyder/widgets/variableexplorer/collectionseditor.py:932
+#: spyder/widgets/variableexplorer/collectionseditor.py:968
msgid "Do you want to remove the selected item?"
msgstr "¿Desea eliminar la variable seleccionada?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:933
+#: spyder/widgets/variableexplorer/collectionseditor.py:969
msgid "Do you want to remove all selected items?"
msgstr "¿Desea eliminar todas las variables seleccionadas?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:953
+#: spyder/widgets/variableexplorer/collectionseditor.py:989
msgid "New variable name:"
msgstr "Nuevo nombre de variable:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:956
+#: spyder/widgets/variableexplorer/collectionseditor.py:992
msgid "Variable name:"
msgstr "Nombre de variable:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:994
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
msgid "Key:"
msgstr "Nombre:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1002
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Value:"
msgstr "Valor:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1018
+#: spyder/widgets/variableexplorer/collectionseditor.py:1054
msgid "Import error"
msgstr "Error de importación"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1019
+#: spyder/widgets/variableexplorer/collectionseditor.py:1055
msgid "Please install matplotlib or guiqwt."
msgstr "Por favor instale Matplotlib o guiqwt."
-#: spyder/widgets/variableexplorer/collectionseditor.py:1031
+#: spyder/widgets/variableexplorer/collectionseditor.py:1067
msgid "Unable to plot data.
Error message:
%s"
msgstr ""
"No fue posible graficar los datos.
Mensaje de error:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1048
+#: spyder/widgets/variableexplorer/collectionseditor.py:1084
msgid "Unable to show image.
Error message:
%s"
msgstr ""
"No fue posible generar la gráfica.
Mensaje de error:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1071
+#: spyder/widgets/variableexplorer/collectionseditor.py:1097
+msgid "NumPy arrays"
+msgstr "Arreglos de NumPy"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1107
msgid "Unable to save array
Error message:
%s"
msgstr ""
"No fue posible guardar el arreglo
Mensaje de error:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1096
+#: spyder/widgets/variableexplorer/collectionseditor.py:1132
msgid "It was not possible to copy this array"
msgstr "No fue posible copiar este arreglo"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1121
+#: spyder/widgets/variableexplorer/collectionseditor.py:1144
+msgid "It was not possible to copy this dataframe"
+msgstr "No fue posible copiar este dataframe"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1166
msgid "Clipboard contents"
msgstr "Contenidos del portapapeles"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1136
+#: spyder/widgets/variableexplorer/collectionseditor.py:1181
msgid "Import from clipboard"
msgstr "Importar desde el portapapeles"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1138
+#: spyder/widgets/variableexplorer/collectionseditor.py:1183
msgid "Empty clipboard"
msgstr "Vaciar el portapapeles"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1139
+#: spyder/widgets/variableexplorer/collectionseditor.py:1184
msgid "Nothing to be imported from clipboard."
msgstr "No hay nada para importar desde el portapapeles."
-#: spyder/widgets/variableexplorer/dataframeeditor.py:597
+#: spyder/widgets/variableexplorer/dataframeeditor.py:321
+msgid ""
+"It is not possible to display this value because\n"
+"an error ocurred while trying to do it"
+msgstr ""
+"No es posible mostrar este valor porque ocurrió\n"
+"un error mientras se intentaba hacerlo"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To bool"
msgstr "A booleano"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:597
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To complex"
msgstr "A complejo"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:598
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To float"
msgstr "A flotante"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:598
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To int"
msgstr "A entero"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:599
+#: spyder/widgets/variableexplorer/dataframeeditor.py:623
msgid "To str"
msgstr "A cadena"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:683
+#: spyder/widgets/variableexplorer/dataframeeditor.py:707
msgid "%s editor"
msgstr "Editor de %s"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:717
+#: spyder/widgets/variableexplorer/dataframeeditor.py:742
msgid "Column min/max"
msgstr "Min/max de columna"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:757
+#: spyder/widgets/variableexplorer/dataframeeditor.py:796
msgid "Format ({}) is incorrect"
msgstr "El formato ({}) es incorrecto"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:761
+#: spyder/widgets/variableexplorer/dataframeeditor.py:800
msgid "Format ({}) should start with '%'"
msgstr "El formato ({}) debe iniciar con '%'"
@@ -5200,38 +5453,38 @@ msgstr ""
"No fue posible pasar al siguiente paso
Por favor revise sus "
"daros.
Mensaje de error:
%s"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:181
-#: spyder/widgets/variableexplorer/namespacebrowser.py:385
+#: spyder/widgets/variableexplorer/namespacebrowser.py:184
+#: spyder/widgets/variableexplorer/namespacebrowser.py:397
msgid "Import data"
msgstr "Importar datos"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:184
-#: spyder/widgets/variableexplorer/namespacebrowser.py:465
-#: spyder/widgets/variableexplorer/namespacebrowser.py:479
+#: spyder/widgets/variableexplorer/namespacebrowser.py:187
+#: spyder/widgets/variableexplorer/namespacebrowser.py:477
+#: spyder/widgets/variableexplorer/namespacebrowser.py:491
msgid "Save data"
msgstr "Guardar datos"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:189
+#: spyder/widgets/variableexplorer/namespacebrowser.py:192
msgid "Save data as..."
msgstr "Guardar datos como..."
-#: spyder/widgets/variableexplorer/namespacebrowser.py:201
+#: spyder/widgets/variableexplorer/namespacebrowser.py:204
msgid "Exclude references which name starts with an underscore"
msgstr ""
"Excluir variables cuyo nombre comienza\n"
"con un guión abajo"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:209
+#: spyder/widgets/variableexplorer/namespacebrowser.py:212
msgid "Exclude references which name is uppercase"
msgstr ""
"Excluir variables cuyo nombre está\n"
"por completo en mayúsculas"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:216
+#: spyder/widgets/variableexplorer/namespacebrowser.py:219
msgid "Exclude references which name starts with an uppercase character"
msgstr "Excluir variables cuyo nombre comienza en mayúsculas"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:224
+#: spyder/widgets/variableexplorer/namespacebrowser.py:227
msgid ""
"Exclude references to unsupported data types (i.e. which won't be handled/"
"saved correctly)"
@@ -5240,7 +5493,16 @@ msgstr ""
"(es decir aquellos que no pueden manejarse y guardarse\n"
"correctamente)"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:405
+#: spyder/widgets/variableexplorer/namespacebrowser.py:306
+msgid ""
+"The object you are trying to modify is too big to be sent back to the "
+"kernel. Therefore, your modifications won't take place."
+msgstr ""
+"El objeto que está tratando de modificar es demasiado grande para ser "
+"enviado de vuelta al núcleo. Por lo tanto, sus modificaciones no se "
+"aplicarán."
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:417
msgid ""
"Unsupported file extension '%s'
Would you like to import it "
"anyway (by selecting a known file format)?"
@@ -5248,38 +5510,29 @@ msgstr ""
"Extensión de archivo no soportada: '%s'
¿Desea importar el "
"archivo de todas formas (seleccionando un formato conocido)?"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:413
+#: spyder/widgets/variableexplorer/namespacebrowser.py:425
msgid "Open file as:"
msgstr "Abrir archivo como:"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:447
+#: spyder/widgets/variableexplorer/namespacebrowser.py:459
msgid "Unable to load '%s'
Error message:
%s"
msgstr "No fue posible cargar '%s'
Mensaje de error:
%s"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:480
+#: spyder/widgets/variableexplorer/namespacebrowser.py:492
msgid "Unable to save current workspace
Error message:
%s"
msgstr ""
"No fue posible guardar el espacio de trabajo actual
Mensaje de "
"error:
%s"
-#: spyder/widgets/variableexplorer/texteditor.py:74
+#: spyder/widgets/variableexplorer/texteditor.py:84
msgid "Text editor"
msgstr "Editor de texto"
-#: spyder/widgets/variableexplorer/utils.py:31
-msgid "View and edit DataFrames and Series in the Variable Explorer"
-msgstr "Ver y editar DataFrames y Series en el Explorador de Variables"
-
-#: spyder/widgets/variableexplorer/utils.py:36
-msgid "View and edit two and three dimensional arrays in the Variable Explorer"
-msgstr ""
-"Ver y editar arreglos bi y tridimensionales en el Explorador de Variables"
-
-#: spyder/workers/updates.py:90 spyder/workers/updates.py:92
+#: spyder/workers/updates.py:128 spyder/workers/updates.py:130
msgid "Unable to retrieve information."
-msgstr "No fue posible recuperar la información"
+msgstr "No fue posible recuperar la información."
-#: spyder/workers/updates.py:94
+#: spyder/workers/updates.py:132
msgid ""
"Unable to connect to the internet.
Make sure the connection is "
"working properly."
@@ -5287,9 +5540,156 @@ msgstr ""
"No fue posible conectarse a Internet.
Por favor asegúrese de que la "
"conexión está funcionando apropiadamente."
-#: spyder/workers/updates.py:97
+#: spyder/workers/updates.py:135
msgid "Unable to check for updates."
-msgstr "No fue posible buscar actualizaciones"
+msgstr "No fue posible buscar actualizaciones."
+
+#~ msgid "ViTables"
+#~ msgstr "ViTables"
+
+#~ msgid ""
+#~ "Update LANGUAGE_CODES (inside config/base.py) if a new translation has "
+#~ "been added to Spyder"
+#~ msgstr ""
+#~ "Actualice LANGUAGE_CODES (en config/base.py) si una nueva traducción se "
+#~ "añadió a Spyder"
+
+#~ msgid ""
+#~ "Please enter the connection info of the kernel you want to connect to. "
+#~ "For that you can either select its JSON connection file using the "
+#~ "Browse button, or write directly its id, in case it's a local "
+#~ "kernel (for example kernel-3764.json or just 3764)."
+#~ msgstr ""
+#~ "Por favor introduzca la información de conexión del núcleo al cual desea "
+#~ "conectarse. Para ello puede seleccionar su archivo de conexión JSON, "
+#~ "usando el botón Seleccionar, o escribir directamente su id, en "
+#~ "caso de que sea un núcleo local (por ejemplo, kernel-3764.json o "
+#~ "sólo 3764)"
+
+#~ msgid "Connection info:"
+#~ msgstr "Información de conexión:"
+
+#~ msgid "Ssh key"
+#~ msgstr "Clave ssh"
+
+#~ msgid "Password"
+#~ msgstr "Contraseña"
+
+#~ msgid "Select ssh key"
+#~ msgstr "Seleccionar clave ssh"
+
+#~ msgid "PyQt4 Reference Guide"
+#~ msgstr "Manual de referencia de PyQt4"
+
+#~ msgid "PyQt4 API Reference"
+#~ msgstr "Referencia del API de PyQt4"
+
+#~ msgid "Qt examples"
+#~ msgstr "Ejemplos de Qt"
+
+#~ msgid "Use the greedy completer"
+#~ msgstr "Usar el completado ambicioso"
+
+#~ msgid ""
+#~ "This error was most probably caused by installing Spyder in a directory "
+#~ "with non-ascii characters (i.e. characters with tildes, apostrophes or "
+#~ "non-latin symbols).
To fix it, please reinstall Spyder in a "
+#~ "different location."
+#~ msgstr ""
+#~ "Este error fue causado probablemente por la instalación de Spyder en un "
+#~ "directorio con caracteres no ascii (es decir, caracteres con tildes, "
+#~ "apóstrofes o símbolos no latinos). Para solucionarlo, por favor "
+#~ "reinstale Spyder en un lugar diferente."
+
+#~ msgid "Supported files"
+#~ msgstr "Archivos soportados"
+
+#~ msgid "All files (*.*)"
+#~ msgstr "Todos los archivos (*.*)"
+
+#~ msgid "Spyder data files"
+#~ msgstr "Archivos de datos de Spyder"
+
+#~ msgid "NumPy zip arrays"
+#~ msgstr "Arreglos comprimidos de NumPy"
+
+#~ msgid "Matlab files"
+#~ msgstr "Archivos de Matlab"
+
+#~ msgid "CSV text files"
+#~ msgstr "Archivos de texto CSV"
+
+#~ msgid "JPEG images"
+#~ msgstr "Imágenes JPEG"
+
+#~ msgid "PNG images"
+#~ msgstr "Imágenes PNG"
+
+#~ msgid "GIF images"
+#~ msgstr "Imágenes GIF"
+
+#~ msgid "TIFF images"
+#~ msgstr "Imágenes TIFF"
+
+#~ msgid "Pickle files"
+#~ msgstr "Archivos pickle"
+
+#~ msgid "JSON files"
+#~ msgstr "Archivos JSON"
+
+#~ msgid "Unsupported file type '%s'"
+#~ msgstr "Tipo de archivo no soportado '%s'"
+
+#~ msgid "Save"
+#~ msgstr "Guardar"
+
+#~ msgid "Spyder internal error"
+#~ msgstr "Error interno de Spyder"
+
+#~ msgid ""
+#~ "Spyder has encountered an internal problem
\n"
+#~ " Before reporting it, please consult our "
+#~ "comprehensive \n"
+#~ " Troubleshooting Guide \n"
+#~ " which should help solve most issues, and search for \n"
+#~ " known bugs matching your "
+#~ "error \n"
+#~ " message or problem description for a quicker solution.\n"
+#~ "
\n"
+#~ " If you don't find anything, please enter a detailed step-by-"
+#~ "step \n"
+#~ " description (in English) of what led up to the problem "
+#~ "below. \n"
+#~ " Issue reports without a clear way to reproduce them will "
+#~ "be \n"
+#~ " closed.
\n"
+#~ " Thanks for helping us making Spyder better for everyone!\n"
+#~ " "
+#~ msgstr ""
+#~ "Spyder a encontrado un problema interno
\n"
+#~ " Antes de reportarlo, por favor consulte nuestra "
+#~ "completa \n"
+#~ " Guía de solución de problemas"
+#~ "b>, \n"
+#~ " la cual debería ayudarle a resolver la mayoría de "
+#~ "problemas, y busqué \n"
+#~ " reportes pasados que coincidan "
+#~ "con su \n"
+#~ " mensaje de error o problema para obtener una solución más "
+#~ "rápida.\n"
+#~ "
\n"
+#~ " Si no encuentra nada relacionado, por favor introduzca una "
+#~ "descripción \n"
+#~ " paso a paso (en inglés) de que lo que pudo haber causado el "
+#~ "problema \n"
+#~ " en la parte de abajo. Los reportes que no tengan una forma "
+#~ "clara de \n"
+#~ " reproducirlos, serán cerrados.
\n"
+#~ " Gracias por ayudarnos a hacer mejor Spyder para todos!\n"
+#~ " "
+
+#~ msgid "Submission enabled; thanks!"
+#~ msgstr "Envío habilitado, gracias!"
#~ msgid "Pop up internal console when internal errors appear"
#~ msgstr "Mostrar la terminal interna cuando se produzcan errores"
@@ -5579,9 +5979,6 @@ msgstr "No fue posible buscar actualizaciones"
#~ msgid "the global working directory"
#~ msgstr "El directorio de trabajo global"
-#~ msgid "Files are created in:"
-#~ msgstr "Los archivos son creados en:"
-
#~ msgid "Change to file base directory"
#~ msgstr "Cambiarse al directorio base de un archivo"
@@ -5743,6 +6140,277 @@ msgstr "No fue posible buscar actualizaciones"
#~ "Actualizar\n"
#~ "periódicamente"
+#: spyder/plugins/breakpoints/plugin.py:45
+#, fuzzy
+msgid "Breakpoints"
+msgstr "Puntos de interrupción (Breakpoints)"
+
+#: spyder/plugins/breakpoints/plugin.py:80
+msgid "List breakpoints"
+msgstr "Listar puntos de interrupción"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "Condition"
+msgstr "Condición"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "File"
+msgstr "Archivo"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "Line"
+msgstr "Línea"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:201
+msgid "Clear this breakpoint"
+msgstr "Eliminar este punto"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:206
+#, fuzzy
+msgid "Edit this breakpoint"
+msgstr "Eliminar este punto"
+
+#: spyder/plugins/pylint/plugin.py:36
+msgid "Save file before analyzing it"
+msgstr "Guardar archivo antes de analizarlo"
+
+#: spyder/plugins/pylint/plugin.py:40
+msgid "The following option will be applied at next startup."
+msgstr "La siguiente opción será aplicada la próxima vez que se inicie Spyder"
+
+#: spyder/plugins/pylint/plugin.py:43
+msgid "History: "
+msgstr "Guardar"
+
+#: spyder/plugins/pylint/plugin.py:44
+msgid " results"
+msgstr " resultados"
+
+#: spyder/plugins/pylint/plugin.py:47 spyder/plugins/profiler/plugin.py:33
+msgid "Results"
+msgstr "Resultados"
+
+#: spyder/plugins/pylint/plugin.py:48
+msgid "Results are stored here:"
+msgstr "Los resultados se guardan en:"
+
+#: spyder/plugins/pylint/plugin.py:98
+#: spyder/plugins/pylint/widgets/pylintgui.py:83
+msgid "Static code analysis"
+msgstr "Análisis estático del código"
+
+#: spyder/plugins/pylint/plugin.py:133
+msgid "Run static code analysis"
+msgstr "Realizar análisis estático del código"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:117
+msgid "Results for "
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:122
+msgid "Convention"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:124
+msgid "Refactor"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:206
+msgid "Analyze"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:207
+msgid "Run analysis"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:212
+msgid "Stop current analysis"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:218
+#: spyder/plugins/pylint/widgets/pylintgui.py:288
+msgid "Select Python file"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:224
+#: spyder/plugins/profiler/widgets/profilergui.py:102
+msgid "Output"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:226
+msgid "Complete output"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:260
+msgid "Pylint script was not found. Please add \"%s\" to PATH."
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:263
+msgid "Please install pylint:"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:326
+msgid "Pylint output"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:465
+msgid "Source code has not been rated yet."
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:471
+msgid "Analysis did not succeed (see output for more details)."
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:484
+msgid "Global evaluation:"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:488
+msgid "previous run:"
+msgstr ""
+
+#: spyder/plugins/profiler/plugin.py:34
+msgid ""
+"Profiler plugin results (the output of python's profile/cProfile)\n"
+"are stored here:"
+msgstr ""
+"Los resultados del perfilador (es decir la salida de profile o cProfile)\n"
+"son guardados aquí:"
+
+#: spyder/plugins/profiler/plugin.py:75
+msgid "Profiler"
+msgstr "Perfilador (Profiler)"
+
+#: spyder/plugins/profiler/plugin.py:104
+#: spyder/plugins/profiler/widgets/profilergui.py:81
+msgid "Profile"
+msgstr "Perfilar (Profile)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:82
+msgid "Run profiler"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:88
+msgid "Stop current profiling"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:96
+#: spyder/plugins/profiler/widgets/profilergui.py:219
+msgid "Select Python script"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:104
+msgid "Show program's output"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:113
+msgid "Collapse one level up"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:118
+msgid "Expand one level down"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:124
+msgid "Save profiling data"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:126
+msgid "Load data"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:129
+msgid "Load profiling data for comparison"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:131
+msgid "Clear comparison"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:171
+msgid "Please install"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:172
+msgid "the Python profiler modules"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:179
+msgid "Save profiler result"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:182
+#: spyder/plugins/profiler/widgets/profilergui.py:188
+#, fuzzy
+msgid "Profiler result"
+msgstr "Perfilador (Profiler)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:187
+msgid "Select script to compare"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:227
+#: spyder/plugins/profiler/widgets/profilergui.py:232
+msgid "Profiler output"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:251
+msgid "Profiling, please wait..."
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:343
+msgid "Sorting data, please wait..."
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Function/Module"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Total Time"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Diff"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Calls"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Local Time"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:391
+msgid "File:line"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:565
+msgid "Function or module name"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:569
+msgid "Time in function (including sub-functions)"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:578
+msgid "Local time in function (not in sub-functions)"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:588
+msgid "Total number of calls (including recursion)"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:598
+msgid "File:line where function is defined"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:603
+msgid "recursion"
+msgstr ""
+
#~ msgid "Python(x,y)"
#~ msgstr "Python(x,y)"
@@ -6082,9 +6750,6 @@ msgstr "No fue posible buscar actualizaciones"
#~ msgid "tab"
#~ msgstr "tabulador"
-#~ msgid "Breakpoints"
-#~ msgstr "Puntos de interrupción (Breakpoints)"
-
#~ msgid "Exit"
#~ msgstr "Terminar"
@@ -6326,9 +6991,6 @@ msgstr "No fue posible buscar actualizaciones"
#~ msgid "Interpreter"
#~ msgstr "Intérprete"
-#~ msgid "Dedicated Python interpreter"
-#~ msgstr "Intérprete de Python dedicado"
-
#~ msgid "Open Python interpreter here"
#~ msgstr "Abrir intérprete de Python aquí"
diff --git a/spyder/locale/fr/LC_MESSAGES/spyder.mo b/spyder/locale/fr/LC_MESSAGES/spyder.mo
index 463bd51a43f..64b960b30d4 100644
Binary files a/spyder/locale/fr/LC_MESSAGES/spyder.mo and b/spyder/locale/fr/LC_MESSAGES/spyder.mo differ
diff --git a/spyder/locale/fr/LC_MESSAGES/spyder.po b/spyder/locale/fr/LC_MESSAGES/spyder.po
index 420c5d119b3..4b98d758aa6 100644
--- a/spyder/locale/fr/LC_MESSAGES/spyder.po
+++ b/spyder/locale/fr/LC_MESSAGES/spyder.po
@@ -1,62 +1,60 @@
# -*- coding: utf-8 -*-
-# Spyder's french translation file
-# Copyright (C) 2009-2011 Pierre Raybaut
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+#
+# Spyder's French gettext translation file
#
msgid ""
msgstr ""
"Project-Id-Version: 2.1\n"
-"POT-Creation-Date: 2018-02-19 11:56+-05\n"
-"PO-Revision-Date: 2018-02-21 23:36+0100\n"
-"Last-Translator: Melaine Euzenat \n"
+"POT-Creation-Date: 2018-11-13 11:49+-05\n"
+"PO-Revision-Date: 2019-03-16 13:03+0100\n"
+"Last-Translator: Carlos Cordoba \n"
"Language-Team: Python\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
-"X-Generator: Poedit 2.0.4\n"
+"X-Generator: Poedit 2.1.1\n"
-#: spyder/app/mainwindow.py:134
+#: spyder/app/mainwindow.py:139
msgid "Initializing..."
msgstr "Initialisation..."
-#: spyder/app/mainwindow.py:238
+#: spyder/app/mainwindow.py:252
msgid "Python2 documentation"
msgstr "Documentation de Python2"
-#: spyder/app/mainwindow.py:240
+#: spyder/app/mainwindow.py:254
msgid "Python3 documentation"
msgstr "Documentation de Python3"
-#: spyder/app/mainwindow.py:242
+#: spyder/app/mainwindow.py:256
msgid "Numpy and Scipy documentation"
msgstr "Documentation de Numpy et Scipy"
-#: spyder/app/mainwindow.py:244
+#: spyder/app/mainwindow.py:258
msgid "Matplotlib documentation"
msgstr "Documentation de Matplotlib"
-#: spyder/app/mainwindow.py:247
-msgid "PyQt4 Reference Guide"
-msgstr "Guide de référence de PyQt4"
-
-#: spyder/app/mainwindow.py:250
-msgid "PyQt4 API Reference"
-msgstr "Documentation de l'API de PyQt4"
-
-#: spyder/app/mainwindow.py:253
+#: spyder/app/mainwindow.py:261
msgid "PyQt5 Reference Guide"
msgstr "Guide de référence de PyQt5"
-#: spyder/app/mainwindow.py:256
+#: spyder/app/mainwindow.py:264
msgid "PyQt5 API Reference"
msgstr "Documentation de l'API de PyQt5"
-#: spyder/app/mainwindow.py:258
+#: spyder/app/mainwindow.py:266
msgid "WinPython"
msgstr "WinPython"
-#: spyder/app/mainwindow.py:518
+#: spyder/app/mainwindow.py:525
msgid ""
"An error occurred while creating a socket needed by Spyder. Please, try to "
"run as an Administrator from cmd.exe the following command and then restart "
@@ -68,174 +66,174 @@ msgstr ""
"administrateur dans une console cmd.exe, puis redémarrez votre ordinateur :"
"
netsh winsock reset
"
-#: spyder/app/mainwindow.py:550
+#: spyder/app/mainwindow.py:557
msgid "Close current pane"
msgstr "Fermer le volet courant"
-#: spyder/app/mainwindow.py:555
+#: spyder/app/mainwindow.py:562
msgid "Lock panes"
msgstr "Verrouiller les onglets"
-#: spyder/app/mainwindow.py:562
+#: spyder/app/mainwindow.py:569
msgid "Use next layout"
msgstr "Utiliser la disposition suivante"
-#: spyder/app/mainwindow.py:566
+#: spyder/app/mainwindow.py:573
msgid "Use previous layout"
msgstr "Utiliser la disposition précédente"
-#: spyder/app/mainwindow.py:576 spyder/widgets/editor.py:497
+#: spyder/app/mainwindow.py:583 spyder/widgets/editor.py:507
msgid "File switcher..."
msgstr "Commutateur de fichiers..."
-#: spyder/app/mainwindow.py:578
+#: spyder/app/mainwindow.py:585
msgid "Fast switch between files"
msgstr "Commutateur de fichiers"
-#: spyder/app/mainwindow.py:584
+#: spyder/app/mainwindow.py:591
msgid "Symbol finder..."
msgstr "Recherche de symboles…"
-#: spyder/app/mainwindow.py:586
+#: spyder/app/mainwindow.py:593
msgid "Fast symbol search in file"
msgstr "Recherche rapide de symboles dans le fichier"
-#: spyder/app/mainwindow.py:605 spyder/widgets/sourcecode/codeeditor.py:2673
+#: spyder/app/mainwindow.py:612 spyder/widgets/sourcecode/codeeditor.py:2680
msgid "Undo"
msgstr "Annuler"
-#: spyder/app/mainwindow.py:607 spyder/widgets/sourcecode/codeeditor.py:2676
+#: spyder/app/mainwindow.py:614 spyder/widgets/sourcecode/codeeditor.py:2683
msgid "Redo"
msgstr "Répéter"
-#: spyder/app/mainwindow.py:609 spyder/widgets/shell.py:123
-#: spyder/widgets/sourcecode/codeeditor.py:2682
-#: spyder/widgets/variableexplorer/arrayeditor.py:467
-#: spyder/widgets/variableexplorer/collectionseditor.py:674
-#: spyder/widgets/variableexplorer/dataframeeditor.py:592
+#: spyder/app/mainwindow.py:616 spyder/widgets/shell.py:123
+#: spyder/widgets/sourcecode/codeeditor.py:2689
+#: spyder/widgets/variableexplorer/arrayeditor.py:465
+#: spyder/widgets/variableexplorer/collectionseditor.py:710
+#: spyder/widgets/variableexplorer/dataframeeditor.py:616
msgid "Copy"
msgstr "Copier"
-#: spyder/app/mainwindow.py:611 spyder/widgets/shell.py:119
-#: spyder/widgets/sourcecode/codeeditor.py:2679
+#: spyder/app/mainwindow.py:618 spyder/widgets/shell.py:119
+#: spyder/widgets/sourcecode/codeeditor.py:2686
msgid "Cut"
msgstr "Couper"
-#: spyder/app/mainwindow.py:613 spyder/widgets/shell.py:127
-#: spyder/widgets/sourcecode/codeeditor.py:2685
-#: spyder/widgets/variableexplorer/collectionseditor.py:671
+#: spyder/app/mainwindow.py:620 spyder/widgets/shell.py:127
+#: spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/widgets/variableexplorer/collectionseditor.py:707
msgid "Paste"
msgstr "Coller"
-#: spyder/app/mainwindow.py:616 spyder/widgets/shell.py:140
-#: spyder/widgets/sourcecode/codeeditor.py:2688
+#: spyder/app/mainwindow.py:623 spyder/widgets/shell.py:140
+#: spyder/widgets/sourcecode/codeeditor.py:2695
msgid "Select All"
msgstr "Sélectionner tout"
-#: spyder/app/mainwindow.py:626 spyder/plugins/editor.py:1422
+#: spyder/app/mainwindow.py:633 spyder/plugins/editor.py:1421
msgid "&File"
msgstr "&Fichier"
-#: spyder/app/mainwindow.py:627 spyder/plugins/editor.py:1410
+#: spyder/app/mainwindow.py:634 spyder/plugins/editor.py:1409
msgid "File toolbar"
msgstr "Barre d'outils fichiers"
-#: spyder/app/mainwindow.py:631 spyder/plugins/editor.py:1423
+#: spyder/app/mainwindow.py:638 spyder/plugins/editor.py:1422
msgid "&Edit"
msgstr "&Édition"
-#: spyder/app/mainwindow.py:632 spyder/plugins/editor.py:1420
+#: spyder/app/mainwindow.py:639 spyder/plugins/editor.py:1419
msgid "Edit toolbar"
msgstr "Barre d'outils édition"
-#: spyder/app/mainwindow.py:636 spyder/plugins/editor.py:1424
+#: spyder/app/mainwindow.py:643 spyder/plugins/editor.py:1423
msgid "&Search"
msgstr "&Recherche"
-#: spyder/app/mainwindow.py:637 spyder/plugins/editor.py:1412
+#: spyder/app/mainwindow.py:644 spyder/plugins/editor.py:1411
msgid "Search toolbar"
msgstr "Barre d'outils de recherche"
-#: spyder/app/mainwindow.py:641 spyder/plugins/editor.py:1425
+#: spyder/app/mainwindow.py:648 spyder/plugins/editor.py:1424
msgid "Sour&ce"
msgstr "Sour&ce"
-#: spyder/app/mainwindow.py:642 spyder/plugins/editor.py:1414
+#: spyder/app/mainwindow.py:649 spyder/plugins/editor.py:1413
msgid "Source toolbar"
msgstr "Barre d'outils code source"
-#: spyder/app/mainwindow.py:646 spyder/plugins/editor.py:803
-#: spyder/plugins/editor.py:1426
+#: spyder/app/mainwindow.py:653 spyder/plugins/editor.py:803
+#: spyder/plugins/editor.py:1425
msgid "&Run"
msgstr "E&xécution"
-#: spyder/app/mainwindow.py:647 spyder/plugins/editor.py:1416
+#: spyder/app/mainwindow.py:654 spyder/plugins/editor.py:1415
msgid "Run toolbar"
msgstr "Barre d'outils exécution"
-#: spyder/app/mainwindow.py:651 spyder/plugins/editor.py:762
+#: spyder/app/mainwindow.py:658 spyder/plugins/editor.py:762
msgid "&Debug"
msgstr "&Déboguer"
-#: spyder/app/mainwindow.py:652 spyder/plugins/editor.py:1418
+#: spyder/app/mainwindow.py:659 spyder/plugins/editor.py:1417
msgid "Debug toolbar"
msgstr "Barre d'outils de débogage"
-#: spyder/app/mainwindow.py:656
+#: spyder/app/mainwindow.py:663
msgid "C&onsoles"
msgstr "C&onsoles"
-#: spyder/app/mainwindow.py:659
+#: spyder/app/mainwindow.py:666
msgid "&Projects"
msgstr "&Projets"
-#: spyder/app/mainwindow.py:662 spyder/plugins/editor.py:1427
+#: spyder/app/mainwindow.py:669 spyder/plugins/editor.py:1426
msgid "&Tools"
msgstr "Ou&tils"
-#: spyder/app/mainwindow.py:665 spyder/plugins/editor.py:1428
+#: spyder/app/mainwindow.py:672 spyder/plugins/editor.py:1427
msgid "&View"
msgstr "&Affichage"
-#: spyder/app/mainwindow.py:668 spyder/plugins/editor.py:1429
+#: spyder/app/mainwindow.py:675 spyder/plugins/editor.py:1428
msgid "&Help"
msgstr "A&ide"
-#: spyder/app/mainwindow.py:673
+#: spyder/app/mainwindow.py:680
msgid "Welcome to Spyder!"
msgstr "Bienvenue dans Spyder !"
-#: spyder/app/mainwindow.py:678
+#: spyder/app/mainwindow.py:685
msgid "Pre&ferences"
msgstr "Pré&férences"
-#: spyder/app/mainwindow.py:685 spyder/widgets/pathmanager.py:53
+#: spyder/app/mainwindow.py:692 spyder/widgets/pathmanager.py:54
msgid "PYTHONPATH manager"
msgstr "Gestionnaire de PYTHONPATH"
-#: spyder/app/mainwindow.py:688
+#: spyder/app/mainwindow.py:695
msgid "Python Path Manager"
msgstr "Gestionnaire de chemins d'accès Python"
-#: spyder/app/mainwindow.py:691
+#: spyder/app/mainwindow.py:698
msgid "Update module names list"
msgstr "Mise à jour de la liste des modules"
-#: spyder/app/mainwindow.py:694
+#: spyder/app/mainwindow.py:701
msgid "Refresh list of module names available in PYTHONPATH"
msgstr ""
"Mise à jour de la liste des modules disponibles notamment à travers "
"PYTHONPATH"
-#: spyder/app/mainwindow.py:697
+#: spyder/app/mainwindow.py:704
msgid "Reset Spyder to factory defaults"
msgstr "Rétablir les valeurs par défaut"
-#: spyder/app/mainwindow.py:702
+#: spyder/app/mainwindow.py:709
msgid "Current user environment variables..."
msgstr "Variables d'environnement de l'utilisateur..."
-#: spyder/app/mainwindow.py:704
+#: spyder/app/mainwindow.py:711
msgid ""
"Show and edit current user environment variables in Windows registry (i.e. "
"for all sessions)"
@@ -243,51 +241,43 @@ msgstr ""
"Afficher et modifier les variables d'environnement de l'utilisateur courant "
"dans Windows (c'est-à-dire directement dans la base de registre)"
-#: spyder/app/mainwindow.py:713 spyder/app/mainwindow.py:1137
+#: spyder/app/mainwindow.py:720 spyder/app/mainwindow.py:1115
msgid "External Tools"
msgstr "Outils externes"
-#: spyder/app/mainwindow.py:716
+#: spyder/app/mainwindow.py:723
msgid "WinPython control panel"
msgstr "Panneau de contrôle WinPython"
-#: spyder/app/mainwindow.py:725
+#: spyder/app/mainwindow.py:733
msgid "Qt Designer"
msgstr "Qt Designer"
-#: spyder/app/mainwindow.py:730
+#: spyder/app/mainwindow.py:737
msgid "Qt Linguist"
msgstr "Qt Linguist"
-#: spyder/app/mainwindow.py:736
-msgid "Qt examples"
-msgstr "Exemples Qt"
-
-#: spyder/app/mainwindow.py:756
+#: spyder/app/mainwindow.py:758
msgid "guidata examples"
msgstr "Exemples guidata"
-#: spyder/app/mainwindow.py:767
+#: spyder/app/mainwindow.py:769
msgid "guiqwt examples"
msgstr "Exemples guiqwt"
-#: spyder/app/mainwindow.py:772
+#: spyder/app/mainwindow.py:774
msgid "Sift"
msgstr "Sift"
-#: spyder/app/mainwindow.py:782
-msgid "ViTables"
-msgstr "ViTables"
-
-#: spyder/app/mainwindow.py:796
+#: spyder/app/mainwindow.py:792
msgid "Fullscreen mode"
msgstr "Mode plein écran"
-#: spyder/app/mainwindow.py:808
+#: spyder/app/mainwindow.py:804
msgid "Main toolbar"
msgstr "Barre d'outils principale"
-#: spyder/app/mainwindow.py:817
+#: spyder/app/mainwindow.py:813
msgid ""
"Spyder Internal Console\n"
"\n"
@@ -310,167 +300,172 @@ msgstr ""
"Ne l'utilisez pas pour exécuter votre propre code.\n"
"\n"
-#: spyder/app/mainwindow.py:834
+#: spyder/app/mainwindow.py:830
msgid "Loading help..."
msgstr "Chargement de l'aide en ligne..."
-#: spyder/app/mainwindow.py:841
+#: spyder/app/mainwindow.py:837
msgid "Loading outline explorer..."
msgstr "Chargement de l'explorateur de structure..."
-#: spyder/app/mainwindow.py:847
+#: spyder/app/mainwindow.py:843
msgid "Loading editor..."
msgstr "Chargement de l'éditeur..."
-#: spyder/app/mainwindow.py:853 spyder/plugins/console.py:141
-#: spyder/widgets/ipythonconsole/client.py:414
+#: spyder/app/mainwindow.py:849 spyder/plugins/console.py:141
+#: spyder/widgets/ipythonconsole/client.py:453
msgid "&Quit"
msgstr "&Quitter"
-#: spyder/app/mainwindow.py:855 spyder/plugins/console.py:143
+#: spyder/app/mainwindow.py:851 spyder/plugins/console.py:143
msgid "Quit"
msgstr "Quitter"
-#: spyder/app/mainwindow.py:859
+#: spyder/app/mainwindow.py:855
msgid "&Restart"
msgstr "&Redémarrer"
-#: spyder/app/mainwindow.py:861
+#: spyder/app/mainwindow.py:857
msgid "Restart"
msgstr "Redémarrer"
-#: spyder/app/mainwindow.py:875
+#: spyder/app/mainwindow.py:871
msgid "Loading file explorer..."
msgstr "Chargement de l'explorateur de fichiers..."
-#: spyder/app/mainwindow.py:882
+#: spyder/app/mainwindow.py:878
msgid "Loading history plugin..."
msgstr "Chargement du journal d'historique..."
-#: spyder/app/mainwindow.py:893
+#: spyder/app/mainwindow.py:889
msgid "Loading online help..."
msgstr "Chargement de l'aide en ligne..."
-#: spyder/app/mainwindow.py:898
+#: spyder/app/mainwindow.py:894
msgid "Loading project explorer..."
msgstr "Chargement de l'explorateur de projet..."
-#: spyder/app/mainwindow.py:911
+#: spyder/app/mainwindow.py:907
msgid "Loading namespace browser..."
msgstr "Chargement de l'explorateur d'espace de noms..."
-#: spyder/app/mainwindow.py:917
+#: spyder/app/mainwindow.py:913
msgid "Loading IPython console..."
msgstr "Chargement de la console IPython..."
-#: spyder/app/mainwindow.py:922
+#: spyder/app/mainwindow.py:918
msgid "Setting up main window..."
msgstr "Configuration de la fenêtre principale..."
-#: spyder/app/mainwindow.py:926
+#: spyder/app/mainwindow.py:922
msgid "Troubleshooting..."
msgstr "Résolution des problèmes..."
-#: spyder/app/mainwindow.py:928
+#: spyder/app/mainwindow.py:924
msgid "Dependencies..."
msgstr "Dépendances..."
-#: spyder/app/mainwindow.py:932
+#: spyder/app/mainwindow.py:928
msgid "Report issue..."
msgstr "Rapport d'erreur..."
-#: spyder/app/mainwindow.py:936
+#: spyder/app/mainwindow.py:932
msgid "Spyder support..."
msgstr "Support technique de Spyder..."
-#: spyder/app/mainwindow.py:939
+#: spyder/app/mainwindow.py:935
msgid "Check for updates..."
msgstr "Rechercher les mises à jour..."
-#: spyder/app/mainwindow.py:962
+#: spyder/app/mainwindow.py:940
msgid "Spyder documentation"
msgstr "Documentation de Spyder"
-#: spyder/app/mainwindow.py:970
+#: spyder/app/mainwindow.py:948
msgid "Spyder tutorial"
msgstr "Tutoriel de Spyder"
-#: spyder/app/mainwindow.py:975
+#: spyder/app/mainwindow.py:953
msgid "Shortcuts Summary"
msgstr "Sommaire des raccourcis"
-#: spyder/app/mainwindow.py:981
+#: spyder/app/mainwindow.py:959
msgid "Interactive tours"
msgstr "Visite interactive"
-#: spyder/app/mainwindow.py:1008
+#: spyder/app/mainwindow.py:986
msgid "Python documentation"
msgstr "Documentation de Python"
-#: spyder/app/mainwindow.py:1014
+#: spyder/app/mainwindow.py:992
msgid "IPython documentation"
msgstr "Documentation de IPython"
-#: spyder/app/mainwindow.py:1015
+#: spyder/app/mainwindow.py:993
msgid "Intro to IPython"
msgstr "Introduction à IPython"
-#: spyder/app/mainwindow.py:1017
+#: spyder/app/mainwindow.py:995
msgid "Quick reference"
msgstr "Référence rapide"
-#: spyder/app/mainwindow.py:1019
+#: spyder/app/mainwindow.py:997
msgid "Console help"
msgstr "Aide sur la console"
-#: spyder/app/mainwindow.py:1049
+#: spyder/app/mainwindow.py:1027
msgid "Installed Python modules"
msgstr "Modules Python installés"
-#: spyder/app/mainwindow.py:1053
+#: spyder/app/mainwindow.py:1031
msgid "Online documentation"
msgstr "Documentation en ligne"
-#: spyder/app/mainwindow.py:1066
+#: spyder/app/mainwindow.py:1044
msgid "Qt documentation"
msgstr "Documentation de Qt"
-#: spyder/app/mainwindow.py:1072
+#: spyder/app/mainwindow.py:1050
msgid "About %s..."
msgstr "À propos de %s..."
-#: spyder/app/mainwindow.py:1103
+#: spyder/app/mainwindow.py:1081
msgid "Panes"
msgstr "Volets"
-#: spyder/app/mainwindow.py:1105
+#: spyder/app/mainwindow.py:1083
msgid "Toolbars"
msgstr "Barres d'outils"
-#: spyder/app/mainwindow.py:1106
+#: spyder/app/mainwindow.py:1084
msgid "Window layouts"
msgstr "Dispositions de fenêtres personnalisées"
-#: spyder/app/mainwindow.py:1115 spyder/app/mainwindow.py:1943
-#: spyder/app/mainwindow.py:1944
+#: spyder/app/mainwindow.py:1093 spyder/app/mainwindow.py:1920
+#: spyder/app/mainwindow.py:1921
msgid "Show toolbars"
msgstr "Afficher les barres d'outils"
-#: spyder/app/mainwindow.py:1130
+#: spyder/app/mainwindow.py:1108
msgid "Attached console window (debugging)"
msgstr "Invite de commandes attachée (débogage)"
-#: spyder/app/mainwindow.py:1322 spyder/plugins/projects.py:254
-#: spyder/widgets/explorer.py:721 spyder/widgets/explorer.py:826
-#: spyder/widgets/variableexplorer/arrayeditor.py:587
-#: spyder/widgets/variableexplorer/collectionseditor.py:427
-#: spyder/widgets/variableexplorer/dataframeeditor.py:758
-#: spyder/widgets/variableexplorer/dataframeeditor.py:762
-#: spyder/widgets/variableexplorer/namespacebrowser.py:299
+#: spyder/app/mainwindow.py:1298 spyder/app/mainwindow.py:1988
+#: spyder/plugins/configdialog.py:1154 spyder/plugins/projects.py:269
+#: spyder/widgets/explorer.py:723 spyder/widgets/explorer.py:828
+#: spyder/widgets/reporterror.py:285
+#: spyder/widgets/variableexplorer/arrayeditor.py:586
+#: spyder/widgets/variableexplorer/collectionseditor.py:460
+#: spyder/widgets/variableexplorer/dataframeeditor.py:797
+#: spyder/plugins/pylint/widgets/pylintgui.py:128
+#: spyder/widgets/variableexplorer/namespacebrowser.py:311
+#: spyder/plugins/pylint/widgets/pylintgui.py:363
+#: spyder/plugins/pylint/widgets/pylintgui.py:391
+#: spyder/plugins/profiler/widgets/profilergui.py:295
msgid "Error"
msgstr "Erreur"
-#: spyder/app/mainwindow.py:1323
+#: spyder/app/mainwindow.py:1299
msgid ""
"You have missing dependencies!
%s
Please "
"install them to avoid this message.
Note: Spyder could "
@@ -489,38 +484,41 @@ msgstr ""
"Assurez-vous que les bogues trouvés ne résultent pas directement des "
"dépendances manquantes avant de signaler un nouveau problème."
-#: spyder/app/mainwindow.py:1779
+#: spyder/app/mainwindow.py:1756
msgid "Spyder Default Layout"
msgstr "Rétablir la disposition de fenêtres par défaut"
-#: spyder/app/mainwindow.py:1797
+#: spyder/app/mainwindow.py:1774
msgid "Save current layout"
msgstr "Enregistrer la disposition actuelle"
-#: spyder/app/mainwindow.py:1801
+#: spyder/app/mainwindow.py:1778
msgid "Layout preferences"
msgstr "Préférences"
-#: spyder/app/mainwindow.py:1805
+#: spyder/app/mainwindow.py:1782
msgid "Reset to spyder default"
msgstr "Rétablir les valeurs par défaut"
-#: spyder/app/mainwindow.py:1825 spyder/app/mainwindow.py:1847
-#: spyder/app/mainwindow.py:1913 spyder/app/mainwindow.py:1921
-#: spyder/app/mainwindow.py:2799 spyder/plugins/configdialog.py:1345
-#: spyder/plugins/ipythonconsole.py:131 spyder/plugins/ipythonconsole.py:927
-#: spyder/plugins/ipythonconsole.py:1386 spyder/plugins/maininterpreter.py:149
-#: spyder/plugins/maininterpreter.py:174 spyder/plugins/maininterpreter.py:203
-#: spyder/utils/environ.py:95 spyder/utils/environ.py:108
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:131
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:149
-#: spyder/widgets/variableexplorer/arrayeditor.py:510
-#: spyder/widgets/variableexplorer/collectionseditor.py:416
-#: spyder/widgets/variableexplorer/collectionseditor.py:1095
+#: spyder/app/mainwindow.py:1802 spyder/app/mainwindow.py:1824
+#: spyder/app/mainwindow.py:1890 spyder/app/mainwindow.py:1898
+#: spyder/app/mainwindow.py:2843 spyder/plugins/configdialog.py:1415
+#: spyder/plugins/ipythonconsole.py:134 spyder/plugins/ipythonconsole.py:987
+#: spyder/plugins/ipythonconsole.py:1439 spyder/plugins/maininterpreter.py:162
+#: spyder/plugins/maininterpreter.py:183 spyder/plugins/maininterpreter.py:212
+#: spyder/utils/environ.py:56 spyder/utils/environ.py:107
+#: spyder/utils/environ.py:120
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:140
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:158
+#: spyder/widgets/variableexplorer/arrayeditor.py:508
+#: spyder/widgets/variableexplorer/collectionseditor.py:449
+#: spyder/plugins/pylint/widgets/pylintgui.py:126
+#: spyder/widgets/variableexplorer/collectionseditor.py:1143
+#: spyder/widgets/variableexplorer/namespacebrowser.py:305
msgid "Warning"
msgstr "Attention"
-#: spyder/app/mainwindow.py:1826
+#: spyder/app/mainwindow.py:1803
msgid ""
"Window layout will be reset to default settings: this affects window "
"position, size and dockwidgets.\n"
@@ -530,7 +528,7 @@ msgstr ""
"défaut.\n"
"Souhaitez-vous continuer ?"
-#: spyder/app/mainwindow.py:1848
+#: spyder/app/mainwindow.py:1825
msgid ""
"Layout %s will be "
"overwritten. Do you want to "
@@ -539,7 +537,7 @@ msgstr ""
"La disposisiton de fenêtres%s sera réinitialisée. Souhaitez-vous "
"continuer ?"
-#: spyder/app/mainwindow.py:1914
+#: spyder/app/mainwindow.py:1891
msgid ""
"Error opening the custom layout. Please close Spyder and try again. If the "
"issue persists, then you must use 'Reset to Spyder default' from the layout "
@@ -549,44 +547,52 @@ msgstr ""
"essayer de nouveau. Si le problème persiste, utiliser la commande 'Rétablir "
"les valeurs par défaut' dans le menu des préférences."
-#: spyder/app/mainwindow.py:1922
+#: spyder/app/mainwindow.py:1899
msgid "Quick switch layout #%s has not yet been defined."
msgstr ""
"La disposition de fenêtre personnalisée #%s n'a pas encore été définie."
-#: spyder/app/mainwindow.py:1940 spyder/app/mainwindow.py:1941
+#: spyder/app/mainwindow.py:1917 spyder/app/mainwindow.py:1918
msgid "Hide toolbars"
msgstr "Masquer les barres d'outils"
-#: spyder/app/mainwindow.py:2256 spyder/app/mainwindow.py:2257
+#: spyder/app/mainwindow.py:1989
+msgid ""
+"{} is no longer a valid Spyder project! Since it is the current "
+"active project, it will be closed automatically."
+msgstr ""
+"{} n'est plus un projet Spyder valide ! Comme il s'agit du projet en "
+"cours, il va être automatiquement fermé."
+
+#: spyder/app/mainwindow.py:2252 spyder/app/mainwindow.py:2253
msgid "Maximize current pane"
msgstr "Agrandir le volet courant"
-#: spyder/app/mainwindow.py:2260
+#: spyder/app/mainwindow.py:2256
msgid "Restore current pane"
msgstr "Restaurer le volet courant"
-#: spyder/app/mainwindow.py:2261
+#: spyder/app/mainwindow.py:2257
msgid "Restore pane to its original size"
msgstr "Restaurer le volet à sa taille d'origine"
-#: spyder/app/mainwindow.py:2359
+#: spyder/app/mainwindow.py:2439
msgid "About %s"
msgstr "À propos de %s"
-#: spyder/app/mainwindow.py:2538 spyder/plugins/editor.py:168
+#: spyder/app/mainwindow.py:2579 spyder/plugins/editor.py:168
#: spyder/plugins/runconfig.py:354 spyder/plugins/runconfig.py:476
-#: spyder/utils/programs.py:286 spyder/widgets/explorer.py:344
+#: spyder/utils/programs.py:307 spyder/widgets/explorer.py:347
msgid "Run"
msgstr "Exécuter"
-#: spyder/app/mainwindow.py:2539
+#: spyder/app/mainwindow.py:2580
msgid "Running an external system terminal is not supported on platform %s."
msgstr ""
"L'exécution dans un terminal système externe n'est pas prise en charge sur "
"la plateforme %s."
-#: spyder/app/mainwindow.py:2800
+#: spyder/app/mainwindow.py:2844
msgid ""
"Spyder will restart and reset to default settings:
Do you want to "
"continue?"
@@ -594,15 +600,15 @@ msgstr ""
"Spyder va redémarrer et réinitialiser les paramètres par défaut :"
"
Souhaitez-vous néanmoins continuer ?"
-#: spyder/app/mainwindow.py:2928 spyder/widgets/helperwidgets.py:254
+#: spyder/app/mainwindow.py:2973 spyder/widgets/helperwidgets.py:254
msgid "Spyder updates"
msgstr "Mises à jour de Spyder"
-#: spyder/app/mainwindow.py:2929 spyder/plugins/configdialog.py:835
+#: spyder/app/mainwindow.py:2974 spyder/plugins/configdialog.py:888
msgid "Check for updates on startup"
msgstr "Vérifier les mises à jour au démarrage"
-#: spyder/app/mainwindow.py:2948
+#: spyder/app/mainwindow.py:2993
msgid ""
"
IMPORTANT NOTE: It seems that you are using Spyder with "
"Anaconda/Miniconda. Please don't use pip
to "
@@ -617,7 +623,7 @@ msgstr ""
"attendre la disponibilité de nouveaux paquets conda avant d'utiliser "
"conda
pour effectuer la mise à jour.
"
-#: spyder/app/mainwindow.py:2958
+#: spyder/app/mainwindow.py:3003
msgid ""
"Spyder %s is available!
Please use your package manager to "
"update Spyder or go to our Releases page to download this "
@@ -630,7 +636,7 @@ msgstr ""
"procéder pour mettre Spyder à jour, veuillez consulter notre documentation."
-#: spyder/app/mainwindow.py:2971
+#: spyder/app/mainwindow.py:3016
msgid "Spyder is up to date."
msgstr "Spyder est à jour."
@@ -765,8 +771,8 @@ msgstr ""
"interactive. En faisant un double-clic sur l'une d'elles, une nouvelle "
"fenêtre s'ouvre, où vous pouvez inspecter et modifier leur contenu."
-#: spyder/app/tour.py:179 spyder/plugins/help.py:484 spyder/plugins/help.py:937
-#: spyder/widgets/internalshell.py:270
+#: spyder/app/tour.py:179 spyder/plugins/help.py:482 spyder/plugins/help.py:931
+#: spyder/widgets/internalshell.py:271
msgid "Help"
msgstr "Aide"
@@ -833,7 +839,7 @@ msgstr "Visite d'introduction"
msgid "New features in version 3.0"
msgstr "Les nouveautés de la version 3.0"
-#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:446
+#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:474
msgid "Run code"
msgstr "Exécuter du code"
@@ -841,208 +847,205 @@ msgstr "Exécuter du code"
msgid "Go to step: "
msgstr "Allez à l'étape : "
-#: spyder/config/base.py:269
-msgid ""
-"Update LANGUAGE_CODES (inside config/base.py) if a new translation has been "
-"added to Spyder"
-msgstr ""
-"Mettre à jour LANGUAGE_CODES (à l'intérieur de config/base.py) si une "
-"nouvelle traduction a été ajoutée à Spyder"
-
-#: spyder/config/utils.py:24
+#: spyder/config/utils.py:25
msgid "Python files"
msgstr "Fichiers Python"
-#: spyder/config/utils.py:25
+#: spyder/config/utils.py:26
msgid "Cython/Pyrex files"
msgstr "Fichiers Cython/Pyrex"
-#: spyder/config/utils.py:26
+#: spyder/config/utils.py:27
msgid "C files"
msgstr "Fichiers C"
-#: spyder/config/utils.py:27
+#: spyder/config/utils.py:28
msgid "C++ files"
msgstr "Fichiers C++"
-#: spyder/config/utils.py:28
+#: spyder/config/utils.py:29
msgid "OpenCL files"
msgstr "Fichiers OpenCL"
-#: spyder/config/utils.py:29
+#: spyder/config/utils.py:30
msgid "Fortran files"
msgstr "Fichiers Fortran"
-#: spyder/config/utils.py:30
+#: spyder/config/utils.py:31
msgid "IDL files"
msgstr "Fichiers IDL"
-#: spyder/config/utils.py:31
+#: spyder/config/utils.py:32
msgid "MATLAB files"
msgstr "Fichiers MATLAB"
-#: spyder/config/utils.py:32
+#: spyder/config/utils.py:33
msgid "Julia files"
msgstr "Fichiers Julia"
-#: spyder/config/utils.py:33
+#: spyder/config/utils.py:34
msgid "Yaml files"
msgstr "Fichiers Yaml"
-#: spyder/config/utils.py:34
+#: spyder/config/utils.py:35
msgid "Patch and diff files"
msgstr "Fichiers patch et diff"
-#: spyder/config/utils.py:35
+#: spyder/config/utils.py:36
msgid "Batch files"
msgstr "Fichiers Batch"
-#: spyder/config/utils.py:36 spyder/utils/iofuncs.py:426
+#: spyder/config/utils.py:37
msgid "Text files"
msgstr "Fichiers texte"
-#: spyder/config/utils.py:37
+#: spyder/config/utils.py:38
msgid "reStructuredText files"
msgstr "Fichiers reST"
-#: spyder/config/utils.py:38
+#: spyder/config/utils.py:39
msgid "gettext files"
msgstr "Fichiers gettext"
-#: spyder/config/utils.py:39
+#: spyder/config/utils.py:40
msgid "NSIS files"
msgstr "Fichiers NSIS"
-#: spyder/config/utils.py:40
+#: spyder/config/utils.py:41
msgid "Web page files"
msgstr "Fichiers web"
-#: spyder/config/utils.py:41
+#: spyder/config/utils.py:42
msgid "XML files"
msgstr "Fichiers XML"
-#: spyder/config/utils.py:42
+#: spyder/config/utils.py:43
msgid "Javascript files"
msgstr "Fichiers Javascript"
-#: spyder/config/utils.py:43
+#: spyder/config/utils.py:44
msgid "Json files"
msgstr "Fichiers Json"
-#: spyder/config/utils.py:44
+#: spyder/config/utils.py:45
msgid "IPython notebooks"
msgstr "Notebooks IPython"
-#: spyder/config/utils.py:45
+#: spyder/config/utils.py:46
msgid "Enaml files"
msgstr "Fichiers Enaml"
-#: spyder/config/utils.py:46
+#: spyder/config/utils.py:47
msgid "Configuration files"
msgstr "Configurations"
-#: spyder/config/utils.py:48
+#: spyder/config/utils.py:49
msgid "Markdown files"
msgstr "Fichiers Markdown"
-#: spyder/config/utils.py:52 spyder/widgets/explorer.py:794
+#: spyder/config/utils.py:53 spyder/widgets/explorer.py:796
msgid "All files"
msgstr "Tous les fichiers"
-#: spyder/config/utils.py:134
+#: spyder/config/utils.py:138
msgid "Supported text files"
msgstr "Fichiers compatibles"
-#: spyder/plugins/__init__.py:511 spyder/plugins/editor.py:105
-#: spyder/plugins/editor.py:568 spyder/plugins/editor.py:1816
-#: spyder/plugins/help.py:117 spyder/plugins/help.py:385
-#: spyder/widgets/editor.py:534 spyder/widgets/sourcecode/codeeditor.py:98
-#: spyder/widgets/sourcecode/codeeditor.py:3222
+#: spyder/plugins/__init__.py:512 spyder/plugins/editor.py:105
+#: spyder/plugins/editor.py:568 spyder/plugins/editor.py:1830
+#: spyder/plugins/help.py:117 spyder/plugins/help.py:383
+#: spyder/widgets/editor.py:544 spyder/widgets/sourcecode/codeeditor.py:98
+#: spyder/widgets/sourcecode/codeeditor.py:3229
msgid "Editor"
msgstr "Éditeur"
-#: spyder/plugins/configdialog.py:144
+#: spyder/plugins/configdialog.py:146
msgid "Reset to defaults"
msgstr "Rétablir les valeurs par défaut"
-#: spyder/plugins/configdialog.py:156
+#: spyder/plugins/configdialog.py:158
msgid "Preferences"
msgstr "Préférences"
-#: spyder/plugins/configdialog.py:508
+#: spyder/plugins/configdialog.py:514
msgid "Invalid directory path"
msgstr "Chemin d'accès de répertoire incorrect"
-#: spyder/plugins/configdialog.py:511 spyder/plugins/configdialog.py:526
+#: spyder/plugins/configdialog.py:517 spyder/plugins/configdialog.py:532
#: spyder/plugins/runconfig.py:220 spyder/plugins/runconfig.py:268
-#: spyder/plugins/workingdirectory.py:240 spyder/widgets/explorer.py:705
-#: spyder/widgets/findinfiles.py:332 spyder/widgets/pathmanager.py:258
+#: spyder/plugins/workingdirectory.py:241 spyder/widgets/explorer.py:707
+#: spyder/widgets/findinfiles.py:347 spyder/widgets/pathmanager.py:259
#: spyder/widgets/projects/projectdialog.py:155
msgid "Select directory"
msgstr "Sélectionner un répertoire"
-#: spyder/plugins/configdialog.py:538
+#: spyder/plugins/configdialog.py:544 spyder/plugins/configdialog.py:704
msgid "Invalid file path"
msgstr "Chemin d'accès de fichier incorrect"
-#: spyder/plugins/configdialog.py:541 spyder/plugins/configdialog.py:558
+#: spyder/plugins/configdialog.py:547 spyder/plugins/configdialog.py:564
+#: spyder/plugins/configdialog.py:707
msgid "Select file"
msgstr "Sélectionner un fichier"
-#: spyder/plugins/configdialog.py:557
+#: spyder/plugins/configdialog.py:563
msgid "All files (*)"
msgstr "Tous les fichiers (*)"
-#: spyder/plugins/configdialog.py:630
+#: spyder/plugins/configdialog.py:636
msgid "Bold"
msgstr "Gras"
-#: spyder/plugins/configdialog.py:633
+#: spyder/plugins/configdialog.py:639
msgid "Italic"
msgstr "Italique"
-#: spyder/plugins/configdialog.py:687
+#: spyder/plugins/configdialog.py:728
msgid "Font: "
msgstr "Police : "
-#: spyder/plugins/configdialog.py:693
+#: spyder/plugins/configdialog.py:734
msgid "Size: "
msgstr "Taille : "
-#: spyder/plugins/configdialog.py:712
+#: spyder/plugins/configdialog.py:753
msgid "Font style"
msgstr "Police d'écriture"
-#: spyder/plugins/configdialog.py:789
+#: spyder/plugins/configdialog.py:830
msgid "Spyder needs to restart to change the following setting:"
msgstr "Il faut redémarrer Spyder pour changer l'option suivante :"
-#: spyder/plugins/configdialog.py:792
+#: spyder/plugins/configdialog.py:833
msgid "Spyder needs to restart to change the following settings:"
msgstr "Il faut redémarrer Spyder pour changer les options suivantes :"
-#: spyder/plugins/configdialog.py:794
+#: spyder/plugins/configdialog.py:835
msgid "Do you wish to restart now?"
msgstr "Souhaitez-vous redémarrer Spyder ?"
-#: spyder/plugins/configdialog.py:800
+#: spyder/plugins/configdialog.py:841
msgid "Information"
msgstr "Information"
-#: spyder/plugins/configdialog.py:814 spyder/plugins/configdialog.py:821
+#: spyder/plugins/configdialog.py:855 spyder/plugins/configdialog.py:862
#: spyder/widgets/projects/configdialog.py:74
msgid "General"
msgstr "Général"
-#: spyder/plugins/configdialog.py:824
-msgid "Language"
-msgstr "Langue"
+#: spyder/plugins/configdialog.py:866
+msgid "Language:"
+msgstr "Langue :"
-#: spyder/plugins/configdialog.py:827
+#: spyder/plugins/configdialog.py:874
+msgid "Rendering engine:"
+msgstr "Moteur de rendu :"
+
+#: spyder/plugins/configdialog.py:879
msgid "Use a single instance"
msgstr "Ouvrir une seule instance de Spyder"
-#: spyder/plugins/configdialog.py:829
+#: spyder/plugins/configdialog.py:881
msgid ""
"Set this to open external
Python files in an already running instance "
"(Requires a restart)"
@@ -1050,91 +1053,91 @@ msgstr ""
"Activer cette option afin que les fichiers ouverts
depuis l'extérieur "
"soit affichés dans une instance unique de Spyder
(redémarrage requis)"
-#: spyder/plugins/configdialog.py:832
+#: spyder/plugins/configdialog.py:885
msgid "Prompt when exiting"
msgstr "Demander à la sortie"
-#: spyder/plugins/configdialog.py:833
+#: spyder/plugins/configdialog.py:886
msgid "Show internal Spyder errors to report them to Github"
msgstr "Montrer les erreurs internes de Spyder pour les signaler sur Github"
-#: spyder/plugins/configdialog.py:852 spyder/plugins/editor.py:114
-#: spyder/plugins/ipythonconsole.py:290
+#: spyder/plugins/configdialog.py:914 spyder/plugins/editor.py:114
+#: spyder/plugins/ipythonconsole.py:301
#: spyder/widgets/projects/configdialog.py:81
msgid "Interface"
msgstr "Interface"
-#: spyder/plugins/configdialog.py:860
+#: spyder/plugins/configdialog.py:922
msgid "Qt windows style"
msgstr "Style de fenêtres Qt"
-#: spyder/plugins/configdialog.py:866
+#: spyder/plugins/configdialog.py:928
msgid "Icon theme"
msgstr "Thème des icônes"
-#: spyder/plugins/configdialog.py:870
+#: spyder/plugins/configdialog.py:932
msgid "Vertical title bars in panes"
msgstr "Barres de titre orientées verticalement"
-#: spyder/plugins/configdialog.py:872
+#: spyder/plugins/configdialog.py:934
msgid "Vertical tabs in panes"
msgstr "Languettes verticales dans onglets"
-#: spyder/plugins/configdialog.py:874
+#: spyder/plugins/configdialog.py:936
msgid "Animated toolbars and panes"
msgstr "Volets et barres d'outils animés"
-#: spyder/plugins/configdialog.py:876
+#: spyder/plugins/configdialog.py:938
msgid "Tear off menus"
msgstr "Menus détachables"
-#: spyder/plugins/configdialog.py:877
+#: spyder/plugins/configdialog.py:939
msgid "Set this to detach any
menu from the main window"
msgstr ""
"Activer cette option rend détachables tous les menus de la fenêtre principale"
-#: spyder/plugins/configdialog.py:879
+#: spyder/plugins/configdialog.py:941
msgid "Custom margin for panes:"
msgstr "Marges personnalisées pour les onglets :"
-#: spyder/plugins/configdialog.py:881
+#: spyder/plugins/configdialog.py:943
msgid "pixels"
msgstr "pixels"
-#: spyder/plugins/configdialog.py:888
+#: spyder/plugins/configdialog.py:950
msgid "Cursor blinking:"
msgstr "Clignotement du curseur :"
-#: spyder/plugins/configdialog.py:890
+#: spyder/plugins/configdialog.py:952
msgid "ms"
msgstr "ms"
-#: spyder/plugins/configdialog.py:929
+#: spyder/plugins/configdialog.py:991
msgid "Status bar"
msgstr "Barre d'état"
-#: spyder/plugins/configdialog.py:930
+#: spyder/plugins/configdialog.py:992
msgid "Show status bar"
msgstr "Afficher la barre d'état"
-#: spyder/plugins/configdialog.py:932
+#: spyder/plugins/configdialog.py:994
msgid "Show memory usage every"
msgstr "Afficher l'occupation mémoire toutes les"
-#: spyder/plugins/configdialog.py:934 spyder/plugins/configdialog.py:943
+#: spyder/plugins/configdialog.py:996 spyder/plugins/configdialog.py:1005
#: spyder/plugins/editor.py:139 spyder/plugins/editor.py:283
msgid " ms"
msgstr " ms"
-#: spyder/plugins/configdialog.py:941
+#: spyder/plugins/configdialog.py:1003
msgid "Show CPU usage every"
msgstr "Afficher la charge du CPU toutes les"
-#: spyder/plugins/configdialog.py:974
+#: spyder/plugins/configdialog.py:1036
msgid "Screen resolution"
msgstr "Résolution d’écran"
-#: spyder/plugins/configdialog.py:976
+#: spyder/plugins/configdialog.py:1038
msgid ""
"Configuration for high DPI screens
Please see {0}"
"a><> for more information about these options (in English)."
@@ -1142,31 +1145,31 @@ msgstr ""
"Configuration pour les écrans PPP/DPI élevés
Consultez {0}<> pour plus d’informations sur ces options (en anglais)."
-#: spyder/plugins/configdialog.py:986
+#: spyder/plugins/configdialog.py:1048
msgid "Normal"
msgstr "Normal"
-#: spyder/plugins/configdialog.py:990
+#: spyder/plugins/configdialog.py:1052
msgid "Enable auto high DPI scaling"
msgstr "Activer la mise à l'échelle pour les écrans à haute résolution"
-#: spyder/plugins/configdialog.py:993
+#: spyder/plugins/configdialog.py:1055
msgid "Set this for high DPI displays"
msgstr "Sélectionner pour les écrans à haute résolution"
-#: spyder/plugins/configdialog.py:997
+#: spyder/plugins/configdialog.py:1059
msgid "Set a custom high DPI scaling"
msgstr ""
"Définissez une mise à l’échelle personnalisée pour les écrans à haute "
"résolution"
-#: spyder/plugins/configdialog.py:1000
+#: spyder/plugins/configdialog.py:1062
msgid "Set this for high DPI displays when auto scaling does not work"
msgstr ""
"Réglez ceci pour les écrans à haute résolution élevés lorsque la mise à "
"l’échelle automatique ne fonctionne pas"
-#: spyder/plugins/configdialog.py:1006
+#: spyder/plugins/configdialog.py:1068
msgid ""
"Enter values for different screens separated by semicolons ';', float values "
"are supported"
@@ -1174,31 +1177,39 @@ msgstr ""
"Entrez les valeurs pour différents écrans séparés par des points-virgules "
"‘;’, les valeurs de virgule flottante sont prises en charge"
-#: spyder/plugins/configdialog.py:1033
+#: spyder/plugins/configdialog.py:1095
msgid "Plain text font"
msgstr "Police d'écriture du texte brut"
-#: spyder/plugins/configdialog.py:1039
+#: spyder/plugins/configdialog.py:1101
msgid "Rich text font"
msgstr "Police d'écriture du texte enrichi"
-#: spyder/plugins/configdialog.py:1042
+#: spyder/plugins/configdialog.py:1104
msgid "Fonts"
msgstr "Police de caractères"
-#: spyder/plugins/configdialog.py:1056
+#: spyder/plugins/configdialog.py:1118
msgid "Appearance"
msgstr "Apparence"
-#: spyder/plugins/configdialog.py:1058 spyder/plugins/ipythonconsole.py:579
+#: spyder/plugins/configdialog.py:1120 spyder/plugins/ipythonconsole.py:633
msgid "Advanced Settings"
msgstr "Options avancées"
-#: spyder/plugins/configdialog.py:1094
+#: spyder/plugins/configdialog.py:1155
+msgid ""
+"We're sorry but the following error occurred while trying to set your "
+"selected language:
{}"
+msgstr ""
+"Désolé mais l'erreur suivantes est survenue lors du changement de langue : "
+"
{}"
+
+#: spyder/plugins/configdialog.py:1164
msgid "Syntax coloring"
msgstr "Coloration syntaxique"
-#: spyder/plugins/configdialog.py:1107
+#: spyder/plugins/configdialog.py:1177
msgid ""
"Here you can select the color scheme used in the Editor and all other Spyder "
"plugins.
You can also edit the color schemes provided by Spyder or "
@@ -1209,52 +1220,52 @@ msgstr ""
"couleurs fournies par Spyder ou créer les vôtres en utilisant les options "
"fournies ci-dessous.
"
-#: spyder/plugins/configdialog.py:1112
+#: spyder/plugins/configdialog.py:1182
msgid "Edit selected"
msgstr "Modifier"
-#: spyder/plugins/configdialog.py:1113
+#: spyder/plugins/configdialog.py:1183
msgid "Create new scheme"
msgstr "Créer un nouveau thème"
-#: spyder/plugins/configdialog.py:1114 spyder/widgets/explorer.py:583
+#: spyder/plugins/configdialog.py:1184 spyder/widgets/explorer.py:582
#: spyder/widgets/projects/explorer.py:243 spyder/widgets/shell.py:136
msgid "Delete"
msgstr "Supprimer"
-#: spyder/plugins/configdialog.py:1117
+#: spyder/plugins/configdialog.py:1187
msgid "Reset"
msgstr "Réinitialiser"
-#: spyder/plugins/configdialog.py:1124
+#: spyder/plugins/configdialog.py:1194
msgid "Scheme:"
msgstr "Thème de coloration :"
-#: spyder/plugins/configdialog.py:1155
+#: spyder/plugins/configdialog.py:1225
msgid "Manage color schemes"
msgstr "Gérer les thèmes de coloration syntaxique"
-#: spyder/plugins/configdialog.py:1346
+#: spyder/plugins/configdialog.py:1416
msgid "Are you sure you want to delete this scheme?"
msgstr "Souhaitez-vous supprimer ce thème ?"
-#: spyder/plugins/configdialog.py:1463
+#: spyder/plugins/configdialog.py:1533
msgid "Text"
msgstr "Texte"
-#: spyder/plugins/configdialog.py:1465
+#: spyder/plugins/configdialog.py:1535
msgid "Highlight"
msgstr "Surligner"
-#: spyder/plugins/configdialog.py:1467
+#: spyder/plugins/configdialog.py:1537
msgid "Background"
msgstr "Fond"
-#: spyder/plugins/configdialog.py:1471
+#: spyder/plugins/configdialog.py:1541
msgid "Scheme name:"
msgstr "Nom du thème :"
-#: spyder/plugins/configdialog.py:1478
+#: spyder/plugins/configdialog.py:1548
msgid "Color scheme editor"
msgstr "Editeur de coloration syntaxique"
@@ -1291,7 +1302,7 @@ msgstr "Afficher le contenu de sys.path (lecture seule)"
msgid "Buffer..."
msgstr "Tampon..."
-#: spyder/plugins/console.py:163 spyder/plugins/history.py:43
+#: spyder/plugins/console.py:163 spyder/plugins/history.py:45
msgid "Set maximum line count"
msgstr "Modifier le nombre maximum de lignes"
@@ -1304,13 +1315,13 @@ msgid "Set external editor executable path"
msgstr "Modifier le chemin d'accès de l'éditeur externe"
#: spyder/plugins/console.py:170 spyder/plugins/editor.py:149
-#: spyder/plugins/help.py:152 spyder/plugins/help.py:360
-#: spyder/plugins/history.py:46 spyder/plugins/history.py:157
+#: spyder/plugins/help.py:152 spyder/plugins/help.py:358
+#: spyder/plugins/history.py:48 spyder/plugins/history.py:159
msgid "Wrap lines"
msgstr "Retour à la ligne automatique"
#: spyder/plugins/console.py:173 spyder/plugins/editor.py:185
-#: spyder/plugins/ipythonconsole.py:300
+#: spyder/plugins/ipythonconsole.py:311
msgid "Display balloon tips"
msgstr "Afficher des info-bulles"
@@ -1330,7 +1341,8 @@ msgstr "Options de la console interne"
msgid "Run Python script"
msgstr "Exécuter un script Python"
-#: spyder/plugins/console.py:266 spyder/widgets/explorer.py:809
+#: spyder/plugins/console.py:266 spyder/widgets/explorer.py:811
+#: spyder/plugins/profiler/widgets/profilergui.py:220
msgid "Python scripts"
msgstr "Scripts Python"
@@ -1363,8 +1375,8 @@ msgid "Show tab bar"
msgstr "Afficher la barre d'onglets"
#: spyder/plugins/editor.py:122 spyder/plugins/editor.py:199
-#: spyder/plugins/help.py:151 spyder/plugins/history.py:45
-#: spyder/plugins/ipythonconsole.py:332
+#: spyder/plugins/help.py:151 spyder/plugins/history.py:47
+#: spyder/plugins/ipythonconsole.py:349
msgid "Source code"
msgstr "Code source"
@@ -1608,8 +1620,8 @@ msgstr ""
msgid "Fix automatically and show warning message box"
msgstr "Réparer automatiquement et afficher un message d'avertissement"
-#: spyder/plugins/editor.py:357 spyder/plugins/ipythonconsole.py:573
-#: spyder/plugins/variableexplorer.py:35
+#: spyder/plugins/editor.py:357 spyder/plugins/ipythonconsole.py:627
+#: spyder/plugins/variableexplorer.py:47
msgid "Display"
msgstr "Affichage"
@@ -1625,8 +1637,8 @@ msgstr "Options avancées"
msgid "&New file..."
msgstr "&Nouveau fichier..."
-#: spyder/plugins/editor.py:645 spyder/widgets/explorer.py:786
-#: spyder/widgets/explorer.py:793
+#: spyder/plugins/editor.py:645 spyder/widgets/explorer.py:788
+#: spyder/widgets/explorer.py:795
msgid "New file"
msgstr "Nouveau fichier"
@@ -1642,8 +1654,8 @@ msgstr "Ouvert dernier fermé"
msgid "&Open..."
msgstr "&Ouvrir..."
-#: spyder/plugins/editor.py:662 spyder/plugins/editor.py:1867
-#: spyder/plugins/editor.py:1873
+#: spyder/plugins/editor.py:662 spyder/plugins/editor.py:1881
+#: spyder/plugins/editor.py:1887
msgid "Open file"
msgstr "Ouvrir un fichier"
@@ -1659,9 +1671,9 @@ msgstr "Revenir à la version du fichier enregistrée sur le disque"
msgid "&Save"
msgstr "&Enregistrer"
-#: spyder/plugins/editor.py:673 spyder/widgets/editor.py:1672
+#: spyder/plugins/editor.py:673 spyder/widgets/editor.py:1675
msgid "Save file"
-msgstr "Enregitrer un fichier"
+msgstr "Enregistrer un fichier"
#: spyder/plugins/editor.py:679
msgid "Sav&e all"
@@ -1740,6 +1752,7 @@ msgid "Set/Edit conditional breakpoint"
msgstr "Ajouter/modifier un point d'arrêt conditionnel"
#: spyder/plugins/editor.py:755
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:180
msgid "Clear breakpoints in all files"
msgstr "Supprimer les points d'arrêt dans tous les fichiers"
@@ -1785,8 +1798,10 @@ msgstr "Pas vers l'extérieur"
msgid "Run until current function or method returns"
msgstr "Exécuter jusqu'au retour de la fonction ou méthode"
-#: spyder/plugins/editor.py:796 spyder/widgets/findinfiles.py:438
-#: spyder/widgets/ipythonconsole/client.py:354
+#: spyder/plugins/editor.py:796 spyder/widgets/findinfiles.py:450
+#: spyder/widgets/ipythonconsole/client.py:393
+#: spyder/plugins/pylint/widgets/pylintgui.py:211
+#: spyder/plugins/profiler/widgets/profilergui.py:87
msgid "Stop"
msgstr "Arrêter"
@@ -1814,7 +1829,7 @@ msgstr "Exécuter de nouveau le &dernier script"
msgid "Run again last file"
msgstr "Exécuter de nouveau le dernier fichier"
-#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2720
+#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2727
msgid "Run &selection or current line"
msgstr "Exécuter la &sélection ou la ligne courante"
@@ -1822,7 +1837,7 @@ msgstr "Exécuter la &sélection ou la ligne courante"
msgid "Run selection or current line"
msgstr "Exécuter la sélection ou le bloc de lignes"
-#: spyder/plugins/editor.py:836 spyder/widgets/sourcecode/codeeditor.py:2708
+#: spyder/plugins/editor.py:836 spyder/widgets/sourcecode/codeeditor.py:2715
msgid "Run cell"
msgstr "Exécuter la cellule"
@@ -1834,7 +1849,7 @@ msgstr ""
"Exécuter la cellule courante \n"
"[Utiliser #%% pour délimiter les cellules]"
-#: spyder/plugins/editor.py:845 spyder/widgets/sourcecode/codeeditor.py:2712
+#: spyder/plugins/editor.py:845 spyder/widgets/sourcecode/codeeditor.py:2719
msgid "Run cell and advance"
msgstr "Exécuter la cellule et avancer"
@@ -1844,7 +1859,7 @@ msgstr ""
"Exécuter la cellule en cours d'édition et aller à la suivante\n"
"(voir la documentation de l'Editeur, pour plus de détails sur les cellules)"
-#: spyder/plugins/editor.py:854 spyder/widgets/sourcecode/codeeditor.py:2716
+#: spyder/plugins/editor.py:854 spyder/widgets/sourcecode/codeeditor.py:2723
msgid "Re-run last cell"
msgstr "Exécuter de nouveau le dernier cellule"
@@ -1912,11 +1927,11 @@ msgstr "Position suivante du curseur"
msgid "Go to next cursor position"
msgstr "Aller à la position suivante du curseur"
-#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Comment"
msgstr "Commenter"
-#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Uncomment"
msgstr "Décommenter"
@@ -2027,8 +2042,8 @@ msgstr "Nombre maximum de fichiers récents..."
msgid "Clear recent files list"
msgstr "Effacer la liste des fichiers récents"
-#: spyder/plugins/editor.py:1009 spyder/plugins/projects.py:107
-#: spyder/widgets/findinfiles.py:246
+#: spyder/plugins/editor.py:1009 spyder/plugins/projects.py:101
+#: spyder/widgets/findinfiles.py:261
msgid "Clear this list"
msgstr "Effacer cette liste"
@@ -2036,39 +2051,39 @@ msgstr "Effacer cette liste"
msgid "Open &recent"
msgstr "Fichiers &récents"
-#: spyder/plugins/editor.py:1675
+#: spyder/plugins/editor.py:1674
msgid "Spyder Editor"
msgstr "Éditeur de Spyder"
-#: spyder/plugins/editor.py:1676
+#: spyder/plugins/editor.py:1675
msgid "This is a temporary script file."
msgstr "Ceci est un script temporaire."
-#: spyder/plugins/editor.py:1745
+#: spyder/plugins/editor.py:1758
msgid "untitled"
msgstr "sanstitre"
-#: spyder/plugins/editor.py:1817
+#: spyder/plugins/editor.py:1831
msgid "Maximum number of recent files"
msgstr "Nombre maximum de fichiers récents"
-#: spyder/plugins/editor.py:1963
+#: spyder/plugins/editor.py:1977
msgid "Printing..."
msgstr "Impression en cours..."
-#: spyder/plugins/explorer.py:54
+#: spyder/plugins/explorer.py:55
msgid "File explorer"
msgstr "Explorateur de fichiers"
-#: spyder/plugins/findinfiles.py:120 spyder/widgets/findinfiles.py:913
+#: spyder/plugins/findinfiles.py:117 spyder/widgets/findinfiles.py:949
msgid "Find in files"
msgstr "Recherche dans des fichiers"
-#: spyder/plugins/findinfiles.py:145
+#: spyder/plugins/findinfiles.py:141
msgid "&Find in files"
msgstr "Rechercher dans des &fichiers"
-#: spyder/plugins/findinfiles.py:150
+#: spyder/plugins/findinfiles.py:146
msgid "Search text in multiple files"
msgstr "Rechercher une chaîne de caractères dans plusieurs fichiers à la fois"
@@ -2124,47 +2139,47 @@ msgstr "Sphinx %s n'est pas installé."
msgid "No further documentation available"
msgstr "Aucune documentation disponible"
-#: spyder/plugins/help.py:307 spyder/plugins/help.py:347
+#: spyder/plugins/help.py:307 spyder/plugins/help.py:345
msgid "No documentation available"
msgstr "Aucune documentation disponible"
-#: spyder/plugins/help.py:378
+#: spyder/plugins/help.py:376
msgid "Source"
msgstr "Source"
-#: spyder/plugins/help.py:385 spyder/plugins/runconfig.py:170
-#: spyder/plugins/runconfig.py:486 spyder/widgets/ipythonconsole/client.py:288
+#: spyder/plugins/help.py:383 spyder/plugins/runconfig.py:170
+#: spyder/plugins/runconfig.py:486 spyder/widgets/ipythonconsole/client.py:327
msgid "Console"
msgstr "Console"
-#: spyder/plugins/help.py:393
+#: spyder/plugins/help.py:391
msgid "Object"
msgstr "Objet"
-#: spyder/plugins/help.py:407
+#: spyder/plugins/help.py:405
msgid "Plain Text"
msgstr "Texte brut"
-#: spyder/plugins/help.py:411
+#: spyder/plugins/help.py:409
msgid "Show Source"
msgstr "Afficher les sources"
-#: spyder/plugins/help.py:415
+#: spyder/plugins/help.py:413
msgid "Rich Text"
msgstr "Texte enrichi"
-#: spyder/plugins/help.py:425
+#: spyder/plugins/help.py:423
msgid "Automatic import"
msgstr "Import automatique"
-#: spyder/plugins/help.py:437 spyder/plugins/history.py:106
-#: spyder/widgets/editor.py:728 spyder/widgets/explorer.py:1200
-#: spyder/widgets/ipythonconsole/client.py:378
-#: spyder/widgets/variableexplorer/namespacebrowser.py:148
+#: spyder/plugins/help.py:435 spyder/plugins/history.py:108
+#: spyder/widgets/editor.py:738 spyder/widgets/explorer.py:1205
+#: spyder/widgets/ipythonconsole/client.py:417
+#: spyder/widgets/variableexplorer/namespacebrowser.py:151
msgid "Options"
msgstr "Options"
-#: spyder/plugins/help.py:696
+#: spyder/plugins/help.py:692
msgid ""
"Here you can get help of any object by pressing %s in front of it, either on "
"the Editor or the Console.%sHelp can also be shown automatically after "
@@ -2176,37 +2191,37 @@ msgstr ""
"automatiquement après la saisie d'une parenthèse gauche après un objet si "
"l'option correspondante est activée dans %s."
-#: spyder/plugins/help.py:702
+#: spyder/plugins/help.py:698
msgid "Preferences > Help"
msgstr "Préférences > Aide"
-#: spyder/plugins/help.py:709
+#: spyder/plugins/help.py:705
msgid "Usage"
msgstr "Utilisation"
-#: spyder/plugins/help.py:710
+#: spyder/plugins/help.py:706
msgid "New to Spyder? Read our"
msgstr "Vous découvrez Spyder ? Lisez notre"
-#: spyder/plugins/help.py:711
+#: spyder/plugins/help.py:707
msgid "tutorial"
msgstr "Tutoriel"
-#: spyder/plugins/help.py:718
+#: spyder/plugins/help.py:714
msgid ""
"Please consider installing Sphinx to get documentation rendered in rich text."
msgstr ""
"Merci d'installer Sphinx pour obtenir la documentation en texte enrichi."
-#: spyder/plugins/help.py:891
+#: spyder/plugins/help.py:885
msgid "Lock"
msgstr "Verrouiller"
-#: spyder/plugins/help.py:891
+#: spyder/plugins/help.py:885
msgid "Unlock"
msgstr "Déverrouiller"
-#: spyder/plugins/help.py:938
+#: spyder/plugins/help.py:932
msgid ""
"The following error occured when calling Sphinx %s.
Incompatible "
"Sphinx version or doc string decoding failed.
Error message:
%s"
@@ -2215,63 +2230,68 @@ msgstr ""
"
Veuillez vérifier si cette version de Sphinx est bien prise en charge "
"par Spyder.
Message d'erreur :
%s"
-#: spyder/plugins/help.py:982
+#: spyder/plugins/help.py:976
msgid "No source code available."
msgstr "Aucun code source disponible."
-#: spyder/plugins/history.py:39
+#: spyder/plugins/history.py:41
msgid "Settings"
msgstr "Options"
-#: spyder/plugins/history.py:41
+#: spyder/plugins/history.py:43
msgid " entries"
msgstr " lignes"
-#: spyder/plugins/history.py:41
+#: spyder/plugins/history.py:43
msgid "History depth: "
msgstr "Taille de l'historique : "
-#: spyder/plugins/history.py:48
+#: spyder/plugins/history.py:50
msgid "Scroll automatically to last entry"
msgstr "Défiler automatiquement jusqu'à la dernière ligne"
-#: spyder/plugins/history.py:126
+#: spyder/plugins/history.py:128
msgid "History log"
msgstr "Historique"
-#: spyder/plugins/history.py:153
+#: spyder/plugins/history.py:153 spyder/plugins/pylint/plugin.py:115
msgid "History..."
msgstr "Historique..."
-#: spyder/plugins/history.py:155
+#: spyder/plugins/history.py:155 spyder/plugins/pylint/plugin.py:117
msgid "Set history maximum entries"
msgstr "Modifier le nombre d'entrées maximum de l'historique"
-#: spyder/plugins/history.py:260
+#: spyder/plugins/history.py:260 spyder/plugins/pylint/plugin.py:39
+#: spyder/plugins/pylint/plugin.py:160
msgid "History"
msgstr "Historique"
-#: spyder/plugins/history.py:261
+#: spyder/plugins/history.py:261 spyder/plugins/pylint/plugin.py:161
msgid "Maximum entries"
msgstr "Nombre maximum d'entrées"
-#: spyder/plugins/ipythonconsole.py:65
+#: spyder/plugins/ipythonconsole.py:64
msgid "Symbolic mathematics in the IPython Console"
msgstr "Mathématiques symboliques pour la console IPython"
-#: spyder/plugins/ipythonconsole.py:69
+#: spyder/plugins/ipythonconsole.py:68
msgid "Run Cython files in the IPython Console"
msgstr "Exécutez les fichiers Cython dans la console IPython"
-#: spyder/plugins/ipythonconsole.py:73
+#: spyder/plugins/ipythonconsole.py:72
msgid "Integrate the IPython console"
msgstr "Intégrer la console IPython"
-#: spyder/plugins/ipythonconsole.py:77
+#: spyder/plugins/ipythonconsole.py:76
msgid "IPython interactive python environment"
msgstr "Environnement python interactif IPython"
-#: spyder/plugins/ipythonconsole.py:128
+#: spyder/plugins/ipythonconsole.py:80
+msgid "Display 2D graphics in the IPython Console"
+msgstr "Affichage des graphes 2D dans la console IPython"
+
+#: spyder/plugins/ipythonconsole.py:131
msgid ""
"The authenticity of host %s can't be established. Are you sure you "
"want to continue connecting?"
@@ -2279,92 +2299,101 @@ msgstr ""
"L'identité du serveur %s ne peut pas être confirmée. Êtes-vous sûr de "
"vouloir poursuivre ?"
-#: spyder/plugins/ipythonconsole.py:140
+#: spyder/plugins/ipythonconsole.py:143
msgid "The authenticity of the host can't be established"
msgstr "L'identité du serveur ne peut pas être confirmée"
-#: spyder/plugins/ipythonconsole.py:147
+#: spyder/plugins/ipythonconsole.py:150
msgid "Tunnel '%s' failed to start"
msgstr "Impossible d'ouvrir le tunnel '%s'"
-#: spyder/plugins/ipythonconsole.py:152
+#: spyder/plugins/ipythonconsole.py:155
msgid "Could not connect to remote host"
msgstr "Impossible d'établir la connection au serveur distant"
-#: spyder/plugins/ipythonconsole.py:169 spyder/plugins/ipythonconsole.py:799
+#: spyder/plugins/ipythonconsole.py:172 spyder/plugins/ipythonconsole.py:846
msgid "Connect to an existing kernel"
msgstr "Connecter à un noyau existant"
-#: spyder/plugins/ipythonconsole.py:171
+#: spyder/plugins/ipythonconsole.py:174
msgid ""
-"Please enter the connection info of the kernel you want to connect to. For "
-"that you can either select its JSON connection file using the Browse"
-"tt> button, or write directly its id, in case it's a local kernel (for "
-"example kernel-3764.json or just 3764)."
+"Please select the JSON connection file (e.g. kernel-3764.json"
+"tt>) or enter the 4-digit ID (e.g. 3764) of the existing "
+"kernel to connect to, and enter the SSH host name and credentials if a "
+"remote kernel."
msgstr ""
-"Entrez les informations de connexion du noyau auquel vous voulez vous "
-"connecter. Pour cela vous pouvez soit sélectionner son fichier de connexion "
-"JSON en utilisant le bouton Parcourir, ou écrivez directement son "
-"identifiant si c'est un noyau local (Exemple : kernel-3764.json ou "
-"juste 3764)."
+"Sélectionner le fichier de connection JSON (ex. kernel-3764.json"
+"tt>) ou entrer l'identifiant à 4 chiffres (ex. 3764) du "
+"noyau existant à connecter, et entrer le nom de domaine SSH et les "
+"identifiants s'il s'agit d'un noyau distant."
-#: spyder/plugins/ipythonconsole.py:182
-msgid "Connection info:"
-msgstr "Information de connexion :"
+#: spyder/plugins/ipythonconsole.py:183
+msgid "Kernel ID/Connection file:"
+msgstr "Identifiant du noyau / Fichier de connection :"
-#: spyder/plugins/ipythonconsole.py:184
-msgid "Path to connection file or kernel id"
-msgstr "Chemin vers un fichier de connexion ou identifiant de noyau"
+#: spyder/plugins/ipythonconsole.py:185
+msgid "ID number or path to connection file"
+msgstr "Identifiant ou chemin vers le ficher de connection"
-#: spyder/plugins/ipythonconsole.py:186 spyder/plugins/ipythonconsole.py:203
+#: spyder/plugins/ipythonconsole.py:187 spyder/plugins/ipythonconsole.py:216
msgid "Browse"
msgstr "Parcourir"
-#: spyder/plugins/ipythonconsole.py:195
-msgid "This is a remote kernel"
-msgstr "Noyau distant"
+#: spyder/plugins/ipythonconsole.py:196
+msgid "This is a remote kernel (via SSH)"
+msgstr "Il s'agit d'un noyau distant (via SSH)"
#: spyder/plugins/ipythonconsole.py:199
+msgid ""
+"Note: If connecting to a remote kernel, only the SSH keyfile or"
+"i> the Password field need to be completed, unless the keyfile is protected "
+"with a passphrase."
+msgstr ""
+"Note : lors de la connection à un noyau distant, seul le fichier clé "
+"SSH ou le champ du mot de passe doit être complété, sauf si le "
+"fichier est protégé par une phrase secrète."
+
+#: spyder/plugins/ipythonconsole.py:207
msgid "username@hostname:port"
msgstr "utilisateur@hôte:port"
-#: spyder/plugins/ipythonconsole.py:202
-msgid "Path to ssh key file"
-msgstr "Chemin vers la clé ssh"
-
-#: spyder/plugins/ipythonconsole.py:211
-msgid "Password or ssh key passphrase"
-msgstr "Mot de passe ou passphrase de clé ssh"
+#: spyder/plugins/ipythonconsole.py:210
+msgid "Remote user password or SSH keyfile passphrase"
+msgstr "Mot de passe utilisateur distant ou phrase secrète du fichier clé SSH"
#: spyder/plugins/ipythonconsole.py:215
-msgid "Host name"
-msgstr "Nom d'hôte"
+msgid "Path to SSH keyfile (optional)"
+msgstr "Chemin vers le fichier clé SSH (optionnel)"
+
+#: spyder/plugins/ipythonconsole.py:224
+msgid "Host name:"
+msgstr "Nom d'hôte :"
-#: spyder/plugins/ipythonconsole.py:216
-msgid "Ssh key"
-msgstr "Clé ssh"
+#: spyder/plugins/ipythonconsole.py:225
+msgid "Password:"
+msgstr "Mot de passe :"
-#: spyder/plugins/ipythonconsole.py:217
-msgid "Password"
-msgstr "Mot de passe"
+#: spyder/plugins/ipythonconsole.py:226
+msgid "SSH keyfile:"
+msgstr "Fichier clé SSH :"
-#: spyder/plugins/ipythonconsole.py:246
-msgid "Open connection file"
-msgstr "Ouvrir un fichier de connexion IPython"
+#: spyder/plugins/ipythonconsole.py:257
+msgid "Select kernel connection file"
+msgstr "Sélectionner un fichier de connection au noyau"
-#: spyder/plugins/ipythonconsole.py:251
-msgid "Select ssh key"
-msgstr "Sélectionner une clé ssh"
+#: spyder/plugins/ipythonconsole.py:262
+msgid "Select SSH keyfile"
+msgstr "Sélectionner le fichier clé SSH"
-#: spyder/plugins/ipythonconsole.py:284 spyder/plugins/ipythonconsole.py:734
+#: spyder/plugins/ipythonconsole.py:295 spyder/plugins/ipythonconsole.py:780
msgid "IPython console"
msgstr "Console IPython"
-#: spyder/plugins/ipythonconsole.py:291
+#: spyder/plugins/ipythonconsole.py:302
msgid "Display initial banner"
msgstr "Afficher le message d'accueil"
-#: spyder/plugins/ipythonconsole.py:292
+#: spyder/plugins/ipythonconsole.py:303
msgid ""
"This option lets you hide the message shown at\n"
"the top of the console when it's opened."
@@ -2372,11 +2401,11 @@ msgstr ""
"Cette option permet de masquer la message d'accueil\n"
"qui s'affiche à l'ouverture de la console."
-#: spyder/plugins/ipythonconsole.py:294
+#: spyder/plugins/ipythonconsole.py:305
msgid "Use a pager to display additional text inside the console"
msgstr "Utiliser un pager pour afficher l'aide"
-#: spyder/plugins/ipythonconsole.py:296
+#: spyder/plugins/ipythonconsole.py:307
msgid ""
"Useful if you don't want to fill the console with long help or completion "
"texts.\n"
@@ -2385,17 +2414,17 @@ msgstr ""
"Le pager permet d'éviter de remplir la console de texte d'aide.\n"
"Remarque : utiliser la touche Q pour quitter le pager."
-#: spyder/plugins/ipythonconsole.py:301
+#: spyder/plugins/ipythonconsole.py:312
msgid "Ask for confirmation before closing"
msgstr "Demander confirmation avant de fermer une console"
-#: spyder/plugins/ipythonconsole.py:304
+#: spyder/plugins/ipythonconsole.py:315
msgid "Ask for confirmation before removing all user-defined variables"
msgstr ""
"Demander confirmation avant de supprimer les variables définies par "
"l'utilisateur"
-#: spyder/plugins/ipythonconsole.py:307
+#: spyder/plugins/ipythonconsole.py:318
msgid ""
"This option lets you hide the warning message shown\n"
"when resetting the namespace from Spyder."
@@ -2403,44 +2432,56 @@ msgstr ""
"Cette option permet de masquer le message de confirmation\n"
"lors de la suppression des variables de Spyder."
-#: spyder/plugins/ipythonconsole.py:309
-#: spyder/widgets/ipythonconsole/client.py:317
+#: spyder/plugins/ipythonconsole.py:320
+#: spyder/widgets/ipythonconsole/client.py:356
msgid "Show elapsed time"
msgstr "Afficher le temps écoulé"
-#: spyder/plugins/ipythonconsole.py:320
+#: spyder/plugins/ipythonconsole.py:322
+msgid "Ask for confirmation before restarting"
+msgstr "Demander confirmation avant de redémarrer"
+
+#: spyder/plugins/ipythonconsole.py:324
+msgid ""
+"This option lets you hide the warning message shown\n"
+"when restarting the kernel."
+msgstr ""
+"Cette option permet de masquer le message d'alerte affiché\n"
+"lors du redémarrage du noyau."
+
+#: spyder/plugins/ipythonconsole.py:337
msgid "Completion Type"
msgstr "Type de complétion de code"
-#: spyder/plugins/ipythonconsole.py:321
+#: spyder/plugins/ipythonconsole.py:338
msgid "Decide what type of completion to use"
msgstr "Sélectionner le type de completion de code a utiliser"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Graphical"
msgstr "Graphique"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Plain"
msgstr "Simple"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Terminal"
msgstr "Terminal"
-#: spyder/plugins/ipythonconsole.py:324
+#: spyder/plugins/ipythonconsole.py:341
msgid "Completion:"
msgstr "Complétion de code :"
-#: spyder/plugins/ipythonconsole.py:334
+#: spyder/plugins/ipythonconsole.py:351
msgid " lines"
msgstr " lignes"
-#: spyder/plugins/ipythonconsole.py:334
+#: spyder/plugins/ipythonconsole.py:351
msgid "Buffer: "
msgstr "Tampon : "
-#: spyder/plugins/ipythonconsole.py:336
+#: spyder/plugins/ipythonconsole.py:353
msgid ""
"Set the maximum number of lines of text shown in the\n"
"console before truncation. Specifying -1 disables it\n"
@@ -2449,41 +2490,43 @@ msgstr ""
"Nombre maximum de lignes de texte affichées dans la console avant troncature "
"(saisir -1 désactive cette dernière, ce qui est fortement déconseillé)."
-#: spyder/plugins/ipythonconsole.py:345
+#: spyder/plugins/ipythonconsole.py:362
msgid "Support for graphics (Matplotlib)"
msgstr "Prise en charge des graphes (Matplotlib)"
-#: spyder/plugins/ipythonconsole.py:346
+#: spyder/plugins/ipythonconsole.py:363
msgid "Activate support"
msgstr "Activer"
-#: spyder/plugins/ipythonconsole.py:347
+#: spyder/plugins/ipythonconsole.py:364
msgid "Automatically load Pylab and NumPy modules"
msgstr "Importer automatiquement Pylab et NumPy"
-#: spyder/plugins/ipythonconsole.py:350
+#: spyder/plugins/ipythonconsole.py:367
msgid ""
"This lets you load graphics support without importing \n"
"the commands to do plots. Useful to work with other\n"
"plotting libraries different to Matplotlib or to develop \n"
"GUIs with Spyder."
msgstr ""
-"Import automatique de toutes les fonctions de représentation graphique et de "
-"calcul numérique"
+"Import automatique des fonctions de représentations\n"
+"graphiques. Très utile pour travailler avec des librairies\n"
+"différentes de matplotlib ou pour développer des GUIs\n"
+"avec Spyder."
-#: spyder/plugins/ipythonconsole.py:365
+#: spyder/plugins/ipythonconsole.py:382
msgid "Inline"
msgstr "En ligne"
-#: spyder/plugins/ipythonconsole.py:366
+#: spyder/plugins/ipythonconsole.py:383
msgid "Automatic"
msgstr "Automatique"
-#: spyder/plugins/ipythonconsole.py:367
+#: spyder/plugins/ipythonconsole.py:384
msgid "Graphics backend"
msgstr "Sortie graphique"
-#: spyder/plugins/ipythonconsole.py:368
+#: spyder/plugins/ipythonconsole.py:385
msgid ""
"Decide how graphics are going to be displayed in the console. If unsure, "
"please select %s to put graphics inside the console or %s to "
@@ -2494,60 +2537,78 @@ msgstr ""
"des graphes tandis que le mode %s permet d'interagir avec (zoom/pan) "
"dans une fenêtre séparée."
-#: spyder/plugins/ipythonconsole.py:388
+#: spyder/plugins/ipythonconsole.py:405
msgid "Backend:"
msgstr "Sortie :"
-#: spyder/plugins/ipythonconsole.py:390
+#: spyder/plugins/ipythonconsole.py:407
msgid "This option will be applied the next time a console is opened."
msgstr ""
"Cette option sera prise en compte lors de la prochaine ouverture de console."
-#: spyder/plugins/ipythonconsole.py:401
+#: spyder/plugins/ipythonconsole.py:418
msgid "Inline backend"
msgstr "Backend intégré"
-#: spyder/plugins/ipythonconsole.py:402
+#: spyder/plugins/ipythonconsole.py:419
msgid "Decide how to render the figures created by this backend"
msgstr "Option relative au rendu des figures dans ce backend"
-#: spyder/plugins/ipythonconsole.py:406
+#: spyder/plugins/ipythonconsole.py:423
msgid "Format:"
msgstr "Format :"
-#: spyder/plugins/ipythonconsole.py:409
+#: spyder/plugins/ipythonconsole.py:427
msgid "Resolution:"
msgstr "Résolution :"
-#: spyder/plugins/ipythonconsole.py:409
+#: spyder/plugins/ipythonconsole.py:427
msgid "dpi"
msgstr "ppp"
-#: spyder/plugins/ipythonconsole.py:411
+#: spyder/plugins/ipythonconsole.py:429
msgid "Only used when the format is PNG. Default is 72"
msgstr "Utilisé uniquement dans le cas du format PNG. Par défaut : 72"
-#: spyder/plugins/ipythonconsole.py:414
+#: spyder/plugins/ipythonconsole.py:432
msgid "Width:"
msgstr "Largeur :"
-#: spyder/plugins/ipythonconsole.py:414 spyder/plugins/ipythonconsole.py:418
+#: spyder/plugins/ipythonconsole.py:432 spyder/plugins/ipythonconsole.py:436
msgid "inches"
msgstr "pouces"
-#: spyder/plugins/ipythonconsole.py:416
+#: spyder/plugins/ipythonconsole.py:434
msgid "Default is 6"
msgstr "Par défaut : 6"
-#: spyder/plugins/ipythonconsole.py:418
+#: spyder/plugins/ipythonconsole.py:436
msgid "Height:"
msgstr "Hauteur :"
-#: spyder/plugins/ipythonconsole.py:420
+#: spyder/plugins/ipythonconsole.py:438
msgid "Default is 4"
msgstr "Par défaut : 4"
-#: spyder/plugins/ipythonconsole.py:447
+#: spyder/plugins/ipythonconsole.py:440
+msgid "Use a tight layout for inline plots"
+msgstr "Utiliser une disposition ajustée pour les graphes en ligne"
+
+#: spyder/plugins/ipythonconsole.py:442
+msgid ""
+"Sets bbox_inches to \"tight\" when\n"
+"plotting inline with matplotlib.\n"
+"When enabled, can cause discrepancies\n"
+"between the image displayed inline and\n"
+"that created using savefig."
+msgstr ""
+"Définir bbox_inches à \"ajusté\" pour\n"
+"les graphes en ligne avec matplotlib.\n"
+"Lorsqu'activée, cette option peut être source\n"
+"de différences entre l'image en ligne et\n"
+"celle créée lors de la sauvegarde de la figure."
+
+#: spyder/plugins/ipythonconsole.py:475
msgid ""
"You can run several lines of code when a console is started. Please "
"introduce each one separated by commas, for example:
import os, import "
@@ -2557,49 +2618,73 @@ msgstr ""
"console. Veuillez séparer deux lignes consécutives par une virgule - par "
"exemple :
import os, import sys"
-#: spyder/plugins/ipythonconsole.py:453
+#: spyder/plugins/ipythonconsole.py:481
msgid "Lines:"
msgstr "Lignes :"
-#: spyder/plugins/ipythonconsole.py:462
+#: spyder/plugins/ipythonconsole.py:490
msgid "Run a file"
msgstr "Exécuter un fichier"
-#: spyder/plugins/ipythonconsole.py:463
+#: spyder/plugins/ipythonconsole.py:491
msgid ""
"You can also run a whole file at startup instead of just some lines (This is "
"similar to have a PYTHONSTARTUP file)."
msgstr "Option similaire à PYTHONSTARTUP pour un interpréteur standard."
-#: spyder/plugins/ipythonconsole.py:467
+#: spyder/plugins/ipythonconsole.py:495
msgid "Use the following file:"
msgstr "Utiliser le fichier suivant :"
-#: spyder/plugins/ipythonconsole.py:481
+#: spyder/plugins/ipythonconsole.py:509
+msgid "Jedi completion"
+msgstr "Auto complétion Jedi"
+
+#: spyder/plugins/ipythonconsole.py:510
+msgid ""
+"Enable Jedi-based Tab completion in the IPython console; similar to "
+"the greedy completer, but without evaluating the code.
Warning: "
+"Slows down your console when working with large dataframes!"
+msgstr ""
+"Activer l'auto complétion utilisant Jedi avec Tab dans la console "
+"IPython ; similaire à la complétion gloutonne mais sans évaluation du code."
+"
Attention : Ralentissement de la console lors de l'utilisation de "
+"dataframes volumineux !"
+
+#: spyder/plugins/ipythonconsole.py:517
+msgid "Use Jedi completion in the IPython console"
+msgstr "Utiliser l'auto complétion Jedi dans la console IPython"
+
+#: spyder/plugins/ipythonconsole.py:530
msgid "Greedy completion"
-msgstr "Complétion avancée"
+msgstr "Complétion gloutonne"
-#: spyder/plugins/ipythonconsole.py:482
+#: spyder/plugins/ipythonconsole.py:531
msgid ""
"Enable Tab completion on elements of lists, results of function "
-"calls, etc, without assigning them to a variable.
For example, you "
-"can get completions on things like li[0].<Tab> or ins."
-"meth().<Tab>"
-msgstr ""
-"Active la complétion par Tab sur les éléments de liste, les "
-"résultats de fonctions, etc. sans les avoir assignés à une variable."
-"
Par exemple vous pourrez avoir la complétion pour des expressions du "
-"type li[0].<Tab> ou ins.meth().<Tab>."
+"calls, etc, without assigning them to a variable, like li[0].<"
+"Tab> or ins.meth().<Tab>
Warning: Due to a "
+"bug, IPython's greedy completer requires a leading <Space> "
+"for some completions; e.g. np.sin(<Space>np.<Tab> "
+"works while np.sin(np.<Tab> doesn't."
+msgstr ""
+"Activer l'auto complétion utilisant Jedi avec Tab dans des éléments "
+"de listes, résultats d'appels de fonctions, etc. sansles assigner à "
+"des variables. Ex. : li[0].<Tab> or ins.meth().<Tab>"
+"
Attention : en raison d'un bogue, l'auto complétion "
+"gloutonne de IPython nécessite d'être précédée de <Space> "
+"pour certaines complétions ; ex. np.sin(<Space>np.<Tab> "
+"fonctionne alors que np.sin(np.<Tab> ne fonctionne pas."
-#: spyder/plugins/ipythonconsole.py:490
-msgid "Use the greedy completer"
-msgstr "Utiliser la complétion avancée"
+#: spyder/plugins/ipythonconsole.py:543
+msgid "Use greedy completion in the IPython console"
+msgstr "Utiliser la complétion gloutonne dans la console IPython"
-#: spyder/plugins/ipythonconsole.py:501
+#: spyder/plugins/ipythonconsole.py:555
msgid "Autocall"
msgstr "Appel automatique"
-#: spyder/plugins/ipythonconsole.py:502
+#: spyder/plugins/ipythonconsole.py:556
msgid ""
"Autocall makes IPython automatically call any callable object even if you "
"didn't type explicit parentheses.
For example, if you type str 43 "
@@ -2609,23 +2694,23 @@ msgstr ""
"appelables même sans parenthèses explicites.
Par exemple str 43 "
"deviendra automatiquement str(43)."
-#: spyder/plugins/ipythonconsole.py:509
+#: spyder/plugins/ipythonconsole.py:563
msgid "Smart"
msgstr "Intelligent"
-#: spyder/plugins/ipythonconsole.py:510
+#: spyder/plugins/ipythonconsole.py:564
msgid "Full"
msgstr "Toujours"
-#: spyder/plugins/ipythonconsole.py:511
+#: spyder/plugins/ipythonconsole.py:565
msgid "Off"
msgstr "Désactivé"
-#: spyder/plugins/ipythonconsole.py:513
+#: spyder/plugins/ipythonconsole.py:567
msgid "Autocall: "
msgstr "Appel automatique : "
-#: spyder/plugins/ipythonconsole.py:514
+#: spyder/plugins/ipythonconsole.py:568
msgid ""
"On %s mode, Autocall is not applied if there are no arguments after "
"the callable. On %s mode, all callable objects are automatically "
@@ -2635,11 +2720,11 @@ msgstr ""
"d'arguments. En mode %s, tous les objets appelables sont "
"automatiquement appelés (même s'il n'y a pas d'arguments)"
-#: spyder/plugins/ipythonconsole.py:526
+#: spyder/plugins/ipythonconsole.py:580
msgid "Symbolic Mathematics"
msgstr "Calcul formel"
-#: spyder/plugins/ipythonconsole.py:527
+#: spyder/plugins/ipythonconsole.py:581
msgid ""
"Perfom symbolic operations in the console (e.g. integrals, derivatives, "
"vector calculus, etc) and get the outputs in a beautifully printed style (it "
@@ -2649,11 +2734,11 @@ msgstr ""
"exemple intégrales, dérivées, calcul vectoriel, etc...) et affiche les "
"résultats de manière élégante."
-#: spyder/plugins/ipythonconsole.py:532
+#: spyder/plugins/ipythonconsole.py:586
msgid "Use symbolic math"
msgstr "Utiliser le calcul formel"
-#: spyder/plugins/ipythonconsole.py:533
+#: spyder/plugins/ipythonconsole.py:587
msgid ""
"This option loads the Sympy library to work with.
Please refer to its "
"documentation to learn how to use it."
@@ -2661,45 +2746,45 @@ msgstr ""
"Activer cette option permet de travailler avec la bibliothèque Sympy."
"
Merci de consulter la documentation pour savoir comment l'utiliser."
-#: spyder/plugins/ipythonconsole.py:543
+#: spyder/plugins/ipythonconsole.py:597
msgid "Prompts"
msgstr "Invites de commande"
-#: spyder/plugins/ipythonconsole.py:544
+#: spyder/plugins/ipythonconsole.py:598
msgid "Modify how Input and Output prompts are shown in the console."
msgstr ""
"Change l'affichage des invites de commande d'entrée et de sortie de la "
"console."
-#: spyder/plugins/ipythonconsole.py:547
+#: spyder/plugins/ipythonconsole.py:601
msgid "Input prompt:"
msgstr "En entrée :"
-#: spyder/plugins/ipythonconsole.py:549
+#: spyder/plugins/ipythonconsole.py:603
msgid ""
"Default is
In [<span class=\"in-prompt-number\">%i</span>]:"
msgstr ""
"Par défaut :
In [<span class=\"in-prompt-number\">%i</span>]:"
-#: spyder/plugins/ipythonconsole.py:553
+#: spyder/plugins/ipythonconsole.py:607
msgid "Output prompt:"
msgstr "En sortie :"
-#: spyder/plugins/ipythonconsole.py:555
+#: spyder/plugins/ipythonconsole.py:609
msgid ""
"Default is
Out[<span class=\"out-prompt-number\">%i</span>]:"
msgstr ""
"Par défaut :
Out[<span class=\"out-prompt-number\">%i</span>]:"
-#: spyder/plugins/ipythonconsole.py:575
+#: spyder/plugins/ipythonconsole.py:629
msgid "Graphics"
msgstr "Graphiques"
-#: spyder/plugins/ipythonconsole.py:577
+#: spyder/plugins/ipythonconsole.py:631
msgid "Startup"
msgstr "Démarrage"
-#: spyder/plugins/ipythonconsole.py:604
+#: spyder/plugins/ipythonconsole.py:658
msgid ""
"The directory {} is not writable and it is required to create IPython "
"consoles. Please make it writable."
@@ -2707,23 +2792,33 @@ msgstr ""
"Le répertoire {} n’est pas accessible en écriture et il est nécessaire de "
"créer des consoles IPython. Créez le chemin d’accès accessible en écriture."
-#: spyder/plugins/ipythonconsole.py:784
+#: spyder/plugins/ipythonconsole.py:831
msgid "Open an &IPython console"
msgstr "Ouvrir une console &IPython"
-#: spyder/plugins/ipythonconsole.py:791
+#: spyder/plugins/ipythonconsole.py:838
msgid "Restart kernel"
msgstr "Redémarrer le noyau"
-#: spyder/plugins/ipythonconsole.py:800
+#: spyder/plugins/ipythonconsole.py:847
msgid "Open a new IPython console connected to an existing kernel"
msgstr "Ouvrir une nouvelle console IPython connecté à un noyau existant"
-#: spyder/plugins/ipythonconsole.py:803
+#: spyder/plugins/ipythonconsole.py:850
msgid "Rename tab"
msgstr "Renommer l’onglet"
-#: spyder/plugins/ipythonconsole.py:928
+#: spyder/plugins/ipythonconsole.py:968
+msgid ""
+"
Please exit from debugging before trying to run a file in this "
+"console.\n"
+"
"
+msgstr ""
+"
Merci de quitter le débuggeur avant de lancer l'exécution d'un "
+"fichier dans cette console.\n"
+"
"
+
+#: spyder/plugins/ipythonconsole.py:988
msgid ""
"No IPython console is currently available to run %s.
Please "
"open a new one and try again."
@@ -2731,27 +2826,25 @@ msgstr ""
"Aucun client IPython n'est actuellement sélectionné pour exécuter %s."
"
Merci d'ouvrir un nouveau client IPython et de réessayer."
-#: spyder/plugins/ipythonconsole.py:1023
+#: spyder/plugins/ipythonconsole.py:1096
msgid ""
-"Your Python environment or installation doesn't have the ipykernel "
-"and cloudpickle modules installed on it. Without these modules is "
-"not possible for Spyder to create a console for you.
You can install "
-"them by running in a system terminal:
pip install ipykernel "
-"cloudpickle
or
conda install ipykernel cloudpickle"
-"tt>"
-msgstr ""
-"Votre environnement Python ou l'installation ne dispose pas des modules "
-"ipykernel et cloudpickle installés sur celui-ci. Sans ces "
-"modules, Spyder ne peut pas créer une console pour vous.
Vous pouvez "
-"les installer en exécutant dans un terminal de commande :
pip "
-"install ipykernel cloudpickle
ou
conda install "
-"ipykernel cloudpickle"
-
-#: spyder/plugins/ipythonconsole.py:1316
+"Your Python environment or installation doesn't have the spyder-kernels"
+"tt> module or the right version of it installed. Without this module is not "
+"possible for Spyder to create a console for you.
You can install it "
+"by running in a system terminal:
conda install spyder-kernels=0."
+"*
or
pip install spyder-kernels==0.*"
+msgstr ""
+"Votre environnement Python ou l'installation ne dispose pas du module "
+"spyder-kernels ou de sa bonne version. Sans ce module, Spyder ne "
+"peut pas créer une console.
Ce module peut être installé en "
+"exécutant dans un terminal de commande :
conda install spyder-"
+"kernels=0.*
ou
pip install spyder-kernels==0.*"
+
+#: spyder/plugins/ipythonconsole.py:1362
msgid "Do you want to close this console?"
msgstr "Souhaitez-vous fermer cette console ?"
-#: spyder/plugins/ipythonconsole.py:1322
+#: spyder/plugins/ipythonconsole.py:1368
msgid ""
"Do you want to close all other consoles connected to the same kernel as this "
"one?"
@@ -2759,39 +2852,31 @@ msgstr ""
"Voulez-vous fermer les toutes les autres consoles connectées au même noyau "
"que celle-ci ?"
-#: spyder/plugins/ipythonconsole.py:1387
+#: spyder/plugins/ipythonconsole.py:1440
msgid ""
"It was not possible to restart the IPython console when switching to this "
-"project. The error was {0}"
+"project. The error was
{0}"
msgstr ""
"Il n’a pas été possible de redémarrer la console IPython lors du passage à "
-"ce projet. L’erreur était la suivante : {0}"
+"ce projet. L'erreur était
{0}"
-#: spyder/plugins/ipythonconsole.py:1488
-msgid ""
-"This error was most probably caused by installing Spyder in a directory with "
-"non-ascii characters (i.e. characters with tildes, apostrophes or non-latin "
-"symbols).
To fix it, please reinstall Spyder in a different "
-"location."
-msgstr ""
-"Cette erreur est probablement causée par l’installation de Spyder dans un "
-"répertoire avec des caractères non ascii (c’est-à-dire des caractères avec "
-"des tildes, des apostrophes ou des symboles non latins).
Pour le "
-"réparer, réinstallez Spyder dans un endroit différent."
+#: spyder/plugins/ipythonconsole.py:1546 spyder/plugins/ipythonconsole.py:1556
+msgid "The error is:
{}"
+msgstr "L'erreur est :
{}"
-#: spyder/plugins/ipythonconsole.py:1694
+#: spyder/plugins/ipythonconsole.py:1742
msgid "IPython"
msgstr "IPython"
-#: spyder/plugins/ipythonconsole.py:1695
+#: spyder/plugins/ipythonconsole.py:1743
msgid "Unable to connect to %s"
msgstr "Impossible de se connecter au noyau IPython %s"
-#: spyder/plugins/ipythonconsole.py:1765
+#: spyder/plugins/ipythonconsole.py:1819
msgid "Connection error"
msgstr "Erreur de connexion"
-#: spyder/plugins/ipythonconsole.py:1766
+#: spyder/plugins/ipythonconsole.py:1820
msgid ""
"Could not open ssh tunnel. The error was:\n"
"\n"
@@ -2815,32 +2900,36 @@ msgstr "Supprimer disposition de fenêtre"
msgid "Layout Display and Order"
msgstr "Configurer l'affichage et l'ordre"
-#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:66
+#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:71
msgid "Python interpreter"
msgstr "Interpréteur Python"
-#: spyder/plugins/maininterpreter.py:68
+#: spyder/plugins/maininterpreter.py:73
msgid "Select the Python interpreter for all Spyder consoles"
msgstr "Sélectionner l'interpréteur Python utilisé pour exécuter des scripts"
-#: spyder/plugins/maininterpreter.py:71
+#: spyder/plugins/maininterpreter.py:76
msgid "Default (i.e. the same as Spyder's)"
msgstr ""
"Par défaut (interpréteur identique à celui dans lequel Spyder est exécuté)"
-#: spyder/plugins/maininterpreter.py:74
+#: spyder/plugins/maininterpreter.py:79
msgid "Use the following Python interpreter:"
msgstr "Utiliser l'interpréteur Python suivant :"
-#: spyder/plugins/maininterpreter.py:77
+#: spyder/plugins/maininterpreter.py:82
msgid "Executables"
msgstr "Exécutables"
-#: spyder/plugins/maininterpreter.py:94
+#: spyder/plugins/maininterpreter.py:92
+msgid "Recent custom interpreters"
+msgstr "Interpréteurs personnalisés récents"
+
+#: spyder/plugins/maininterpreter.py:107
msgid "User Module Reloader (UMR)"
msgstr "User Module Reloader (UMR)"
-#: spyder/plugins/maininterpreter.py:95
+#: spyder/plugins/maininterpreter.py:108
msgid ""
"UMR forces Python to reload modules which were imported when executing a "
"file in a Python or IPython console with the runfile function."
@@ -2848,11 +2937,11 @@ msgstr ""
"L'UMR force Python à recharger les modules importés lors de l'exécution d'un "
"script dans la console interne avec la fonction 'runfile'."
-#: spyder/plugins/maininterpreter.py:100
+#: spyder/plugins/maininterpreter.py:113
msgid "Enable UMR"
msgstr "Activer l'UMR"
-#: spyder/plugins/maininterpreter.py:101
+#: spyder/plugins/maininterpreter.py:114
msgid ""
"This option will enable the User Module Reloader (UMR) in Python/IPython "
"consoles. UMR forces Python to reload deeply modules during import when "
@@ -2877,21 +2966,21 @@ msgstr ""
"l'attribut Qt.WA_DeleteOnClose sur votre objet fenêtre principale "
"grâce à la méthode setAttribute)"
-#: spyder/plugins/maininterpreter.py:117
+#: spyder/plugins/maininterpreter.py:130
msgid "Show reloaded modules list"
msgstr "Afficher les modules rechargés"
-#: spyder/plugins/maininterpreter.py:118
+#: spyder/plugins/maininterpreter.py:131
msgid "Please note that these changes will be applied only to new consoles"
msgstr ""
"Veuillez noter que ces changements ne seront pris en compte que dans les "
"nouvelles consoles Python"
-#: spyder/plugins/maininterpreter.py:122
+#: spyder/plugins/maininterpreter.py:135
msgid "Set UMR excluded (not reloaded) modules"
msgstr "Définir la liste des modules non rechargés par l'UMR"
-#: spyder/plugins/maininterpreter.py:150
+#: spyder/plugins/maininterpreter.py:163
msgid ""
"You selected an invalid Python interpreter for the console so the previous "
"interpreter will stay. Please make sure to select a valid one."
@@ -2900,7 +2989,7 @@ msgstr ""
"que l’interprète précédent reste. Assurez-vous de sélectionner un interprète "
"valide."
-#: spyder/plugins/maininterpreter.py:175
+#: spyder/plugins/maininterpreter.py:184
msgid ""
"You selected a Python %d interpreter for the console but Spyder is "
"running on Python %d!.
Although this is possible, we recommend "
@@ -2913,19 +3002,19 @@ msgstr ""
"c'est techniquement possible, il est recommandé d'installer et d'exécuter "
"Spyder directement dans la version de l'interpréteur sélectionnée, afin "
"d'éviter l'apparition d'avertissements ou d'erreurs liées à une syntaxe "
-"incompatible entre ces deux versions de Python"
+"incompatible entre ces deux versions de Python."
-#: spyder/plugins/maininterpreter.py:186 spyder/plugins/maininterpreter.py:213
-#: spyder/plugins/maininterpreter.py:217
+#: spyder/plugins/maininterpreter.py:195 spyder/plugins/maininterpreter.py:222
+#: spyder/plugins/maininterpreter.py:226
msgid "UMR"
msgstr "UMR"
-#: spyder/plugins/maininterpreter.py:187
+#: spyder/plugins/maininterpreter.py:196
msgid "Set the list of excluded modules as this: numpy, scipy"
msgstr ""
"Définissez la liste des modules exclus comme ceci : numpy, scipy"
-#: spyder/plugins/maininterpreter.py:204
+#: spyder/plugins/maininterpreter.py:213
msgid ""
"You are working with Python 2, this means that you can not import a module "
"that contains non-ascii characters."
@@ -2933,7 +3022,7 @@ msgstr ""
"Vous travaillez avec Python 2, cela signifie que vous ne pouvez pas importer "
"un module qui contient des caractères non ASCII."
-#: spyder/plugins/maininterpreter.py:214
+#: spyder/plugins/maininterpreter.py:223
msgid ""
"The following modules are not installed on your machine:\n"
"%s"
@@ -2941,7 +3030,7 @@ msgstr ""
"Les modules suivants ne sont pas installés sur votre ordinateur :\n"
"%s"
-#: spyder/plugins/maininterpreter.py:218
+#: spyder/plugins/maininterpreter.py:227
msgid ""
"Please note that these changes will be applied only to new Python/IPython "
"consoles"
@@ -2957,40 +3046,40 @@ msgstr "Aide en ligne"
msgid "Outline"
msgstr "Structure"
-#: spyder/plugins/projects.py:83 spyder/widgets/projects/explorer.py:112
+#: spyder/plugins/projects.py:77 spyder/widgets/projects/explorer.py:112
#: spyder/widgets/projects/explorer.py:126
msgid "Project explorer"
msgstr "Explorateur de projets"
-#: spyder/plugins/projects.py:95
+#: spyder/plugins/projects.py:89
msgid "New Project..."
msgstr "Nouveau Projet..."
-#: spyder/plugins/projects.py:98
+#: spyder/plugins/projects.py:92
msgid "Open Project..."
msgstr "Ouvrir un Projet..."
-#: spyder/plugins/projects.py:101
+#: spyder/plugins/projects.py:95
msgid "Close Project"
msgstr "Fermer le projet"
-#: spyder/plugins/projects.py:104
+#: spyder/plugins/projects.py:98
msgid "Delete Project"
msgstr "Supprimer projet"
-#: spyder/plugins/projects.py:110
+#: spyder/plugins/projects.py:104
msgid "Project Preferences"
msgstr "Préférences du projet"
-#: spyder/plugins/projects.py:112
+#: spyder/plugins/projects.py:106
msgid "Recent Projects"
msgstr "Projets récents"
-#: spyder/plugins/projects.py:249
+#: spyder/plugins/projects.py:264
msgid "Open project"
msgstr "Ouvrir le projet"
-#: spyder/plugins/projects.py:255
+#: spyder/plugins/projects.py:270
msgid "%s is not a Spyder project!"
msgstr "%s n'est pas un projet Spyder !"
@@ -3012,7 +3101,7 @@ msgstr "Toujours afficher %s lors de la première exécution d'un script"
#: spyder/plugins/runconfig.py:45
msgid "Remove all variables before execution"
-msgstr "Effacer toutes les variables avant l'exécution"
+msgstr "Supprimer toutes les variables avant l'exécution"
#: spyder/plugins/runconfig.py:46
msgid "Directly enter debugging when errors appear"
@@ -3094,7 +3183,7 @@ msgstr "Le répertoire de travail par défaut est :"
#: spyder/plugins/runconfig.py:556
msgid "Run Settings dialog"
-msgstr "la fenêtre Options d'exécution"
+msgstr "Ouvre la fenêtre d'options"
#: spyder/plugins/shortcuts.py:65
msgid "Currently used to delete lines on editor/Cut a word"
@@ -3165,7 +3254,7 @@ msgid "Context"
msgstr "Contexte"
#: spyder/plugins/shortcuts.py:587
-#: spyder/widgets/variableexplorer/collectionseditor.py:128
+#: spyder/widgets/variableexplorer/collectionseditor.py:153
msgid "Name"
msgstr "Nom"
@@ -3205,36 +3294,47 @@ msgstr "Réinitialisation des raccourcis"
msgid "Do you want to reset to default values?"
msgstr "Souhaitez-vous rétablir les valeurs par défaut ?"
-#: spyder/plugins/variableexplorer.py:25
+#: spyder/plugins/variableexplorer.py:24
+msgid "View and edit DataFrames and Series in the Variable Explorer"
+msgstr ""
+"Voir et éditer les Dataframes et les Series dans l'explorateur de variables"
+
+#: spyder/plugins/variableexplorer.py:29
+msgid "View and edit two and three dimensional arrays in the Variable Explorer"
+msgstr ""
+"Voir et éditer Tableaux de deux et trois dimensions dans l'explorateur de "
+"variables"
+
+#: spyder/plugins/variableexplorer.py:37
msgid "Filter"
msgstr "Filtre"
-#: spyder/plugins/variableexplorer.py:27
-#: spyder/widgets/variableexplorer/namespacebrowser.py:200
+#: spyder/plugins/variableexplorer.py:39
+#: spyder/widgets/variableexplorer/namespacebrowser.py:203
msgid "Exclude private references"
msgstr "Exclure les références privées"
-#: spyder/plugins/variableexplorer.py:28
-#: spyder/widgets/variableexplorer/namespacebrowser.py:215
+#: spyder/plugins/variableexplorer.py:40
+#: spyder/widgets/variableexplorer/namespacebrowser.py:218
msgid "Exclude capitalized references"
msgstr "Exclure les références commençant par une majuscule"
-#: spyder/plugins/variableexplorer.py:29
-#: spyder/widgets/variableexplorer/namespacebrowser.py:208
+#: spyder/plugins/variableexplorer.py:41
+#: spyder/widgets/variableexplorer/namespacebrowser.py:211
msgid "Exclude all-uppercase references"
msgstr "Exclure les références en lettres capitales"
-#: spyder/plugins/variableexplorer.py:30
-#: spyder/widgets/variableexplorer/namespacebrowser.py:223
+#: spyder/plugins/variableexplorer.py:42
+#: spyder/widgets/variableexplorer/namespacebrowser.py:226
msgid "Exclude unsupported data types"
msgstr "Exclure les types non supportés"
-#: spyder/plugins/variableexplorer.py:36
-#: spyder/widgets/variableexplorer/collectionseditor.py:702
+#: spyder/plugins/variableexplorer.py:48
+#: spyder/widgets/variableexplorer/collectionseditor.py:738
msgid "Show arrays min/max"
msgstr "Afficher les min/max des tableaux"
-#: spyder/plugins/variableexplorer.py:178
+#: spyder/plugins/variableexplorer.py:202
msgid "Variable explorer"
msgstr "Explorateur de variables"
@@ -3275,12 +3375,12 @@ msgstr ""
msgid "Back"
msgstr "Retour"
-#: spyder/plugins/workingdirectory.py:132 spyder/widgets/explorer.py:1194
+#: spyder/plugins/workingdirectory.py:130 spyder/widgets/explorer.py:1199
#: spyder/widgets/variableexplorer/importwizard.py:539
msgid "Next"
msgstr "Suivant"
-#: spyder/plugins/workingdirectory.py:143
+#: spyder/plugins/workingdirectory.py:141
msgid ""
"This is the working directory for newly\n"
"opened consoles (Python/IPython consoles and\n"
@@ -3294,31 +3394,39 @@ msgstr ""
"de fichiers, pour la recherche dans les fichiers\n"
"et pour les fichiers créés dans l'éditeur"
-#: spyder/plugins/workingdirectory.py:168
+#: spyder/plugins/workingdirectory.py:166
msgid "Browse a working directory"
msgstr "Sélectionner un répertoire de travail"
-#: spyder/plugins/workingdirectory.py:175
+#: spyder/plugins/workingdirectory.py:173
msgid "Change to parent directory"
msgstr "Aller au répertoire parent"
-#: spyder/plugins/workingdirectory.py:182 spyder/widgets/findinfiles.py:225
+#: spyder/plugins/workingdirectory.py:180 spyder/widgets/findinfiles.py:240
msgid "Current working directory"
msgstr "Le répertoire de travail actuel"
-#: spyder/utils/codeanalysis.py:92
+#: spyder/utils/codeanalysis.py:94
msgid "Real-time code analysis on the Editor"
msgstr "Analyse de code temps réel dans l'éditeur"
-#: spyder/utils/codeanalysis.py:96
+#: spyder/utils/codeanalysis.py:98
msgid "Real-time code style analysis on the Editor"
msgstr "Analyse de code temps réel dans l'éditeur"
-#: spyder/utils/environ.py:46
+#: spyder/utils/environ.py:48
msgid "Environment variables"
msgstr "Variables d'environnement"
-#: spyder/utils/environ.py:96
+#: spyder/utils/environ.py:57
+msgid ""
+"An error occurred while trying to show your environment variables. The error "
+"was
{0}"
+msgstr ""
+"Une erreur est survenue lors de l'affichage des variables d'environnement. "
+"L'erreur est la suivante :
{0}"
+
+#: spyder/utils/environ.py:108
msgid ""
"Module pywin32 was not found.
Please restart this Windows "
"session (not the computer) for changes to take effect."
@@ -3327,7 +3435,7 @@ msgstr ""
"session en cours (et non l'ordinateur) pour que les changements "
"effectués prennent effet."
-#: spyder/utils/environ.py:109
+#: spyder/utils/environ.py:121
msgid ""
"If you accept changes, this will modify the current user environment "
"variables directly in Windows registry. Use it with precautions, at "
@@ -3347,7 +3455,7 @@ msgstr ""
"servie à exécuter Spyder : Python(x,y) Home ou un invite de commandes "
"par exemple)"
-#: spyder/utils/help/sphinxify.py:217 spyder/utils/help/sphinxify.py:227
+#: spyder/utils/help/sphinxify.py:216 spyder/utils/help/sphinxify.py:226
msgid ""
"It was not possible to generate rich text help for this object.Please "
"see it in plain text."
@@ -3358,135 +3466,78 @@ msgstr ""
#: spyder/utils/introspection/manager.py:34
#: spyder/utils/introspection/manager.py:39
msgid "Editor's code completion, go-to-definition and help"
-msgstr "Editeur : complétion de code, aller à la définition, etc."
-
-#: spyder/utils/iofuncs.py:408
-msgid "Supported files"
-msgstr "Fichiers compatibles"
-
-#: spyder/utils/iofuncs.py:410
-msgid "All files (*.*)"
-msgstr "Tous les fichiers (*.*)"
-
-#: spyder/utils/iofuncs.py:420
-msgid "Spyder data files"
-msgstr "Fichiers Spyder"
-
-#: spyder/utils/iofuncs.py:422
-#: spyder/widgets/variableexplorer/collectionseditor.py:1061
-msgid "NumPy arrays"
-msgstr "Tableaux NumPy"
-
-#: spyder/utils/iofuncs.py:423
-msgid "NumPy zip arrays"
-msgstr "Tableaux NumPy compressés"
-
-#: spyder/utils/iofuncs.py:424
-msgid "Matlab files"
-msgstr "Fichiers Matlab"
-
-#: spyder/utils/iofuncs.py:425
-msgid "CSV text files"
-msgstr "Fichiers texte CSV"
-
-#: spyder/utils/iofuncs.py:427
-msgid "JPEG images"
-msgstr "Images JPEG"
-
-#: spyder/utils/iofuncs.py:428
-msgid "PNG images"
-msgstr "Images PNG"
-
-#: spyder/utils/iofuncs.py:429
-msgid "GIF images"
-msgstr "Images GIF"
-
-#: spyder/utils/iofuncs.py:430
-msgid "TIFF images"
-msgstr "Images TIFF"
-
-#: spyder/utils/iofuncs.py:431 spyder/utils/iofuncs.py:432
-msgid "Pickle files"
-msgstr "Fichiers pickle"
-
-#: spyder/utils/iofuncs.py:433
-msgid "JSON files"
-msgstr "Fichiers JSON"
-
-#: spyder/utils/iofuncs.py:452 spyder/utils/iofuncs.py:459
-msgid "Unsupported file type '%s'"
-msgstr "Type de fichier non pris en charge '%s'"
+msgstr "Editeur : complétion de code, aller à la définition et aide"
-#: spyder/utils/programs.py:287
+#: spyder/utils/programs.py:308
msgid "It was not possible to run this file in an external terminal"
msgstr "Impossible d'exécuter ce fichier dans un terminal externe"
-#: spyder/utils/syntaxhighlighters.py:34
+#: spyder/utils/syntaxhighlighters.py:35
msgid "Syntax highlighting for Matlab, Julia and other file types"
msgstr "Coloration syntaxique pour Matlab, Julia et d'autres types de fichier"
-#: spyder/utils/syntaxhighlighters.py:43
+#: spyder/utils/syntaxhighlighters.py:44
msgid "Background:"
msgstr "Fond :"
-#: spyder/utils/syntaxhighlighters.py:44
+#: spyder/utils/syntaxhighlighters.py:45
#: spyder/widgets/sourcecode/codeeditor.py:107
msgid "Current line:"
msgstr "Ligne actuelle :"
-#: spyder/utils/syntaxhighlighters.py:45
+#: spyder/utils/syntaxhighlighters.py:46
msgid "Current cell:"
msgstr "Cellule actuelle :"
-#: spyder/utils/syntaxhighlighters.py:46
+#: spyder/utils/syntaxhighlighters.py:47
msgid "Occurrence:"
msgstr "Occurrence :"
-#: spyder/utils/syntaxhighlighters.py:47
+#: spyder/utils/syntaxhighlighters.py:48
msgid "Link:"
msgstr "Lien :"
-#: spyder/utils/syntaxhighlighters.py:48
+#: spyder/utils/syntaxhighlighters.py:49
msgid "Side areas:"
msgstr "Zones latérales :"
-#: spyder/utils/syntaxhighlighters.py:49
+#: spyder/utils/syntaxhighlighters.py:50
msgid "Matched
parens:"
msgstr "Parenthèses correspondantes :"
-#: spyder/utils/syntaxhighlighters.py:50
+#: spyder/utils/syntaxhighlighters.py:51
msgid "Unmatched
parens:"
msgstr "Parenthèse isolée :"
-#: spyder/utils/syntaxhighlighters.py:51
+#: spyder/utils/syntaxhighlighters.py:52
msgid "Normal text:"
msgstr "Texte normal :"
-#: spyder/utils/syntaxhighlighters.py:52
+#: spyder/utils/syntaxhighlighters.py:53
msgid "Keyword:"
msgstr "Mot-clé :"
-#: spyder/utils/syntaxhighlighters.py:53
+#: spyder/utils/syntaxhighlighters.py:54
msgid "Builtin:"
msgstr "Objet intégré :"
-#: spyder/utils/syntaxhighlighters.py:54
+#: spyder/utils/syntaxhighlighters.py:55
msgid "Definition:"
msgstr "Définition :"
-#: spyder/utils/syntaxhighlighters.py:55
+#: spyder/utils/syntaxhighlighters.py:56
msgid "Comment:"
msgstr "Commentaire :"
-#: spyder/utils/syntaxhighlighters.py:56
+#: spyder/utils/syntaxhighlighters.py:57
msgid "String:"
msgstr "Chaîne :"
-#: spyder/utils/syntaxhighlighters.py:57
+#: spyder/utils/syntaxhighlighters.py:58
msgid "Number:"
msgstr "Nombre :"
-#: spyder/utils/syntaxhighlighters.py:58
+#: spyder/utils/syntaxhighlighters.py:59
msgid "Instance:"
msgstr "Instance :"
@@ -3545,39 +3596,39 @@ msgstr ""
msgid "Array dimensions not valid"
msgstr "Dimensions du tableau non valides"
-#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2731
+#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2738
msgid "Zoom out"
msgstr "Réduire"
-#: spyder/widgets/browser.py:61 spyder/widgets/sourcecode/codeeditor.py:2727
+#: spyder/widgets/browser.py:61 spyder/widgets/sourcecode/codeeditor.py:2734
msgid "Zoom in"
msgstr "Agrandir"
-#: spyder/widgets/browser.py:213
+#: spyder/widgets/browser.py:216
msgid "Home"
msgstr "Accueil"
-#: spyder/widgets/browser.py:249
+#: spyder/widgets/browser.py:252
msgid "Find text"
msgstr "Rechercher"
-#: spyder/widgets/browser.py:266
+#: spyder/widgets/browser.py:269
msgid "Address:"
msgstr "Adresse :"
-#: spyder/widgets/browser.py:302
+#: spyder/widgets/browser.py:305
msgid "Unable to load page"
msgstr "Impossible de charger la page"
-#: spyder/widgets/comboboxes.py:164
+#: spyder/widgets/comboboxes.py:165
msgid "Press enter to validate this entry"
msgstr "Appuyer sur Entrée pour valider cette saisie"
-#: spyder/widgets/comboboxes.py:165
+#: spyder/widgets/comboboxes.py:166
msgid "This entry is incorrect"
msgstr "Cette saisie n'est pas correcte"
-#: spyder/widgets/comboboxes.py:208
+#: spyder/widgets/comboboxes.py:209
msgid "Press enter to validate this path"
msgstr "Appuyez sur Entrée pour valider ce chemin d'accès"
@@ -3623,79 +3674,80 @@ msgstr ""
msgid "Copy to clipboard"
msgstr "Copier dans le presse-papier"
-#: spyder/widgets/editor.py:501
+#: spyder/widgets/editor.py:511
msgid "Find symbols in file..."
msgstr "Rechercher des symboles dans le fichier…"
-#: spyder/widgets/editor.py:504
+#: spyder/widgets/editor.py:514
msgid "Copy path to clipboard"
msgstr "Copier le chemin d'accès dans le presse-papier"
-#: spyder/widgets/editor.py:508
+#: spyder/widgets/editor.py:518
msgid "Close all to the right"
msgstr "Fermer tous les onglets vers la droite"
-#: spyder/widgets/editor.py:510
+#: spyder/widgets/editor.py:520
msgid "Close all but this"
msgstr "Fermer tout sauf cet onglet"
-#: spyder/widgets/editor.py:514 spyder/widgets/explorer.py:370
+#: spyder/widgets/editor.py:524 spyder/widgets/explorer.py:373
msgid "Show in Finder"
msgstr "Afficher dans le Finder"
-#: spyder/widgets/editor.py:516 spyder/widgets/explorer.py:372
+#: spyder/widgets/editor.py:526 spyder/widgets/explorer.py:375
msgid "Show in external file explorer"
msgstr "Afficher dans l’explorateur de fichiers externe"
-#: spyder/widgets/editor.py:1193
+#: spyder/widgets/editor.py:1201
msgid "Temporary file"
msgstr "Fichier temporaire"
-#: spyder/widgets/editor.py:1279
+#: spyder/widgets/editor.py:1287
msgid "New window"
msgstr "Nouvelle fenêtre"
-#: spyder/widgets/editor.py:1280
+#: spyder/widgets/editor.py:1288
msgid "Create a new editor window"
msgstr "Créer une nouvelle fenêtre d'édition"
-#: spyder/widgets/editor.py:1283
+#: spyder/widgets/editor.py:1291
msgid "Split vertically"
msgstr "Séparation verticale"
-#: spyder/widgets/editor.py:1285
+#: spyder/widgets/editor.py:1293
msgid "Split vertically this editor window"
msgstr "Séparer en deux verticalement cette fenêtre d'édition"
-#: spyder/widgets/editor.py:1287
+#: spyder/widgets/editor.py:1295
msgid "Split horizontally"
msgstr "Séparation horizontale"
-#: spyder/widgets/editor.py:1289
+#: spyder/widgets/editor.py:1297
msgid "Split horizontally this editor window"
msgstr "Séparer en deux horizontalement cette fenêtre d'édition"
-#: spyder/widgets/editor.py:1291
+#: spyder/widgets/editor.py:1299
msgid "Close this panel"
msgstr "Fermer ce volet"
-#: spyder/widgets/editor.py:1531
+#: spyder/widgets/editor.py:1534
msgid "%s has been modified.
Do you want to save changes?"
msgstr ""
"%s a été modifié.
Souhaitez-vous enregistrer ces changements ?"
-#: spyder/widgets/editor.py:1617 spyder/widgets/editor.py:1780
-msgid "Save"
-msgstr "Enregistrer"
+#: spyder/widgets/editor.py:1620 spyder/widgets/editor.py:1783
+#: spyder/widgets/explorer.py:82
+msgid "Save Error"
+msgstr "Erreur de Sauvegarde"
-#: spyder/widgets/editor.py:1618 spyder/widgets/editor.py:1781
-#: spyder/widgets/shell.py:267
+#: spyder/widgets/editor.py:1621 spyder/widgets/editor.py:1784
+#: spyder/widgets/explorer.py:83
msgid "Unable to save file '%s'
Error message:
%s"
msgstr ""
"Impossible d'enregistrer le fichier '%s'
Message d'erreur :
"
"%s"
-#: spyder/widgets/editor.py:1968
+#: spyder/widgets/editor.py:1971
msgid ""
"%s is unavailable (this file may have been removed, moved or renamed "
"outside Spyder).
Do you want to close it?"
@@ -3703,7 +3755,7 @@ msgstr ""
"%s n'est pas accessible (ce fichier a peut-être été supprimé, déplacé "
"ou renommé en dehors de Spyder).
Souhaitez-vous le fermer ?"
-#: spyder/widgets/editor.py:1991
+#: spyder/widgets/editor.py:1994
msgid ""
"%s has been modified outside Spyder.
Do you want to reload it and "
"lose all your changes?"
@@ -3711,7 +3763,7 @@ msgstr ""
"%s a été modifié en dehors de Spyder.
Souhaitez-vous le recharger "
"et perdre ainsi vos modifications ?"
-#: spyder/widgets/editor.py:2101
+#: spyder/widgets/editor.py:2104
msgid ""
"All changes to %s will be lost.
Do you want to revert file from "
"disk?"
@@ -3720,11 +3772,11 @@ msgstr ""
"
Souhaitez-vous revenir à la version du fichier enregistrée sur le "
"disque ?"
-#: spyder/widgets/editor.py:2245
+#: spyder/widgets/editor.py:2250
msgid "Loading %s..."
msgstr "Chargement de \"%s\" en cours..."
-#: spyder/widgets/editor.py:2257
+#: spyder/widgets/editor.py:2262
msgid ""
"%s contains mixed end-of-line characters.
Spyder will fix this "
"automatically."
@@ -3732,11 +3784,11 @@ msgstr ""
"%s contient des caractères de fin de ligne mélangés.
Spyder va "
"corriger ceci automatiquement."
-#: spyder/widgets/editor.py:2664
+#: spyder/widgets/editor.py:2672
msgid "Close window"
msgstr "Fermer la fenêtre"
-#: spyder/widgets/editor.py:2666
+#: spyder/widgets/editor.py:2674
msgid "Close this window"
msgstr "Fermer cette fenêtre d'édition"
@@ -3768,7 +3820,7 @@ msgstr "Aller à la position du curseur"
msgid "Show absolute path"
msgstr "Afficher les chemins complets"
-#: spyder/widgets/editortools.py:207 spyder/widgets/explorer.py:283
+#: spyder/widgets/editortools.py:207 spyder/widgets/explorer.py:286
msgid "Show all files"
msgstr "Afficher tous les fichiers"
@@ -3780,109 +3832,109 @@ msgstr "Afficher les commentaires spéciaux"
msgid "Show/hide outline explorer"
msgstr "Afficher/masquer l'explorateur de structure"
-#: spyder/widgets/explorer.py:279
+#: spyder/widgets/explorer.py:282
msgid "Edit filename filters..."
msgstr "Modifier les filtres..."
-#: spyder/widgets/explorer.py:293
+#: spyder/widgets/explorer.py:296
msgid "Edit filename filters"
msgstr "Modifier les filtres"
-#: spyder/widgets/explorer.py:294
+#: spyder/widgets/explorer.py:297
msgid "Name filters:"
msgstr "Filtres sur les noms de fichiers :"
-#: spyder/widgets/explorer.py:313
+#: spyder/widgets/explorer.py:316
msgid "File..."
msgstr "Fichier..."
-#: spyder/widgets/explorer.py:317
+#: spyder/widgets/explorer.py:320
msgid "Module..."
msgstr "Module..."
-#: spyder/widgets/explorer.py:321
+#: spyder/widgets/explorer.py:324
msgid "Folder..."
msgstr "Dossier..."
-#: spyder/widgets/explorer.py:325
+#: spyder/widgets/explorer.py:328
msgid "Package..."
msgstr "Paquet..."
-#: spyder/widgets/explorer.py:346
-#: spyder/widgets/variableexplorer/collectionseditor.py:677
+#: spyder/widgets/explorer.py:349
+#: spyder/widgets/variableexplorer/collectionseditor.py:713
msgid "Edit"
msgstr "Modifier"
-#: spyder/widgets/explorer.py:348
+#: spyder/widgets/explorer.py:351
msgid "Move..."
msgstr "Déplacer..."
-#: spyder/widgets/explorer.py:351
+#: spyder/widgets/explorer.py:354
msgid "Delete..."
msgstr "Supprimer..."
-#: spyder/widgets/explorer.py:354
+#: spyder/widgets/explorer.py:357
msgid "Rename..."
msgstr "Renommer..."
-#: spyder/widgets/explorer.py:357
+#: spyder/widgets/explorer.py:360
msgid "Open"
msgstr "Ouvrir"
-#: spyder/widgets/explorer.py:358 spyder/widgets/sourcecode/codeeditor.py:2699
+#: spyder/widgets/explorer.py:361 spyder/widgets/sourcecode/codeeditor.py:2706
msgid "Convert to Python script"
msgstr "Convertir en fichier Python"
-#: spyder/widgets/explorer.py:399
+#: spyder/widgets/explorer.py:393
msgid "Commit"
msgstr "Commiter"
-#: spyder/widgets/explorer.py:402
+#: spyder/widgets/explorer.py:396
msgid "Browse repository"
msgstr "Explorer le dépôt"
-#: spyder/widgets/explorer.py:413
+#: spyder/widgets/explorer.py:407
msgid "Open command prompt here"
msgstr "Ouvrir un invite de commandes ici"
-#: spyder/widgets/explorer.py:415
+#: spyder/widgets/explorer.py:409
msgid "Open terminal here"
msgstr "Ouvrir un terminal ici"
-#: spyder/widgets/explorer.py:416
+#: spyder/widgets/explorer.py:410
msgid "Open IPython console here"
msgstr "Ouvrir une console IPython ici"
-#: spyder/widgets/explorer.py:430
+#: spyder/widgets/explorer.py:424
msgid "New"
msgstr "Nouveau"
-#: spyder/widgets/explorer.py:438
+#: spyder/widgets/explorer.py:432
msgid "Import"
msgstr "Import"
-#: spyder/widgets/explorer.py:584
+#: spyder/widgets/explorer.py:583
msgid "Do you really want to delete %s?"
msgstr "Souhaitez-vous réellement supprimer %s ?"
-#: spyder/widgets/explorer.py:602
+#: spyder/widgets/explorer.py:601
msgid "delete"
msgstr "supprimer"
-#: spyder/widgets/explorer.py:603 spyder/widgets/projects/explorer.py:148
+#: spyder/widgets/explorer.py:602 spyder/widgets/projects/explorer.py:148
#: spyder/widgets/projects/explorer.py:256
msgid "Project Explorer"
msgstr "Explorateur de projets"
-#: spyder/widgets/explorer.py:604 spyder/widgets/projects/explorer.py:149
+#: spyder/widgets/explorer.py:603 spyder/widgets/projects/explorer.py:149
msgid "Unable to %s %s
Error message:
%s"
msgstr "Impossible de %s %s
Message d'erreur :
%s"
-#: spyder/widgets/explorer.py:619
+#: spyder/widgets/explorer.py:618
msgid "File Explorer"
msgstr "Explorateur de Fichiers"
-#: spyder/widgets/explorer.py:620
+#: spyder/widgets/explorer.py:619
msgid ""
"The current directory contains a project.
If you want to delete the "
"project, please go to Projects » Delete Project"
@@ -3890,11 +3942,11 @@ msgstr ""
"Le dossier actuel contient un projet.
Si vous souhaitez supprimer le "
"projet, allez dans Projets b> & raquo; Supprimer le projet b>"
-#: spyder/widgets/explorer.py:637 spyder/widgets/sourcecode/codeeditor.py:2160
+#: spyder/widgets/explorer.py:636 spyder/widgets/sourcecode/codeeditor.py:2167
msgid "Conversion error"
msgstr "Erreur de conversion"
-#: spyder/widgets/explorer.py:638 spyder/widgets/sourcecode/codeeditor.py:2161
+#: spyder/widgets/explorer.py:637 spyder/widgets/sourcecode/codeeditor.py:2168
msgid ""
"It was not possible to convert this notebook. The error is:\n"
"\n"
@@ -3902,18 +3954,18 @@ msgstr ""
"Impossible de convertir ce notebook. Message d'erreur :\n"
"\n"
-#: spyder/widgets/explorer.py:655 spyder/widgets/explorer.py:663
-#: spyder/widgets/explorer.py:674
-#: spyder/widgets/variableexplorer/collectionseditor.py:706
-#: spyder/widgets/variableexplorer/collectionseditor.py:952
+#: spyder/widgets/explorer.py:654 spyder/widgets/explorer.py:662
+#: spyder/widgets/explorer.py:676
+#: spyder/widgets/variableexplorer/collectionseditor.py:742
+#: spyder/widgets/variableexplorer/collectionseditor.py:988
msgid "Rename"
msgstr "Renommer"
-#: spyder/widgets/explorer.py:656
+#: spyder/widgets/explorer.py:655
msgid "New name:"
msgstr "Nouveau nom :"
-#: spyder/widgets/explorer.py:664
+#: spyder/widgets/explorer.py:663
msgid ""
"Do you really want to rename %s and overwrite the existing file "
"%s?"
@@ -3921,84 +3973,86 @@ msgstr ""
"Souhaitez-vous réellement renommer %s et remplacer le ficher existant "
"%s ?"
-#: spyder/widgets/explorer.py:675
+#: spyder/widgets/explorer.py:677
msgid "Unable to rename file %s
Error message:
%s"
msgstr ""
"Impossible de renommer l'élément %s
Message d'erreur :"
"
%s"
-#: spyder/widgets/explorer.py:722
+#: spyder/widgets/explorer.py:724
msgid "Unable to move %s
Error message:
%s"
msgstr ""
"Impossible de déplacer %s
Message d'erreur :
%s"
-#: spyder/widgets/explorer.py:740
+#: spyder/widgets/explorer.py:742
msgid "Unable to create folder %s
Error message:
%s"
msgstr ""
"Impossible de créer le répertoire %s
Message d'erreur :"
"
%s"
-#: spyder/widgets/explorer.py:753 spyder/widgets/explorer.py:787
+#: spyder/widgets/explorer.py:755 spyder/widgets/explorer.py:789
msgid "Unable to create file %s
Error message:
%s"
msgstr ""
"Impossible de créer le fichier %s
Message d'erreur :
"
"%s"
-#: spyder/widgets/explorer.py:761
+#: spyder/widgets/explorer.py:763
msgid "New folder"
msgstr "Nouveau répertoire"
-#: spyder/widgets/explorer.py:762
+#: spyder/widgets/explorer.py:764
msgid "Folder name:"
msgstr "Nom du dossier :"
-#: spyder/widgets/explorer.py:767
+#: spyder/widgets/explorer.py:769
msgid "New package"
msgstr "Nouveau paquet"
-#: spyder/widgets/explorer.py:768
+#: spyder/widgets/explorer.py:770
msgid "Package name:"
msgstr "Nom du paquet :"
-#: spyder/widgets/explorer.py:808
+#: spyder/widgets/explorer.py:810
msgid "New module"
msgstr "Nouveau module"
-#: spyder/widgets/explorer.py:823
+#: spyder/widgets/explorer.py:825
msgid ""
"For %s support, please install one of the
following tools:
%s"
msgstr ""
"Pour ajouter la prise en charge de %s, merci d'installer
l'un des "
"outils suivants :
%s"
-#: spyder/widgets/explorer.py:827
+#: spyder/widgets/explorer.py:829
msgid "Unable to find external program.
%s"
msgstr "Impossible de trouver un programme externe.
%s"
-#: spyder/widgets/explorer.py:1048
+#: spyder/widgets/explorer.py:1049
msgid "Show current directory only"
msgstr "Afficher uniquement le répertoire courant"
-#: spyder/widgets/explorer.py:1158
+#: spyder/widgets/explorer.py:1163
msgid "You don't have the right permissions to open this directory"
msgstr ""
"Vous n'avez pas les permissions nécessaires pour afficher le contenu de ce "
"dossier"
-#: spyder/widgets/explorer.py:1189
+#: spyder/widgets/explorer.py:1194
msgid "Show icons and text"
msgstr "Afficher icônes et textes"
-#: spyder/widgets/explorer.py:1191
+#: spyder/widgets/explorer.py:1196
#: spyder/widgets/variableexplorer/importwizard.py:535
msgid "Previous"
msgstr "Précédent"
-#: spyder/widgets/explorer.py:1197
+#: spyder/widgets/explorer.py:1202
msgid "Parent"
msgstr "Parent"
#: spyder/widgets/fileswitcher.py:110
+#: spyder/plugins/pylint/widgets/pylintgui.py:364
+#: spyder/plugins/profiler/widgets/profilergui.py:296
msgid "unsaved file"
msgstr "fichier non enregistré"
@@ -4015,33 +4069,33 @@ msgstr ""
"
Utilisez:numberpour aller à une ligne, par exemple "
"main: 42
Utilisez@symbol_text pour accéder à un "
"symbole, par example @init
Appuyez sur Ctrl + "
-"W pour fermer l'onglet actuel."
+"W pour fermer l'onglet actuel.
"
#: spyder/widgets/fileswitcher.py:663
msgid "lines"
msgstr "lignes"
-#: spyder/widgets/findinfiles.py:124
+#: spyder/widgets/findinfiles.py:121
msgid "Unexpected error: see internal console"
msgstr "Erreur inattendue : voir console interne"
-#: spyder/widgets/findinfiles.py:152
+#: spyder/widgets/findinfiles.py:158
msgid "invalid regular expression"
msgstr "expression régulière incorrecte"
-#: spyder/widgets/findinfiles.py:202
+#: spyder/widgets/findinfiles.py:217
msgid "permission denied errors were encountered"
msgstr "des erreurs d'autorisation d'accès ont été rencontrées"
-#: spyder/widgets/findinfiles.py:217
+#: spyder/widgets/findinfiles.py:232
msgid "Search directory"
msgstr "Rechercher un répertoire"
-#: spyder/widgets/findinfiles.py:230
+#: spyder/widgets/findinfiles.py:245
msgid "Project"
msgstr "Projets"
-#: spyder/widgets/findinfiles.py:231
+#: spyder/widgets/findinfiles.py:246
msgid ""
"Search in all files and directories present on the current project path (if "
"opened)"
@@ -4049,247 +4103,388 @@ msgstr ""
"Rechercher dans tous les fichiers et répertoires présents sur le chemin du "
"projet en cours (si ouvert)"
-#: spyder/widgets/findinfiles.py:236
+#: spyder/widgets/findinfiles.py:251
msgid "File"
msgstr "Fichier"
-#: spyder/widgets/findinfiles.py:237
+#: spyder/widgets/findinfiles.py:252
msgid "Search in current opened file"
msgstr "Rechercher dans le fichier en cours"
-#: spyder/widgets/findinfiles.py:242
+#: spyder/widgets/findinfiles.py:257
msgid "Select other directory"
msgstr "Sélectionner un autre répertoire"
-#: spyder/widgets/findinfiles.py:243
+#: spyder/widgets/findinfiles.py:258
msgid "Search in other folder present on the file system"
msgstr "Rechercher dans un autre répertoire du système"
-#: spyder/widgets/findinfiles.py:247
+#: spyder/widgets/findinfiles.py:262
msgid "Clear the list of other directories"
msgstr "Effacer la liste des autres répertoires"
-#: spyder/widgets/findinfiles.py:318
+#: spyder/widgets/findinfiles.py:333
msgid "Clear other directories"
msgstr "Effacer les autres répertoires"
-#: spyder/widgets/findinfiles.py:319
+#: spyder/widgets/findinfiles.py:334
msgid "Do you want to clear the list of other directories?"
msgstr "Souhaitez-vous effacer la liste des autres répertoires ?"
-#: spyder/widgets/findinfiles.py:415
+#: spyder/widgets/findinfiles.py:404 spyder/widgets/findreplace.py:52
+msgid "Regular expression error"
+msgstr "Erreur d'expression régulière"
+
+#: spyder/widgets/findinfiles.py:427
msgid "Search pattern"
msgstr "Expression recherchée"
-#: spyder/widgets/findinfiles.py:418 spyder/widgets/findinfiles.py:458
-#: spyder/widgets/findreplace.py:99
+#: spyder/widgets/findinfiles.py:430 spyder/widgets/findinfiles.py:470
+#: spyder/widgets/findreplace.py:100
msgid "Regular expression"
msgstr "Expression régulière"
-#: spyder/widgets/findinfiles.py:421 spyder/widgets/findreplace.py:105
+#: spyder/widgets/findinfiles.py:433 spyder/widgets/findreplace.py:106
msgid "Case Sensitive"
msgstr "Respecter la casse"
-#: spyder/widgets/findinfiles.py:432
+#: spyder/widgets/findinfiles.py:444
msgid "Search"
msgstr "Rechercher"
-#: spyder/widgets/findinfiles.py:435
+#: spyder/widgets/findinfiles.py:447
msgid "Start search"
msgstr "Démarrer la recherche"
-#: spyder/widgets/findinfiles.py:442
+#: spyder/widgets/findinfiles.py:454
msgid "Stop search"
msgstr "Arrêter la recherche"
-#: spyder/widgets/findinfiles.py:452
-msgid "Excluded filenames pattern"
-msgstr "Expression des noms de fichier à exclure"
+#: spyder/widgets/findinfiles.py:464
+msgid "Exclude pattern"
+msgstr "Pattern à exclure"
-#: spyder/widgets/findinfiles.py:461
+#: spyder/widgets/findinfiles.py:473
msgid "Exclude:"
msgstr "Exclure :"
-#: spyder/widgets/findinfiles.py:470
+#: spyder/widgets/findinfiles.py:482
msgid "Search in:"
msgstr "Rechercher dans :"
-#: spyder/widgets/findinfiles.py:499
+#: spyder/widgets/findinfiles.py:511
msgid "Hide advanced options"
msgstr "Masquer les options avancées"
-#: spyder/widgets/findinfiles.py:502
+#: spyder/widgets/findinfiles.py:514
msgid "Show advanced options"
msgstr "Afficher les options avancées"
-#: spyder/widgets/findinfiles.py:759 spyder/widgets/findinfiles.py:843
+#: spyder/widgets/findinfiles.py:790 spyder/widgets/findinfiles.py:877
msgid "String not found"
msgstr "Chaîne de caractères non trouvée"
-#: spyder/widgets/findinfiles.py:845
+#: spyder/widgets/findinfiles.py:879
msgid "matches in"
msgstr "correspondances trouvées dans"
-#: spyder/widgets/findinfiles.py:846
+#: spyder/widgets/findinfiles.py:880
msgid "file"
msgstr "fichier"
-#: spyder/widgets/findinfiles.py:878
+#: spyder/widgets/findinfiles.py:912
msgid " Scanning: {0}"
msgstr " Recherche en cours : {0}"
-#: spyder/widgets/findinfiles.py:880
+#: spyder/widgets/findinfiles.py:914
msgid " Searching for files in folder: {0}"
msgstr " Recherche de fichiers dans le dossier : {0}"
-#: spyder/widgets/findinfiles.py:884
+#: spyder/widgets/findinfiles.py:918
msgid " Searching for files..."
msgstr " Recherche de fichiers…"
-#: spyder/widgets/findreplace.py:48
+#: spyder/widgets/findreplace.py:49
msgid "No matches"
msgstr "Pas de correspondance"
-#: spyder/widgets/findreplace.py:49 spyder/widgets/findreplace.py:50
-#: spyder/widgets/findreplace.py:72
+#: spyder/widgets/findreplace.py:50 spyder/widgets/findreplace.py:51
+#: spyder/widgets/findreplace.py:73
msgid "Search string"
msgstr "Chaîne de caractères à rechercher"
-#: spyder/widgets/findreplace.py:51
-msgid "Regular expression error"
-msgstr "Erreur d'expression régulière"
-
-#: spyder/widgets/findreplace.py:111
+#: spyder/widgets/findreplace.py:112
msgid "Whole words"
msgstr "Mots entiers"
-#: spyder/widgets/findreplace.py:117
+#: spyder/widgets/findreplace.py:118
msgid "Highlight matches"
msgstr "Surligner les résultats"
-#: spyder/widgets/findreplace.py:131
+#: spyder/widgets/findreplace.py:132
msgid "Replace with:"
msgstr "Remplacer par :"
-#: spyder/widgets/findreplace.py:133
+#: spyder/widgets/findreplace.py:134
msgid "Replace string"
msgstr "Chaîne de caractères de remplacement"
-#: spyder/widgets/findreplace.py:137
+#: spyder/widgets/findreplace.py:138
msgid "Replace/find next"
msgstr "Remplacer/rechercher suivant"
-#: spyder/widgets/findreplace.py:142
+#: spyder/widgets/findreplace.py:143
msgid "Replace selection"
msgstr "Remplacer la sélection"
-#: spyder/widgets/findreplace.py:150
+#: spyder/widgets/findreplace.py:151
msgid "Replace all"
msgstr "Remplacer tout"
-#: spyder/widgets/findreplace.py:577
+#: spyder/widgets/findreplace.py:583
msgid "of"
msgstr "sur"
-#: spyder/widgets/findreplace.py:581
+#: spyder/widgets/findreplace.py:587
msgid "matches"
msgstr "correspondances"
-#: spyder/widgets/findreplace.py:584
+#: spyder/widgets/findreplace.py:590
msgid "no matches"
msgstr "Pas de correspondance"
-#: spyder/widgets/internalshell.py:262
+#: spyder/widgets/github/backend.py:151
+msgid "Invalid credentials"
+msgstr "Erreur d'authentification"
+
+#: spyder/widgets/github/backend.py:152
+msgid "Failed to create Github issue, invalid credentials..."
+msgstr ""
+"Impossible de créer le rapport d'erreur Github, identifiants non valides..."
+
+#: spyder/widgets/github/backend.py:159
+msgid "Failed to create issue"
+msgstr "Impossible de créer le rapport d'erreur"
+
+#: spyder/widgets/github/backend.py:160
+msgid "Failed to create Github issue. Error %d"
+msgstr "Impossible de créer le rapport d'erreur Github. Erreur %d"
+
+#: spyder/widgets/github/backend.py:167
+msgid "Issue created on Github"
+msgstr "Rapport d'erreur créé sur Github"
+
+#: spyder/widgets/github/backend.py:168
+msgid ""
+"Issue successfully created. Would you like to open the issue in your web "
+"browser?"
+msgstr ""
+"Rapport d'erreur créé avec succès. Ouvrir ce rapport dans le navigateur "
+"internet ?"
+
+#: spyder/widgets/github/backend.py:195
+msgid "Failed to store password"
+msgstr "Impossible d'enregistrer le mot de passe"
+
+#: spyder/widgets/github/backend.py:196
+msgid ""
+"It was not possible to securely save your password. You will be prompted for "
+"your Github credentials next time you want to report an issue."
+msgstr ""
+"Impossible d'enregistrer le mot de passe de façon sécurisée. Vous serez "
+"invité à entrer vos identifiants lors de la prochaine création de rapport "
+"d'erreur."
+
+#: spyder/widgets/github/backend.py:212
+msgid "Failed to store token"
+msgstr "Impossible d'enregistrer le token"
+
+#: spyder/widgets/github/backend.py:213
+msgid ""
+"It was not possible to securely save your token. You will be prompted for "
+"your Github token next time you want to report an issue."
+msgstr ""
+"Impossible d'enregistrer le token de façon sécurisée. Vous serez invité à "
+"entrer votre token lors de la prochaine création de rapport d'erreur."
+
+#: spyder/widgets/github/backend.py:237
+msgid "Failed to retrieve password"
+msgstr "Impossible de récupérer le mot de passe"
+
+#: spyder/widgets/github/backend.py:238
+msgid ""
+"It was not possible to retrieve your password. Please introduce it again."
+msgstr ""
+"Impossible de récupérer votre mot de passe. Veuillez l'entrer à nouveau."
+
+#: spyder/widgets/github/backend.py:249
+msgid "Failed to retrieve token"
+msgstr "Impossible de récupérer le token"
+
+#: spyder/widgets/github/backend.py:250
+msgid "It was not possible to retrieve your token. Please introduce it again."
+msgstr "Impossible de récupérer votre token. Veuillez l'entrer à nouveau."
+
+#: spyder/widgets/github/gh_login.py:38
+msgid "Sign in to Github"
+msgstr "S'authentifier sur Github"
+
+#: spyder/widgets/github/gh_login.py:57
+msgid ""
+"For regular users, i.e. users without two-factor authentication "
+"enabled"
+msgstr ""
+"Pour les utilisateurs classiques, c'est-à-dire les utilisateurs sans "
+"l'authentification à deux facteurs activée"
+
+#: spyder/widgets/github/gh_login.py:62
+msgid "Username:"
+msgstr "Nom d'utilisateur :"
+
+#: spyder/widgets/github/gh_login.py:69
+msgid "Password: "
+msgstr "Mot de passe : "
+
+#: spyder/widgets/github/gh_login.py:81
+msgid "Remember me"
+msgstr "Se souvenir de moi"
+
+#: spyder/widgets/github/gh_login.py:82
+msgid "Spyder will save your credentials safely"
+msgstr "Spyder va enregistrer les identifiants de façon sécurisée"
+
+#: spyder/widgets/github/gh_login.py:99
+msgid "Password Only"
+msgstr "Mot de passe uniquement"
+
+#: spyder/widgets/github/gh_login.py:105
+msgid ""
+"For users with two-factor authentication enabled, or who prefer a per-"
+"app token authentication.
You can go here "
+"and click \"Generate token\" at the bottom to create a new token to use for "
+"this, with the appropriate permissions."
+msgstr ""
+"Pour les utilisateurs sans l'authentification double facteur activée, "
+"ou pour ceux qui préfèrent une authentification avec un token par "
+"application.
Se connecter ici et cliquer "
+"sur \"Generate token\" en bas de page pour créer un nouveau token à utiliser "
+"ici avec les autorisations appropriées."
+
+#: spyder/widgets/github/gh_login.py:127
+msgid "Remember token"
+msgstr "Se souvenir du token"
+
+#: spyder/widgets/github/gh_login.py:128
+msgid "Spyder will save your token safely"
+msgstr "Spyder va enregistrer votre token de façon sécurisée"
+
+#: spyder/widgets/github/gh_login.py:145
+msgid "Access Token"
+msgstr "Accéder au Token"
+
+#: spyder/widgets/github/gh_login.py:148
+msgid "Sign in"
+msgstr "S'identifier"
+
+#: spyder/widgets/internalshell.py:263
msgid "Help..."
msgstr "Aide..."
-#: spyder/widgets/internalshell.py:279
+#: spyder/widgets/internalshell.py:280
msgid "Shell special commands:"
msgstr "Commandes spéciales de la console :"
-#: spyder/widgets/internalshell.py:280
+#: spyder/widgets/internalshell.py:281
msgid "Internal editor:"
msgstr "Éditeur interne :"
-#: spyder/widgets/internalshell.py:281
+#: spyder/widgets/internalshell.py:282
msgid "External editor:"
msgstr "Éditeur externe :"
-#: spyder/widgets/internalshell.py:282
+#: spyder/widgets/internalshell.py:283
msgid "Run script:"
msgstr "Exécuter un script :"
-#: spyder/widgets/internalshell.py:283
+#: spyder/widgets/internalshell.py:284
msgid "Remove references:"
msgstr "Supprimer des références :"
-#: spyder/widgets/internalshell.py:284
+#: spyder/widgets/internalshell.py:285
msgid "System commands:"
msgstr "Commandes systèmes :"
-#: spyder/widgets/internalshell.py:285
+#: spyder/widgets/internalshell.py:286
msgid "Python help:"
msgstr "Aide Python :"
-#: spyder/widgets/internalshell.py:286
+#: spyder/widgets/internalshell.py:287
msgid "GUI-based editor:"
msgstr "Éditeur graphique :"
-#: spyder/widgets/ipythonconsole/client.py:272
+#: spyder/widgets/internalshell.py:418
+msgid ""
+"In order to use commands like \"raw_input\" or \"input\" run Spyder with the "
+"multithread option (--multithread) from a system terminal"
+msgstr ""
+"Pour utiliser des commandes telles que \"raw_input\" ou \"input\" utiliser "
+"Spyder avec l'option (--multithread) depuis un terminal de commande"
+
+#: spyder/widgets/ipythonconsole/client.py:308
msgid "An error ocurred while starting the kernel"
msgstr "Une erreur est survenue lors du démarrage du noyau"
-#: spyder/widgets/ipythonconsole/client.py:313
-#: spyder/widgets/ipythonconsole/client.py:369
-#: spyder/widgets/ipythonconsole/client.py:402
-#: spyder/widgets/ipythonconsole/shell.py:233
-#: spyder/widgets/variableexplorer/namespacebrowser.py:193
+#: spyder/widgets/ipythonconsole/client.py:352
+#: spyder/widgets/ipythonconsole/client.py:408
+#: spyder/widgets/ipythonconsole/client.py:441
+#: spyder/widgets/ipythonconsole/shell.py:234
+#: spyder/widgets/variableexplorer/namespacebrowser.py:196
msgid "Remove all variables"
msgstr "Supprimer toutes les variables"
-#: spyder/widgets/ipythonconsole/client.py:322
+#: spyder/widgets/ipythonconsole/client.py:361
msgid "Show environment variables"
msgstr "Afficher les variables d’environnement"
-#: spyder/widgets/ipythonconsole/client.py:329
+#: spyder/widgets/ipythonconsole/client.py:368
msgid "Show sys.path contents"
msgstr "Afficher le contenu de sys.path"
-#: spyder/widgets/ipythonconsole/client.py:356
+#: spyder/widgets/ipythonconsole/client.py:395
msgid "Stop the current command"
msgstr "Interrompre la commande en cours"
-#: spyder/widgets/ipythonconsole/client.py:367
-#: spyder/widgets/variableexplorer/collectionseditor.py:699
-#: spyder/widgets/variableexplorer/collectionseditor.py:934
+#: spyder/widgets/ipythonconsole/client.py:406
+#: spyder/widgets/variableexplorer/collectionseditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:970
msgid "Remove"
msgstr "Supprimer"
-#: spyder/widgets/ipythonconsole/client.py:390
+#: spyder/widgets/ipythonconsole/client.py:429
msgid "Inspect current object"
msgstr "Inspecter l'onglet courant"
-#: spyder/widgets/ipythonconsole/client.py:396
+#: spyder/widgets/ipythonconsole/client.py:435
msgid "Clear line or block"
msgstr "Effacer la ligne ou le bloc"
-#: spyder/widgets/ipythonconsole/client.py:409
+#: spyder/widgets/ipythonconsole/client.py:448
msgid "Clear console"
msgstr "Effacer la console"
-#: spyder/widgets/ipythonconsole/client.py:462
+#: spyder/widgets/ipythonconsole/client.py:507
msgid "Are you sure you want to restart the kernel?"
msgstr "Souhaitez-vous vraiment redémarrer le noyau ?"
-#: spyder/widgets/ipythonconsole/client.py:464
+#: spyder/widgets/ipythonconsole/client.py:509
msgid "Restart kernel?"
msgstr "Redémarrer le noyau ?"
-#: spyder/widgets/ipythonconsole/client.py:476
+#: spyder/widgets/ipythonconsole/client.py:526
msgid "Error restarting kernel: %s\n"
msgstr "Une erreur est survenue lors du démarrage du noyau : %s\n"
-#: spyder/widgets/ipythonconsole/client.py:484
+#: spyder/widgets/ipythonconsole/client.py:534
msgid ""
"
Restarting kernel...\n"
"
"
@@ -4297,40 +4492,40 @@ msgstr ""
"
Redémarrage du noyau...\n"
"
"
-#: spyder/widgets/ipythonconsole/client.py:488
+#: spyder/widgets/ipythonconsole/client.py:538
msgid "Cannot restart a kernel not started by Spyder\n"
msgstr "Impossible de redémarrer un noyau non démarré par Spyder\n"
-#: spyder/widgets/ipythonconsole/client.py:597
+#: spyder/widgets/ipythonconsole/client.py:649
msgid "Connecting to kernel..."
msgstr "Connexion au noyau..."
-#: spyder/widgets/ipythonconsole/help.py:128 spyder/widgets/mixins.py:712
+#: spyder/widgets/ipythonconsole/help.py:128 spyder/widgets/mixins.py:726
msgid "Arguments"
msgstr "Arguments"
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:129
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:138
msgid "Loading this kind of data while debugging is not supported."
msgstr ""
"Le chargement de ce type de données pendant le débogage n’est pas pris en "
"charge."
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:148
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:157
msgid "Saving data while debugging is not supported."
msgstr "L’enregistrement de données lors du débogage n’est pas pris en charge."
-#: spyder/widgets/ipythonconsole/shell.py:234
+#: spyder/widgets/ipythonconsole/shell.py:235
msgid ""
"All user-defined variables will be removed. Are you sure you want to proceed?"
msgstr ""
"Toutes les variables définies par l'utilisateur seront supprimées. Souhaitez-"
"vous continuer ?"
-#: spyder/widgets/ipythonconsole/shell.py:240
+#: spyder/widgets/ipythonconsole/shell.py:241
msgid "Don't show again."
msgstr "Ne plus me demander."
-#: spyder/widgets/ipythonconsole/shell.py:264
+#: spyder/widgets/ipythonconsole/shell.py:266
msgid ""
"
Removing all variables...\n"
"
"
@@ -4338,15 +4533,15 @@ msgstr ""
"
Suppression de toutes les variables...\n"
"
"
-#: spyder/widgets/ipythonconsole/shell.py:430
-msgid "Changing backend to Qt for Mayavi"
-msgstr "Utilisation du backend Qt pour Mayavi"
+#: spyder/widgets/ipythonconsole/shell.py:432
+msgid "Changing backend to Qt4 for Mayavi"
+msgstr "Changer le back-end pour Qt4 pour Mayavi"
-#: spyder/widgets/ipythonconsole/shell.py:475
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel died, restarting"
msgstr "Le noyau est mort, redémarrage en cours"
-#: spyder/widgets/ipythonconsole/shell.py:475
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel restarting"
msgstr "Redémarrage du noyau"
@@ -4374,45 +4569,46 @@ msgstr "Replier la sélection"
msgid "Expand selection"
msgstr "Déplier la sélection"
-#: spyder/widgets/pathmanager.py:97
+#: spyder/widgets/pathmanager.py:98
msgid "Move to top"
msgstr "Placer en premier"
-#: spyder/widgets/pathmanager.py:103
+#: spyder/widgets/pathmanager.py:104
msgid "Move up"
msgstr "Monter"
-#: spyder/widgets/pathmanager.py:109
+#: spyder/widgets/pathmanager.py:110
msgid "Move down"
msgstr "Descendre"
-#: spyder/widgets/pathmanager.py:115
+#: spyder/widgets/pathmanager.py:116
msgid "Move to bottom"
msgstr "Placer en dernier"
-#: spyder/widgets/pathmanager.py:126 spyder/widgets/pathmanager.py:267
+#: spyder/widgets/pathmanager.py:127 spyder/widgets/pathmanager.py:270
+#: spyder/widgets/pathmanager.py:282
msgid "Add path"
msgstr "Ajouter un chemin"
-#: spyder/widgets/pathmanager.py:131 spyder/widgets/pathmanager.py:246
+#: spyder/widgets/pathmanager.py:132 spyder/widgets/pathmanager.py:247
msgid "Remove path"
msgstr "Supprimer"
-#: spyder/widgets/pathmanager.py:141
+#: spyder/widgets/pathmanager.py:142
msgid "Synchronize..."
msgstr "Synchroniser..."
-#: spyder/widgets/pathmanager.py:143
+#: spyder/widgets/pathmanager.py:144
msgid "Synchronize Spyder's path list with PYTHONPATH environment variable"
msgstr ""
"Synchronise la liste des chemins d'accès de Spyder avec celle de la variable "
"d'environnement PYTHONPATH"
-#: spyder/widgets/pathmanager.py:155
+#: spyder/widgets/pathmanager.py:156
msgid "Synchronize"
msgstr "Synchroniser"
-#: spyder/widgets/pathmanager.py:156
+#: spyder/widgets/pathmanager.py:157
msgid ""
"This will synchronize Spyder's path list with PYTHONPATH environment "
"variable for current user, allowing you to run your Python modules outside "
@@ -4425,11 +4621,19 @@ msgstr ""
"avoir besoin de configurer sys.path.
Souhaitez-vous effacer le contenu "
"de PYTHONPATH avant d'y ajouter la liste des chemins d'accès de Spyder ?"
-#: spyder/widgets/pathmanager.py:247
+#: spyder/widgets/pathmanager.py:248
msgid "Do you really want to remove selected path?"
msgstr "Souhaitez-vous vraiment supprimer le chemin sélectionné ?"
-#: spyder/widgets/pathmanager.py:268
+#: spyder/widgets/pathmanager.py:271
+msgid ""
+"You are using Python 2 and the path selected has Unicode characters. The new "
+"path will not be added."
+msgstr ""
+"Vous utilisez Python 2 et le chemin sélectionné possède des caractères "
+"unicodes. Le nouveau chemin ne sera pas ajouté."
+
+#: spyder/widgets/pathmanager.py:283
msgid ""
"This directory is already included in Spyder path list.
Do you want to "
"move it to the top of the list?"
@@ -4556,7 +4760,7 @@ msgstr "Créer"
msgid "Create new project"
msgstr "Créer un nouveau projet"
-#: spyder/widgets/projects/type/__init__.py:216
+#: spyder/widgets/projects/type/__init__.py:223
msgid "Empty project"
msgstr "Projet vide"
@@ -4568,78 +4772,106 @@ msgstr "Projet Python"
msgid "Python package"
msgstr "Paquet Python"
-#: spyder/widgets/pydocgui.py:110
+#: spyder/widgets/pydocgui.py:117
msgid "Module or package:"
msgstr "Module ou paquet :"
-#: spyder/widgets/reporterror.py:121
-msgid "Spyder internal error"
-msgstr "Erreur interne de Spyder"
-
-#: spyder/widgets/reporterror.py:129
-msgid ""
-"Spyder has encountered an internal problem
\n"
-" Before reporting it, please consult our comprehensive \n"
-" Troubleshooting Guide \n"
-" which should help solve most issues, and search for \n"
-" known bugs matching your error \n"
-" message or problem description for a quicker solution.\n"
-"
\n"
-" If you don't find anything, please enter a detailed step-by-"
-"step \n"
-" description (in English) of what led up to the problem "
-"below. \n"
-" Issue reports without a clear way to reproduce them will be \n"
-" closed.
\n"
-" Thanks for helping us making Spyder better for everyone!\n"
-" "
-msgstr ""
-"Spyder a rencontré un problème interne
\n"
-" Avant de le signaler, veuillez d'abord consulter notre \n"
-" Guide de Dépannage détaillé \n"
-" qui permet de résoudre la majorité des problèmes et chercher \n"
-" des problèmes déjà signalés "
-"correspondant \n"
-" au message d'erreur ou à la description de votre problème. "
-"Cela permet \n"
-" souvent d'obtenir une solution rapidement.\n"
-"
\n"
-" Si cela n'aide pas, veuillez décrire étape par étape (en "
-"anglais) \n"
-" ce qui a conduit au problème ci-dessous. \n"
-" Les rapports d'erreurs sans description claire permettant de "
-"les reproduire \n"
-" seront fermés.
\n"
-" Merci de nous aider à améliorer Spyder !\n"
-" "
-
-#: spyder/widgets/reporterror.py:163
-msgid "Hide all future errors this session"
+#: spyder/widgets/reporterror.py:128
+msgid "Issue reporter"
+msgstr "Rapporteur d'erreur"
+
+#: spyder/widgets/reporterror.py:136
+msgid "Please fill the following information"
+msgstr "Veuillez entrer les informations suivantes"
+
+#: spyder/widgets/reporterror.py:138
+msgid "Spyder has encountered an internal problem!"
+msgstr "Spyder a rencontré un problème interne !"
+
+#: spyder/widgets/reporterror.py:140
+msgid ""
+"{title}
Before reporting this problem, please consult our "
+"comprehensive Troubleshooting Guide "
+"which should help solve most issues, and search for known bugs matching your error message or problem "
+"description for a quicker solution."
+msgstr ""
+"{title}
Avant de rapporter cette erreur, merci de consulter "
+"le Troubleshooting Guide détaillé qui "
+"permet de résoudre la majorité des problèmes et de chercher des erreurs déjà rapportées similaires à la vôtre afin "
+"d'obtenir une solution plus rapide."
+
+#: spyder/widgets/reporterror.py:158 spyder/widgets/reporterror.py:190
+msgid "{} more characters to go..."
+msgstr "Encore {} caractères nécessaires.."
+
+#: spyder/widgets/reporterror.py:162
+msgid "Title: {}"
+msgstr "Titre : {}"
+
+#: spyder/widgets/reporterror.py:168
+msgid "Steps to reproduce: {}"
+msgstr "Etapes pour reproduire : {}"
+
+#: spyder/widgets/reporterror.py:169
+msgid ""
+"Please enter a detailed step-by-step description (in English) of what led up "
+"to the problem below. Issue reports without a clear way to reproduce them "
+"will be closed."
+msgstr ""
+"Veuillez détailler étape par étape et en anglais ce qui a conduit au "
+"problème ci-dessous. Les rapports d'erreur sans façon claire de reproduire "
+"le problème seront fermés."
+
+#: spyder/widgets/reporterror.py:194
+msgid "Hide all future errors during this session"
msgstr "Masquer toutes les futures erreurs pour cette session"
-#: spyder/widgets/reporterror.py:171
+#: spyder/widgets/reporterror.py:201
msgid "Submit to Github"
msgstr "Soumettre à Github"
-#: spyder/widgets/reporterror.py:175 spyder/widgets/reporterror.py:227
+#: spyder/widgets/reporterror.py:205 spyder/widgets/reporterror.py:312
msgid "Show details"
msgstr "Afficher les détails"
-#: spyder/widgets/reporterror.py:178
+#: spyder/widgets/reporterror.py:210
+#: spyder/widgets/variableexplorer/arrayeditor.py:740
+#: spyder/widgets/variableexplorer/collectionseditor.py:1397
+#: spyder/widgets/variableexplorer/dataframeeditor.py:756
+#: spyder/widgets/variableexplorer/texteditor.py:72
msgid "Close"
msgstr "Fermer"
-#: spyder/widgets/reporterror.py:235
+#: spyder/widgets/reporterror.py:286
+msgid ""
+"An error occurred while trying to send the issue to Github automatically. "
+"Would you like to open it manually?
If so, please make sure to paste "
+"your clipboard into the issue report box that will appear in a new browser "
+"tab before clicking Submit on that page."
+msgstr ""
+"Une erreur est survenue pendant l'envoi automatique du rapport d'erreur à "
+"Github. Souhaitez vous l'ouvrir manuellement ?
Dans ce cas, avant de "
+"cliquer sur Submit, bien s'assurer de ne pas oublier de coller le "
+"contenu du presse papier dans le rapport qui va s'ouvrir dans un nouvel "
+"onglet du navigateur internet."
+
+#: spyder/widgets/reporterror.py:320
msgid "Hide details"
msgstr "Masquer les détails"
-#: spyder/widgets/reporterror.py:243
+#: spyder/widgets/reporterror.py:329 spyder/widgets/reporterror.py:337
msgid "more characters to go..."
msgstr "ajouter encore des caractères..."
-#: spyder/widgets/reporterror.py:245
-msgid "Submission enabled; thanks!"
-msgstr "Contribution possible; merci !"
+#: spyder/widgets/reporterror.py:331
+msgid "Description complete; thanks!"
+msgstr "Description complète ; merci !"
+
+#: spyder/widgets/reporterror.py:339
+msgid "Title complete; thanks!"
+msgstr "Titre complet ; merci !"
#: spyder/widgets/shell.py:131
msgid "Save history log..."
@@ -4687,27 +4919,27 @@ msgstr "Aller à la ligne :"
msgid "Line count:"
msgstr "Nombre de lignes :"
-#: spyder/widgets/sourcecode/codeeditor.py:1327
+#: spyder/widgets/sourcecode/codeeditor.py:1334
msgid "Breakpoint"
msgstr "Point d'arrêt"
-#: spyder/widgets/sourcecode/codeeditor.py:1328
+#: spyder/widgets/sourcecode/codeeditor.py:1335
msgid "Condition:"
msgstr "Condition :"
-#: spyder/widgets/sourcecode/codeeditor.py:1733
+#: spyder/widgets/sourcecode/codeeditor.py:1740
msgid "Code analysis"
msgstr "Analyse de code"
-#: spyder/widgets/sourcecode/codeeditor.py:1787
+#: spyder/widgets/sourcecode/codeeditor.py:1794
msgid "To do"
msgstr "À faire"
-#: spyder/widgets/sourcecode/codeeditor.py:2147
+#: spyder/widgets/sourcecode/codeeditor.py:2154
msgid "Removal error"
msgstr "Erreur de suppression"
-#: spyder/widgets/sourcecode/codeeditor.py:2148
+#: spyder/widgets/sourcecode/codeeditor.py:2155
msgid ""
"It was not possible to remove outputs from this notebook. The error is:\n"
"\n"
@@ -4715,15 +4947,15 @@ msgstr ""
"Impossible d'effacer les résultats de ce notebook :\n"
"\n"
-#: spyder/widgets/sourcecode/codeeditor.py:2696
+#: spyder/widgets/sourcecode/codeeditor.py:2703
msgid "Clear all ouput"
msgstr "Effacer tous les résultats"
-#: spyder/widgets/sourcecode/codeeditor.py:2702
+#: spyder/widgets/sourcecode/codeeditor.py:2709
msgid "Go to definition"
msgstr "Aller à la définition de l'objet"
-#: spyder/widgets/sourcecode/codeeditor.py:2735
+#: spyder/widgets/sourcecode/codeeditor.py:2742
msgid "Zoom reset"
msgstr "Réinitialisation du zoom"
@@ -4780,100 +5012,100 @@ msgstr "Naviguer dans les onglets"
msgid "Close current tab"
msgstr "Fermer l'onglet"
-#: spyder/widgets/variableexplorer/arrayeditor.py:511
+#: spyder/widgets/variableexplorer/arrayeditor.py:509
msgid "It was not possible to copy values for this array"
msgstr "Impossible de copier les valeurs de ce tableau"
-#: spyder/widgets/variableexplorer/arrayeditor.py:546
-#: spyder/widgets/variableexplorer/arrayeditor.py:579
-#: spyder/widgets/variableexplorer/dataframeeditor.py:703
-#: spyder/widgets/variableexplorer/dataframeeditor.py:748
+#: spyder/widgets/variableexplorer/arrayeditor.py:545
+#: spyder/widgets/variableexplorer/arrayeditor.py:578
+#: spyder/widgets/variableexplorer/dataframeeditor.py:728
+#: spyder/widgets/variableexplorer/dataframeeditor.py:787
msgid "Format"
msgstr "Format"
-#: spyder/widgets/variableexplorer/arrayeditor.py:551
-#: spyder/widgets/variableexplorer/dataframeeditor.py:707
+#: spyder/widgets/variableexplorer/arrayeditor.py:550
+#: spyder/widgets/variableexplorer/dataframeeditor.py:732
msgid "Resize"
msgstr "Ajuster"
-#: spyder/widgets/variableexplorer/arrayeditor.py:554
-#: spyder/widgets/variableexplorer/dataframeeditor.py:711
+#: spyder/widgets/variableexplorer/arrayeditor.py:553
+#: spyder/widgets/variableexplorer/dataframeeditor.py:736
msgid "Background color"
msgstr "Couleur de fond"
-#: spyder/widgets/variableexplorer/arrayeditor.py:580
-#: spyder/widgets/variableexplorer/dataframeeditor.py:749
+#: spyder/widgets/variableexplorer/arrayeditor.py:579
+#: spyder/widgets/variableexplorer/dataframeeditor.py:788
msgid "Float formatting"
msgstr "Format de flottant"
-#: spyder/widgets/variableexplorer/arrayeditor.py:588
+#: spyder/widgets/variableexplorer/arrayeditor.py:587
msgid "Format (%s) is incorrect"
msgstr "Le format (%s) n'est pas valide"
-#: spyder/widgets/variableexplorer/arrayeditor.py:624
+#: spyder/widgets/variableexplorer/arrayeditor.py:625
msgid "Arrays with more than 3 dimensions are not supported"
msgstr "Les tableaux de plus de trois dimensions ne sont pas pris en charge"
-#: spyder/widgets/variableexplorer/arrayeditor.py:628
+#: spyder/widgets/variableexplorer/arrayeditor.py:629
msgid "The 'xlabels' argument length do no match array column number"
msgstr ""
"La taille de 'xlabels' ne correspond pas au nombre de colonnes du tableau"
-#: spyder/widgets/variableexplorer/arrayeditor.py:632
+#: spyder/widgets/variableexplorer/arrayeditor.py:633
msgid "The 'ylabels' argument length do no match array row number"
msgstr ""
"La taille de 'ylabels' ne correspond pas au nombre de lignes du tableau"
-#: spyder/widgets/variableexplorer/arrayeditor.py:639
+#: spyder/widgets/variableexplorer/arrayeditor.py:640
msgid "%s arrays"
msgstr "Les tableaux %s"
-#: spyder/widgets/variableexplorer/arrayeditor.py:640
+#: spyder/widgets/variableexplorer/arrayeditor.py:641
msgid "%s are currently not supported"
msgstr "%s ne sont actuellement pas pris en charge"
-#: spyder/widgets/variableexplorer/arrayeditor.py:647
+#: spyder/widgets/variableexplorer/arrayeditor.py:648
msgid "NumPy array"
msgstr "Tableaux NumPy"
-#: spyder/widgets/variableexplorer/arrayeditor.py:649
-#: spyder/widgets/variableexplorer/arrayeditor.py:806
+#: spyder/widgets/variableexplorer/arrayeditor.py:650
+#: spyder/widgets/variableexplorer/arrayeditor.py:828
msgid "Array editor"
msgstr "Éditeur de tableaux"
-#: spyder/widgets/variableexplorer/arrayeditor.py:651
+#: spyder/widgets/variableexplorer/arrayeditor.py:652
msgid "read only"
msgstr "lecture seule"
-#: spyder/widgets/variableexplorer/arrayeditor.py:681
+#: spyder/widgets/variableexplorer/arrayeditor.py:685
msgid "Record array fields:"
msgstr "Champs du tableau :"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Data"
msgstr "Données"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Mask"
msgstr "Masque"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Masked data"
msgstr "Données masquées"
-#: spyder/widgets/variableexplorer/arrayeditor.py:704
+#: spyder/widgets/variableexplorer/arrayeditor.py:708
msgid "Axis:"
msgstr "Axe :"
-#: spyder/widgets/variableexplorer/arrayeditor.py:709
+#: spyder/widgets/variableexplorer/arrayeditor.py:713
msgid "Index:"
msgstr "Indice :"
-#: spyder/widgets/variableexplorer/arrayeditor.py:722
+#: spyder/widgets/variableexplorer/arrayeditor.py:726
msgid "Warning: changes are applied separately"
msgstr "Attention : les changements seront pris en compte séparément"
-#: spyder/widgets/variableexplorer/arrayeditor.py:723
+#: spyder/widgets/variableexplorer/arrayeditor.py:727
msgid ""
"For performance reasons, changes applied to masked array won't be reflected "
"in array's data (and vice-versa)."
@@ -4882,47 +5114,54 @@ msgstr ""
"masquées ne seront pas reflétées sur les données du tableau (et "
"réciproquement)."
-#: spyder/widgets/variableexplorer/collectionseditor.py:126
+#: spyder/widgets/variableexplorer/arrayeditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:1392
+#: spyder/widgets/variableexplorer/dataframeeditor.py:751
+#: spyder/widgets/variableexplorer/texteditor.py:67
+msgid "Save and Close"
+msgstr "Enregistrer et Fermer"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:151
msgid "Index"
msgstr "Indice"
-#: spyder/widgets/variableexplorer/collectionseditor.py:131
+#: spyder/widgets/variableexplorer/collectionseditor.py:156
msgid "Tuple"
msgstr "Tuple"
-#: spyder/widgets/variableexplorer/collectionseditor.py:134
+#: spyder/widgets/variableexplorer/collectionseditor.py:159
msgid "List"
msgstr "Liste"
-#: spyder/widgets/variableexplorer/collectionseditor.py:137
+#: spyder/widgets/variableexplorer/collectionseditor.py:162
msgid "Dictionary"
msgstr "Dictionnaire"
-#: spyder/widgets/variableexplorer/collectionseditor.py:139
+#: spyder/widgets/variableexplorer/collectionseditor.py:164
msgid "Key"
msgstr "Clé"
-#: spyder/widgets/variableexplorer/collectionseditor.py:144
+#: spyder/widgets/variableexplorer/collectionseditor.py:169
msgid "Attribute"
msgstr "Attribut"
-#: spyder/widgets/variableexplorer/collectionseditor.py:148
+#: spyder/widgets/variableexplorer/collectionseditor.py:173
msgid "elements"
msgstr "éléments"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Size"
msgstr "Taille"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Type"
msgstr "Type"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Value"
msgstr "Valeur"
-#: spyder/widgets/variableexplorer/collectionseditor.py:417
+#: spyder/widgets/variableexplorer/collectionseditor.py:450
msgid ""
"Opening this variable can be slow\n"
"\n"
@@ -4932,7 +5171,7 @@ msgstr ""
"\n"
"Souhaitez-vous néanmoins continuer ?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:428
+#: spyder/widgets/variableexplorer/collectionseditor.py:461
msgid ""
"Spyder was unable to retrieve the value of this variable from the console."
"
The error mesage was:
%s"
@@ -4940,149 +5179,165 @@ msgstr ""
"Impossible de récupérer la valeur de cette variable depuis la console. "
"
Message d'erreur :
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:608
+#: spyder/widgets/variableexplorer/collectionseditor.py:643
msgid "Edit item"
msgstr "Modifier"
-#: spyder/widgets/variableexplorer/collectionseditor.py:609
+#: spyder/widgets/variableexplorer/collectionseditor.py:644
msgid "Unable to assign data to item.
Error message:
%s"
msgstr ""
"Impossible d'assigner la valeur de l'objet.
Message d'erreur :"
"
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:669
+#: spyder/widgets/variableexplorer/collectionseditor.py:705
msgid "Resize rows to contents"
msgstr "Ajuster la hauteur des lignes"
-#: spyder/widgets/variableexplorer/collectionseditor.py:680
-#: spyder/widgets/variableexplorer/collectionseditor.py:1030
-#: spyder/widgets/variableexplorer/collectionseditor.py:1047
+#: spyder/widgets/variableexplorer/collectionseditor.py:716
+#: spyder/widgets/variableexplorer/collectionseditor.py:1066
+#: spyder/widgets/variableexplorer/collectionseditor.py:1083
msgid "Plot"
msgstr "Tracer"
-#: spyder/widgets/variableexplorer/collectionseditor.py:684
+#: spyder/widgets/variableexplorer/collectionseditor.py:720
msgid "Histogram"
msgstr "Histogramme"
-#: spyder/widgets/variableexplorer/collectionseditor.py:688
+#: spyder/widgets/variableexplorer/collectionseditor.py:724
msgid "Show image"
msgstr "Afficher l'image"
-#: spyder/widgets/variableexplorer/collectionseditor.py:692
-#: spyder/widgets/variableexplorer/collectionseditor.py:1055
+#: spyder/widgets/variableexplorer/collectionseditor.py:728
+#: spyder/widgets/variableexplorer/collectionseditor.py:1091
msgid "Save array"
msgstr "Enregistrer le tableau"
-#: spyder/widgets/variableexplorer/collectionseditor.py:696
-#: spyder/widgets/variableexplorer/collectionseditor.py:994
-#: spyder/widgets/variableexplorer/collectionseditor.py:1002
+#: spyder/widgets/variableexplorer/collectionseditor.py:732
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Insert"
msgstr "Insérer"
-#: spyder/widgets/variableexplorer/collectionseditor.py:709
-#: spyder/widgets/variableexplorer/collectionseditor.py:955
+#: spyder/widgets/variableexplorer/collectionseditor.py:745
+#: spyder/widgets/variableexplorer/collectionseditor.py:991
msgid "Duplicate"
msgstr "Dupliquer"
-#: spyder/widgets/variableexplorer/collectionseditor.py:932
+#: spyder/widgets/variableexplorer/collectionseditor.py:968
msgid "Do you want to remove the selected item?"
msgstr "Souhaitez-vous supprimer l'élément sélectionné ?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:933
+#: spyder/widgets/variableexplorer/collectionseditor.py:969
msgid "Do you want to remove all selected items?"
msgstr "Souhaitez-vous supprimer les éléments sélectionnés ?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:953
+#: spyder/widgets/variableexplorer/collectionseditor.py:989
msgid "New variable name:"
msgstr "Nouveau nom de variable :"
-#: spyder/widgets/variableexplorer/collectionseditor.py:956
+#: spyder/widgets/variableexplorer/collectionseditor.py:992
msgid "Variable name:"
msgstr "Nom de variable :"
-#: spyder/widgets/variableexplorer/collectionseditor.py:994
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
msgid "Key:"
msgstr "Clé :"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1002
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Value:"
msgstr "Valeur :"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1018
+#: spyder/widgets/variableexplorer/collectionseditor.py:1054
msgid "Import error"
msgstr "Erreur d'import"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1019
+#: spyder/widgets/variableexplorer/collectionseditor.py:1055
msgid "Please install matplotlib or guiqwt."
msgstr "Merci d'installer matplotlib ou guiqwt."
-#: spyder/widgets/variableexplorer/collectionseditor.py:1031
+#: spyder/widgets/variableexplorer/collectionseditor.py:1067
msgid "Unable to plot data.
Error message:
%s"
msgstr ""
"Impossible d'afficher les données
Message d'erreur :
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1048
+#: spyder/widgets/variableexplorer/collectionseditor.py:1084
msgid "Unable to show image.
Error message:
%s"
msgstr "Impossible d'afficher l'image
Message d'erreur :
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1071
+#: spyder/widgets/variableexplorer/collectionseditor.py:1097
+msgid "NumPy arrays"
+msgstr "Tableaux NumPy"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1107
msgid "Unable to save array
Error message:
%s"
msgstr ""
"Impossible d'enregistrer le tableau
Message d'erreur :
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1096
+#: spyder/widgets/variableexplorer/collectionseditor.py:1132
msgid "It was not possible to copy this array"
msgstr "Impossible de copier cet tableaux"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1121
+#: spyder/widgets/variableexplorer/collectionseditor.py:1144
+msgid "It was not possible to copy this dataframe"
+msgstr "Impossible de copier ce dataframe"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1166
msgid "Clipboard contents"
msgstr "Contenu du presse-papiers"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1136
+#: spyder/widgets/variableexplorer/collectionseditor.py:1181
msgid "Import from clipboard"
msgstr "Importer depuis le presse-papiers"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1138
+#: spyder/widgets/variableexplorer/collectionseditor.py:1183
msgid "Empty clipboard"
msgstr "Presse-papiers vide"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1139
+#: spyder/widgets/variableexplorer/collectionseditor.py:1184
msgid "Nothing to be imported from clipboard."
msgstr "Aucune donnée ne peut être importée depuis le presse-papiers."
-#: spyder/widgets/variableexplorer/dataframeeditor.py:597
+#: spyder/widgets/variableexplorer/dataframeeditor.py:321
+msgid ""
+"It is not possible to display this value because\n"
+"an error ocurred while trying to do it"
+msgstr ""
+"Il n'est pas possible d'afficher cette valeur car\n"
+"une erreur est survenue en essayant de le faire"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To bool"
msgstr "Booléen"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:597
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To complex"
msgstr "Complexe"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:598
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To float"
msgstr "Flottant"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:598
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To int"
msgstr "Entier"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:599
+#: spyder/widgets/variableexplorer/dataframeeditor.py:623
msgid "To str"
msgstr "Caractères"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:683
+#: spyder/widgets/variableexplorer/dataframeeditor.py:707
msgid "%s editor"
msgstr "Éditeur de %s"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:717
+#: spyder/widgets/variableexplorer/dataframeeditor.py:742
msgid "Column min/max"
msgstr "Colonne min/max"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:757
+#: spyder/widgets/variableexplorer/dataframeeditor.py:796
msgid "Format ({}) is incorrect"
msgstr "Le format (%s) n'est pas valide"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:761
+#: spyder/widgets/variableexplorer/dataframeeditor.py:800
msgid "Format ({}) should start with '%'"
msgstr "Le format ({}) devrait commencer par ‘%’"
@@ -5194,34 +5449,34 @@ msgstr ""
"Impossible de passer à l'étape suivante
Merci de vérifier "
"votre saisie.
Message d'erreur :
%s"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:181
-#: spyder/widgets/variableexplorer/namespacebrowser.py:385
+#: spyder/widgets/variableexplorer/namespacebrowser.py:184
+#: spyder/widgets/variableexplorer/namespacebrowser.py:397
msgid "Import data"
msgstr "Importer des données"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:184
-#: spyder/widgets/variableexplorer/namespacebrowser.py:465
-#: spyder/widgets/variableexplorer/namespacebrowser.py:479
+#: spyder/widgets/variableexplorer/namespacebrowser.py:187
+#: spyder/widgets/variableexplorer/namespacebrowser.py:477
+#: spyder/widgets/variableexplorer/namespacebrowser.py:491
msgid "Save data"
msgstr "Enregistrer les données"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:189
+#: spyder/widgets/variableexplorer/namespacebrowser.py:192
msgid "Save data as..."
msgstr "Enregistrer les données sous..."
-#: spyder/widgets/variableexplorer/namespacebrowser.py:201
+#: spyder/widgets/variableexplorer/namespacebrowser.py:204
msgid "Exclude references which name starts with an underscore"
msgstr "Exclure les références dont le nom commence par un tiret bas"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:209
+#: spyder/widgets/variableexplorer/namespacebrowser.py:212
msgid "Exclude references which name is uppercase"
msgstr "Exclure les références dont le nom s'écrit en lettres capitales"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:216
+#: spyder/widgets/variableexplorer/namespacebrowser.py:219
msgid "Exclude references which name starts with an uppercase character"
msgstr "Exclure les références dont le nom commence par une lettre majuscule"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:224
+#: spyder/widgets/variableexplorer/namespacebrowser.py:227
msgid ""
"Exclude references to unsupported data types (i.e. which won't be handled/"
"saved correctly)"
@@ -5229,7 +5484,15 @@ msgstr ""
"Exclure les références dont le type n'est pas supporté par l'espace de "
"travail (en particulier, l'enregistrement ne fonctionnera pas)"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:405
+#: spyder/widgets/variableexplorer/namespacebrowser.py:306
+msgid ""
+"The object you are trying to modify is too big to be sent back to the "
+"kernel. Therefore, your modifications won't take place."
+msgstr ""
+"L'objet que vous tentez de modifier est trop volumineux pour être renvoyé "
+"vers le noyau. Les modifications ne seront donc pas prises en compte."
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:417
msgid ""
"Unsupported file extension '%s'
Would you like to import it "
"anyway (by selecting a known file format)?"
@@ -5237,40 +5500,29 @@ msgstr ""
"Extension de fichier non pris en charge '%s'
Souhaitez-vous "
"néanmoins ouvrir ce fichier (en choisissant un format de fichier connu) ?"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:413
+#: spyder/widgets/variableexplorer/namespacebrowser.py:425
msgid "Open file as:"
msgstr "Ouvrir le fichier en tant que :"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:447
+#: spyder/widgets/variableexplorer/namespacebrowser.py:459
msgid "Unable to load '%s'
Error message:
%s"
msgstr "Impossible d'ouvrir '%s'
Message d'erreur :
%s"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:480
+#: spyder/widgets/variableexplorer/namespacebrowser.py:492
msgid "Unable to save current workspace
Error message:
%s"
msgstr ""
"Impossible d'enregistrer l'espace de travail
Message d'erreur :"
"
%s"
-#: spyder/widgets/variableexplorer/texteditor.py:74
+#: spyder/widgets/variableexplorer/texteditor.py:84
msgid "Text editor"
msgstr "Éditeur de texte"
-#: spyder/widgets/variableexplorer/utils.py:31
-msgid "View and edit DataFrames and Series in the Variable Explorer"
-msgstr ""
-"Voir et éditer les Dataframes et les Series dans l'explorateur de variables"
-
-#: spyder/widgets/variableexplorer/utils.py:36
-msgid "View and edit two and three dimensional arrays in the Variable Explorer"
-msgstr ""
-"Voir et éditer Tableaux de deux et trois dimensions dans l'explorateur de "
-"variables"
-
-#: spyder/workers/updates.py:90 spyder/workers/updates.py:92
+#: spyder/workers/updates.py:128 spyder/workers/updates.py:130
msgid "Unable to retrieve information."
msgstr "Impossible de charger l'information."
-#: spyder/workers/updates.py:94
+#: spyder/workers/updates.py:132
msgid ""
"Unable to connect to the internet.
Make sure the connection is "
"working properly."
@@ -5278,10 +5530,155 @@ msgstr ""
"Impossible de se connecter à internet.
Vérifiez que votre accès à "
"internet fonctionne correctement."
-#: spyder/workers/updates.py:97
+#: spyder/workers/updates.py:135
msgid "Unable to check for updates."
msgstr "Impossible de vérifier les mises à jour."
+#~ msgid "ViTables"
+#~ msgstr "ViTables"
+
+#~ msgid ""
+#~ "Update LANGUAGE_CODES (inside config/base.py) if a new translation has "
+#~ "been added to Spyder"
+#~ msgstr ""
+#~ "Mettre à jour LANGUAGE_CODES (à l'intérieur de config/base.py) si une "
+#~ "nouvelle traduction a été ajoutée à Spyder"
+
+#~ msgid ""
+#~ "Please enter the connection info of the kernel you want to connect to. "
+#~ "For that you can either select its JSON connection file using the "
+#~ "Browse button, or write directly its id, in case it's a local "
+#~ "kernel (for example kernel-3764.json or just 3764)."
+#~ msgstr ""
+#~ "Entrez les informations de connexion du noyau auquel vous voulez vous "
+#~ "connecter. Pour cela vous pouvez soit sélectionner son fichier de "
+#~ "connexion JSON en utilisant le bouton Parcourir, ou écrivez "
+#~ "directement son identifiant si c'est un noyau local (Exemple : "
+#~ "kernel-3764.json ou juste 3764)."
+
+#~ msgid "Connection info:"
+#~ msgstr "Information de connexion :"
+
+#~ msgid "Ssh key"
+#~ msgstr "Clé ssh"
+
+#~ msgid "Password"
+#~ msgstr "Mot de passe"
+
+#~ msgid "Select ssh key"
+#~ msgstr "Sélectionner une clé ssh"
+
+#~ msgid "PyQt4 Reference Guide"
+#~ msgstr "Guide de référence de PyQt4"
+
+#~ msgid "PyQt4 API Reference"
+#~ msgstr "Documentation de l'API de PyQt4"
+
+#~ msgid "Qt examples"
+#~ msgstr "Exemples Qt"
+
+#~ msgid "Use the greedy completer"
+#~ msgstr "Utiliser la complétion avancée"
+
+#~ msgid ""
+#~ "This error was most probably caused by installing Spyder in a directory "
+#~ "with non-ascii characters (i.e. characters with tildes, apostrophes or "
+#~ "non-latin symbols).
To fix it, please reinstall Spyder in a "
+#~ "different location."
+#~ msgstr ""
+#~ "Cette erreur est probablement causée par l’installation de Spyder dans un "
+#~ "répertoire avec des caractères non ascii (c’est-à-dire des caractères "
+#~ "avec des tildes, des apostrophes ou des symboles non latins).
"
+#~ "Pour le réparer, réinstallez Spyder dans un endroit différent."
+
+#~ msgid "Supported files"
+#~ msgstr "Fichiers compatibles"
+
+#~ msgid "All files (*.*)"
+#~ msgstr "Tous les fichiers (*.*)"
+
+#~ msgid "Spyder data files"
+#~ msgstr "Fichiers Spyder"
+
+#~ msgid "NumPy zip arrays"
+#~ msgstr "Tableaux NumPy compressés"
+
+#~ msgid "Matlab files"
+#~ msgstr "Fichiers Matlab"
+
+#~ msgid "CSV text files"
+#~ msgstr "Fichiers texte CSV"
+
+#~ msgid "JPEG images"
+#~ msgstr "Images JPEG"
+
+#~ msgid "PNG images"
+#~ msgstr "Images PNG"
+
+#~ msgid "GIF images"
+#~ msgstr "Images GIF"
+
+#~ msgid "TIFF images"
+#~ msgstr "Images TIFF"
+
+#~ msgid "Pickle files"
+#~ msgstr "Fichiers pickle"
+
+#~ msgid "JSON files"
+#~ msgstr "Fichiers JSON"
+
+#~ msgid "Unsupported file type '%s'"
+#~ msgstr "Type de fichier non pris en charge '%s'"
+
+#~ msgid "Save"
+#~ msgstr "Enregistrer"
+
+#~ msgid "Spyder internal error"
+#~ msgstr "Erreur interne de Spyder"
+
+#~ msgid ""
+#~ "Spyder has encountered an internal problem
\n"
+#~ " Before reporting it, please consult our "
+#~ "comprehensive \n"
+#~ " Troubleshooting Guide \n"
+#~ " which should help solve most issues, and search for \n"
+#~ " known bugs matching your "
+#~ "error \n"
+#~ " message or problem description for a quicker solution.\n"
+#~ "
\n"
+#~ " If you don't find anything, please enter a detailed step-by-"
+#~ "step \n"
+#~ " description (in English) of what led up to the problem "
+#~ "below. \n"
+#~ " Issue reports without a clear way to reproduce them will "
+#~ "be \n"
+#~ " closed.
\n"
+#~ " Thanks for helping us making Spyder better for everyone!\n"
+#~ " "
+#~ msgstr ""
+#~ "Spyder a rencontré un problème interne
\n"
+#~ " Avant de le signaler, veuillez d'abord consulter notre \n"
+#~ " Guide de Dépannage détaillé \n"
+#~ " qui permet de résoudre la majorité des problèmes et "
+#~ "chercher \n"
+#~ " des problèmes déjà signalés "
+#~ "correspondant \n"
+#~ " au message d'erreur ou à la description de votre problème. "
+#~ "Cela permet \n"
+#~ " souvent d'obtenir une solution rapidement.\n"
+#~ "
\n"
+#~ " Si cela n'aide pas, veuillez décrire étape par étape (en "
+#~ "anglais) \n"
+#~ " ce qui a conduit au problème ci-dessous. \n"
+#~ " Les rapports d'erreurs sans description claire permettant "
+#~ "de les reproduire \n"
+#~ " seront fermés.
\n"
+#~ " Merci de nous aider à améliorer Spyder !\n"
+#~ " "
+
+#~ msgid "Submission enabled; thanks!"
+#~ msgstr "Contribution possible; merci !"
+
#~ msgid "Pop up internal console when internal errors appear"
#~ msgstr "Afficher la console interne en cas d'erreur inattendue"
@@ -5317,270 +5714,269 @@ msgstr "Impossible de vérifier les mises à jour."
#~ msgid "Reset IPython namespace"
#~ msgstr "Réinitialiser l'espace de noms de la console IPython"
-#~ msgid "Loading external console..."
-#~ msgstr "Chargement de la console externe..."
+#: spyder/plugins/breakpoints/plugin.py:45
+msgid "Breakpoints"
+msgstr "Points d'arrêt"
-#~ msgid "The Python console"
-#~ msgstr "Console IPython"
+#: spyder/plugins/breakpoints/plugin.py:80
+msgid "List breakpoints"
+msgstr "Liste des points d'arrêt"
-#~ msgid ""
-#~ "You can also run your code on a Python console. These consoles are useful "
-#~ "because they let you run a file in a console dedicated only to it.To "
-#~ "select this behavior, please press the F6 key.
By pressing "
-#~ "the button below and then focusing the Variable Explorer, you will notice "
-#~ "that Python consoles are also connected to that pane, and that the "
-#~ "Variable Explorer only shows the variables of the currently focused "
-#~ "console."
-#~ msgstr ""
-#~ "Vous pouvez également exécuter votre code dans une console Python. Ces "
-#~ "consoles sont utiles car elles vous permettent d'exécuter un fichier dans "
-#~ "une console dédiée uniquement à celui-ci. Pour sélectionner ce "
-#~ "comportement, appuyez sur la touche F6.
En appuyant sur le "
-#~ "bouton ci-dessous, puis en retournant sur l'explorateur de variables, "
-#~ "vous remarquerez que les consoles Python sont également connectées à ce "
-#~ "volet et que l'explorateur de variables ne montre que les variables de la "
-#~ "console actuellement sélectionnée."
-
-#~ msgid "Sort files according to full path"
-#~ msgstr "Classer les fichiers suivant leur chemin complet"
-
-#~ msgid "&Configure..."
-#~ msgstr "&Configurer..."
-
-#~ msgid "Show TODO/FIXME/XXX/HINT/TIP/@todo comments list"
-#~ msgstr ""
-#~ "Afficher la liste des commentaires du type TODO/FIXME/XXX/HINT/TIP/@todo"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "Condition"
+msgstr "Condition"
-#~ msgid "Interactive data plotting in the consoles"
-#~ msgstr "Visualisation interactive de données"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "File"
+msgstr "Fichier"
-#~ msgid "Python console"
-#~ msgstr "Console Python"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "Line"
+msgstr "Ligne"
-#~ msgid "One tab per script"
-#~ msgstr "Un onglet par script"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:201
+msgid "Clear this breakpoint"
+msgstr "Supprimer ce point d'arrêt"
-#~ msgid "Buffer: "
-#~ msgstr "Tampon : "
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:206
+msgid "Edit this breakpoint"
+msgstr "Supprimer ce point d'arrêt"
-#~ msgid "Merge process standard output/error channels"
-#~ msgstr "Fusionner les canaux de sortie et d'erreur du processus"
+#: spyder/plugins/pylint/plugin.py:36
+msgid "Save file before analyzing it"
+msgstr "Enregistrer le fichier avant de l'analyser"
-#~ msgid ""
-#~ "Merging the output channels of the process means that\n"
-#~ "the standard error won't be written in red anymore,\n"
-#~ "but this has the effect of speeding up display."
-#~ msgstr ""
-#~ "Fusionner les canaux de sortie et d'erreur du processus\n"
-#~ "signifie que les erreurs ne seront plus affichées en rouge,\n"
-#~ "mais cela entraînera également une amélioration des performances\n"
-#~ "d'affichage et une meilleure réactivité de la console."
+#: spyder/plugins/pylint/plugin.py:40
+msgid "The following option will be applied at next startup."
+msgstr "L'option suivante ne sera appliquée qu'au prochain démarrage."
+msgstr "Historique : "
-#~ msgid "Colorize standard error channel using ANSI escape codes"
-#~ msgstr "Coloriser le canal d'erreur standard (codes d'échappement ANSI)"
+#: spyder/plugins/pylint/plugin.py:44
+msgid " results"
+msgstr " résultats"
-#~ msgid ""
-#~ "This method is the only way to have colorized standard\n"
-#~ "error channel when the output channels have been merged."
-#~ msgstr ""
-#~ "Cette méthode est le seul moyen de coloriser le canal\n"
-#~ "d'erreur standard lorsque les canaux de sorties ont été fusionnés."
+#: spyder/plugins/pylint/plugin.py:47 spyder/plugins/profiler/plugin.py:33
+msgid "Results"
+msgstr "Résultats"
-#~ msgid ""
-#~ "This option will be applied the next time a Python console or a terminal "
-#~ "is opened."
-#~ msgstr ""
-#~ "Cette option sera prise en compte lors de la prochaine ouverture de "
-#~ "console (interpréteur Python ou terminal)."
+#: spyder/plugins/pylint/plugin.py:48
+msgid "Results are stored here:"
+msgstr "Les résultats sont stockés ici :"
-#~ msgid "Light background (white color)"
-#~ msgstr "Fond blanc"
+#: spyder/plugins/pylint/plugin.py:98
+#: spyder/plugins/pylint/widgets/pylintgui.py:83
+msgid "Static code analysis"
+msgstr "Analyse de code statique"
-#~ msgid "PYTHONSTARTUP replacement"
-#~ msgstr "Substitution de PYTHONSTARTUP"
+#: spyder/plugins/pylint/plugin.py:133
+msgid "Run static code analysis"
+msgstr "Démarrer l'analyse de code statique"
-#~ msgid ""
-#~ "This option will override the PYTHONSTARTUP environment variable which\n"
-#~ "defines the script to be executed during the Python console startup."
-#~ msgstr ""
-#~ "Cette option permet de remplacer le script de démarrage des consoles "
-#~ "Python défini par la\n"
-#~ "variable d'environnement PYTHONSTARTUP."
+#: spyder/plugins/pylint/widgets/pylintgui.py:117
+msgid "Results for "
+msgstr "Résultats pour "
-#~ msgid "Default PYTHONSTARTUP script"
-#~ msgstr "Script PYTHONSTARTUP par défaut"
+#: spyder/plugins/pylint/widgets/pylintgui.py:122
+msgid "Convention"
+msgstr "Convention"
-#~ msgid "Use the following startup script:"
-#~ msgstr "Utiliser le script de démarrage suivant :"
+#: spyder/plugins/pylint/widgets/pylintgui.py:124
+msgid "Refactor"
+msgstr "Factorisation"
-#~ msgid "Monitor"
-#~ msgstr "Moniteur"
+#: spyder/plugins/pylint/widgets/pylintgui.py:206
+msgid "Analyze"
+msgstr "Analyser"
-#~ msgid ""
-#~ "The monitor provides introspection features to console: code completion, "
-#~ "calltips and variable explorer. Because it relies on several modules, "
-#~ "disabling the monitor may be useful to accelerate console startup."
-#~ msgstr ""
-#~ "Le moniteur fournit à la console des fonctionnalités d'introspection "
-#~ "telles que la complétion de code, les info-bulles et l'explorateur de "
-#~ "variables. Parce qu'il nécessite l'import de nombreux modules, désactiver "
-#~ "le moniteur permet d'accélérer le démarrage de la console."
+#: spyder/plugins/pylint/widgets/pylintgui.py:207
+msgid "Run analysis"
+msgstr "Analyser le code source"
-#~ msgid "Enable monitor"
-#~ msgstr "Activer le moniteur"
+#: spyder/plugins/pylint/widgets/pylintgui.py:212
+msgid "Stop current analysis"
+msgstr "Arrêter l'analyse en cours"
-#~ msgid "Default library"
-#~ msgstr "Bibliothèque par défaut"
+#: spyder/plugins/pylint/widgets/pylintgui.py:218
+#: spyder/plugins/pylint/widgets/pylintgui.py:288
+msgid "Select Python file"
+msgstr "Sélectionner un fichier Python"
-#~ msgid "Qt-Python Bindings"
-#~ msgstr "Sélection de la bibliothèque d'interfaçage Qt"
+#: spyder/plugins/pylint/widgets/pylintgui.py:224
+#: spyder/plugins/profiler/widgets/profilergui.py:102
+msgid "Output"
+msgstr "Sortie"
-#~ msgid "Library:"
-#~ msgstr "Module:"
+#: spyder/plugins/pylint/widgets/pylintgui.py:226
+msgid "Complete output"
+msgstr "Sortie complète"
-#~ msgid ""
-#~ "This option will act on
libraries such as Matplotlib, guidata or ETS"
-#~ msgstr ""
-#~ "Cette option est prise en charge par les bibliothèques telles que "
-#~ "Matplotlib, guidata ou ETS"
+#: spyder/plugins/pylint/widgets/pylintgui.py:260
+msgid "Pylint script was not found. Please add \"%s\" to PATH."
+msgstr "Le script pylint est introuvable. Merci d'ajouter \"%s\" au PATH."
-#~ msgid ""
-#~ "Decide which backend to use to display graphics. If unsure, please select "
-#~ "the Automatic backend.
Note: We support a very "
-#~ "limited number of backends in our Python consoles. If you prefer to work "
-#~ "with a different one, please use an IPython console."
-#~ msgstr ""
-#~ "Décidez quel backend utiliser pour afficher les graphiques. Si vous "
-#~ "n'êtes pas sûr, sélectionnez le backend Automatique. "
-#~ "
Remarque: Nous soutenons un nombre très limité de backends "
-#~ "dans nos consoles Python. Si vous préférez travailler avec un autre, "
-#~ "utilisez une console IPython."
+#: spyder/plugins/pylint/widgets/pylintgui.py:263
+msgid "Please install pylint:"
+msgstr "Merci d'installer au préalable pylint :"
-#~ msgid "None"
-#~ msgstr "Aucun"
+#: spyder/plugins/pylint/widgets/pylintgui.py:326
+msgid "Pylint output"
+msgstr "Analyse Pylint"
-#~ msgid "Enthought Tool Suite"
-#~ msgstr "Enthought Tool Suite"
+#: spyder/plugins/pylint/widgets/pylintgui.py:465
+msgid "Source code has not been rated yet."
+msgstr "Le code source n'a pas encore été analysé."
-#~ msgid ""
-#~ "Enthought Tool Suite (ETS) supports PyQt4 (qt4) and wxPython (wx) "
-#~ "graphical user interfaces."
-#~ msgstr ""
-#~ "Le logiciel Enthought Tool Suite (ETS) prend en charge les interfaces "
-#~ "graphiques PyQt4 (qt4) et wxPython (wx)."
+#: spyder/plugins/pylint/widgets/pylintgui.py:471
+msgid "Analysis did not succeed (see output for more details)."
+msgstr "L'analyse n'a pas réussi (voir la sortie pour plus de détails)."
-#~ msgid "ETS_TOOLKIT:"
-#~ msgstr "ETS_TOOLKIT:"
+#: spyder/plugins/pylint/widgets/pylintgui.py:484
+msgid "Global evaluation:"
+msgstr "Évaluation globale :"
-#~ msgid "External modules"
-#~ msgstr "Modules externes"
+#: spyder/plugins/pylint/widgets/pylintgui.py:488
+msgid "previous run:"
+msgstr "analyse précédente :"
-#~ msgid ""
-#~ "No Python console is currently selected to run %s.
Please "
-#~ "select or open a new Python console and try again."
-#~ msgstr ""
-#~ "Aucune console Python n'est actuellement sélectionnée pour exécuter "
-#~ "%s.
Merci de sélectionner ou d'ouvrir une nouvelle console "
-#~ "Python et de réessayer."
+#: spyder/plugins/profiler/plugin.py:34
+msgid ""
+"Profiler plugin results (the output of python's profile/cProfile)\n"
+"are stored here:"
+msgstr "Les résultats du profileur Python sont stockés ici :"
-#~ msgid ""
-#~ "%s is already running in a separate process.\n"
-#~ "Do you want to kill the process before starting a new one?"
-#~ msgstr ""
-#~ "%s est déjà en cours d'exécution dans un processus séparé.\n"
-#~ "Souhaitez-vous tuer ce processus avant d'en démarrer un autre ?"
+#: spyder/plugins/profiler/plugin.py:75
+msgid "Profiler"
+msgstr "Profileur"
-#~ msgid "Command Window"
-#~ msgstr "Invite de commandes"
+#: spyder/plugins/profiler/plugin.py:104
+#: spyder/plugins/profiler/widgets/profilergui.py:81
+msgid "Profile"
+msgstr "Profiler"
-#~ msgid "Open a &Python console"
-#~ msgstr "Ouvrir une console &Python"
+#: spyder/plugins/profiler/widgets/profilergui.py:82
+msgid "Run profiler"
+msgstr "Exécuter le profileur"
-#~ msgid "Open &command prompt"
-#~ msgstr "Ouvrir un invite de &commandes"
+#: spyder/plugins/profiler/widgets/profilergui.py:88
+msgid "Stop current profiling"
+msgstr "Arrêter le processus en cours"
-#~ msgid "Open a Windows command prompt"
-#~ msgstr "Ouvrir un invite de commandes Windows"
+#: spyder/plugins/profiler/widgets/profilergui.py:96
+#: spyder/plugins/profiler/widgets/profilergui.py:219
+msgid "Select Python script"
+msgstr "Sélectionner un script Python"
-#~ msgid "Open a &terminal"
-#~ msgstr "Ouvrir un &terminal"
+#: spyder/plugins/profiler/widgets/profilergui.py:104
+msgid "Show program's output"
+msgstr "Afficher la sortie du programme"
-#~ msgid "Open a terminal window"
-#~ msgstr "Ouvrir un terminal de commandes dans Spyder"
+#: spyder/plugins/profiler/widgets/profilergui.py:113
+msgid "Collapse one level up"
+msgstr "Replier l'arbre d'un niveau"
-#~ msgid "Python Console"
-#~ msgstr "Console Python"
+#: spyder/plugins/profiler/widgets/profilergui.py:118
+msgid "Expand one level down"
+msgstr "Déplier l'arbre d'un niveau"
-#~ msgid "Light background"
-#~ msgstr "Fond blanc"
+#: spyder/plugins/profiler/widgets/profilergui.py:124
+msgid "Save profiling data"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:126
+msgid "Load data"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:129
+msgid "Load profiling data for comparison"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:131
+msgid "Clear comparison"
+msgstr ""
-#~ msgid "Dark background"
-#~ msgstr "Fond noir"
+#: spyder/plugins/profiler/widgets/profilergui.py:171
+msgid "Please install"
+msgstr "Veuillez installer"
-#~ msgid "Working directory:"
-#~ msgstr "Répertoire de travail :"
+#: spyder/plugins/profiler/widgets/profilergui.py:172
+msgid "the Python profiler modules"
+msgstr "les profileurs Python"
-#~ msgid "Dedicated Python console"
-#~ msgstr "Console Python dédiée"
+#: spyder/plugins/profiler/widgets/profilergui.py:179
+msgid "Save profiler result"
+msgstr ""
-#~ msgid "Show warning when killing running process"
-#~ msgstr "Afficher un avertissement à l'interruption d'un processus"
+#: spyder/plugins/profiler/widgets/profilergui.py:182
+#: spyder/plugins/profiler/widgets/profilergui.py:188
+#, fuzzy
+msgid "Profiler result"
+msgstr "Sortie du profileur"
-#~ msgid "Run Settings"
-#~ msgstr "Options d'exécution"
+#: spyder/plugins/profiler/widgets/profilergui.py:187
+msgid "Select script to compare"
+msgstr ""
-#~ msgid "the script directory"
-#~ msgstr "le répertoire du fichier à exécuter"
+#: spyder/plugins/profiler/widgets/profilergui.py:227
+#: spyder/plugins/profiler/widgets/profilergui.py:232
+msgid "Profiler output"
+msgstr "Sortie du profileur"
-#~ msgid "Show warning when killing running processes"
-#~ msgstr "Afficher un avertissement à l'interruption d'un processus"
+#: spyder/plugins/profiler/widgets/profilergui.py:251
+msgid "Profiling, please wait..."
+msgstr "Profilage en cours..."
-#~ msgid "Autorefresh"
-#~ msgstr "Rafraîchissement automatique"
+#: spyder/plugins/profiler/widgets/profilergui.py:343
+msgid "Sorting data, please wait..."
+msgstr "Classement des résultats en cours..."
-#~ msgid "Enable autorefresh"
-#~ msgstr "Activer le rafraîchissement automatique"
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Function/Module"
+msgstr "Fonction/Module"
-#~ msgid "Refresh interval: "
-#~ msgstr "Période de rafraîchissement : "
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Total Time"
+msgstr "Durée totale"
-#~ msgid ""
-#~ "The global working directory is the working directory for newly "
-#~ "opened consoles (Python/IPython consoles and terminals), for the "
-#~ "file explorer, for the find in files plugin and for new "
-#~ "files created in the editor."
-#~ msgstr ""
-#~ "Le répertoire de travail global est le répertoire de travail "
-#~ "utilisé pour les nouvelles consoles (consoles Python/IPython et "
-#~ "terminaux), pour l'explorateur de fichiers, pour la recherche "
-#~ "dans les fichiers et pour les fichiers créés dans l'éditeur."
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Diff"
+msgstr ""
-#~ msgid "the same as in last session"
-#~ msgstr "celui utilisé lors de la dernière session"
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Calls"
+msgstr "Appels"
-#~ msgid ""
-#~ "At startup, Spyder will restore the global directory from last session"
-#~ msgstr ""
-#~ "Au démarrage, Spyder reprendra le répertoire de travail global de la "
-#~ "dernière session"
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Local Time"
+msgstr "Durée locale"
-#~ msgid "Files are opened from:"
-#~ msgstr "Les fichiers sont ouverts depuis :"
+#: spyder/plugins/profiler/widgets/profilergui.py:391
+msgid "File:line"
+msgstr "Fichier:ligne"
-#~ msgid "the current file directory"
-#~ msgstr "le répertoire du fichier en cours d'édition"
+#: spyder/plugins/profiler/widgets/profilergui.py:565
+#, fuzzy
+msgid "Function or module name"
+msgstr "Fonction/Module"
-#~ msgid "the global working directory"
-#~ msgstr "le répertoire de travail global"
+#: spyder/plugins/profiler/widgets/profilergui.py:569
+msgid "Time in function (including sub-functions)"
+msgstr "Temps écoulé dans la fonction (sous-fonctions comprises)"
+#: spyder/plugins/profiler/widgets/profilergui.py:578
+msgid "Local time in function (not in sub-functions)"
+msgstr "Temps écoulé dans la fonction (hors sous-fonctions)"
-#~ msgid "Files are created in:"
-#~ msgstr "Les fichiers sont créés dans :"
+#: spyder/plugins/profiler/widgets/profilergui.py:588
+msgid "Total number of calls (including recursion)"
+msgstr "Nombre total d'appels (récursion comprise)"
-#~ msgid "Change to file base directory"
-#~ msgstr "Sélectionner le répertoire de base du fichier"
+#: spyder/plugins/profiler/widgets/profilergui.py:598
+msgid "File:line where function is defined"
+msgstr "Fichier:ligne de définition de la fonction"
-#~ msgid "When opening a file"
-#~ msgstr "Lors de l'ouverture d'un fichier"
+#: spyder/plugins/profiler/widgets/profilergui.py:603
+msgid "recursion"
+msgstr "récursion"
#~ msgid "When saving a file"
#~ msgstr "Lors de l'enregistrement d'un fichier"
@@ -6064,9 +6460,6 @@ msgstr "Impossible de vérifier les mises à jour."
#~ msgid "tab"
#~ msgstr "tabulation"
-#~ msgid "Breakpoints"
-#~ msgstr "Points d'arrêt"
-
#~ msgid "Exit"
#~ msgstr "Sortir"
@@ -6306,9 +6699,6 @@ msgstr "Impossible de vérifier les mises à jour."
#~ msgid "Interpreter"
#~ msgstr "Interpréteur"
-#~ msgid "Dedicated Python interpreter"
-#~ msgstr "Interpréteur Python dédié"
-
#~ msgid "Open Python interpreter here"
#~ msgstr "Ouvrir un interpréteur Python ici"
@@ -6819,3 +7209,9 @@ msgstr "Impossible de vérifier les mises à jour."
#~ msgid "Edit filename filter..."
#~ msgstr "Modifier le filtre des types de fichier affichés"
+
+#~ msgid "Pylint"
+#~ msgstr "Pylint"
+
+#~ msgid "Run pylint code analysis"
+#~ msgstr "Analyser le code source avec pylint"
diff --git a/spyder/locale/hu/LC_MESSAGES/spyder.mo b/spyder/locale/hu/LC_MESSAGES/spyder.mo
new file mode 100644
index 00000000000..5acd0d7a6e7
Binary files /dev/null and b/spyder/locale/hu/LC_MESSAGES/spyder.mo differ
diff --git a/spyder/locale/hu/LC_MESSAGES/spyder.po b/spyder/locale/hu/LC_MESSAGES/spyder.po
new file mode 100644
index 00000000000..acc66aa34cc
--- /dev/null
+++ b/spyder/locale/hu/LC_MESSAGES/spyder.po
@@ -0,0 +1,5667 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR , YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2017-04-05 12:05+0200\n"
+"PO-Revision-Date: 2018-11-15 12:54-0500\n"
+"Last-Translator: Barcza Károly \n"
+"Language-Team: \n"
+"Language: hu\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+"X-Generator: Poedit 2.2\n"
+
+#: spyder/app/mainwindow.py:128
+msgid "Initializing..."
+msgstr "Inicializálás..."
+
+#: spyder/app/mainwindow.py:244
+msgid "Numpy and Scipy documentation"
+msgstr "Numpy és Scipy dokumentáció"
+
+#: spyder/app/mainwindow.py:246
+msgid "Matplotlib documentation"
+msgstr "Matplotlib documentáció"
+
+#: spyder/app/mainwindow.py:249
+msgid "PyQt4 Reference Guide"
+msgstr "PyQt4 Referencia útmutató"
+
+#: spyder/app/mainwindow.py:252
+msgid "PyQt4 API Reference"
+msgstr "PyQt4 API Referencia"
+
+#: spyder/app/mainwindow.py:254
+msgid "WinPython"
+msgstr "WinPython"
+
+#: spyder/app/mainwindow.py:533
+msgid "Close current pane"
+msgstr "Jelenlegi panel bezárása"
+
+#: spyder/app/mainwindow.py:538
+msgid "Lock panes"
+msgstr "Panelek zárolása"
+
+#: spyder/app/mainwindow.py:545
+msgid "Use next layout"
+msgstr "A következő elrendezés használata"
+
+#: spyder/app/mainwindow.py:549
+msgid "Use previous layout"
+msgstr "Az előző elrendezés használata"
+
+#: spyder/app/mainwindow.py:568 spyder/widgets/sourcecode/codeeditor.py:2565
+msgid "Undo"
+msgstr "Visszavonás"
+
+#: spyder/app/mainwindow.py:570 spyder/widgets/sourcecode/codeeditor.py:2568
+msgid "Redo"
+msgstr "Újra"
+
+#: spyder/app/mainwindow.py:572 spyder/widgets/shell.py:120
+#: spyder/widgets/sourcecode/codeeditor.py:2574
+#: spyder/widgets/variableexplorer/arrayeditor.py:454
+#: spyder/widgets/variableexplorer/collectionseditor.py:674
+#: spyder/widgets/variableexplorer/dataframeeditor.py:569
+msgid "Copy"
+msgstr "Másolás"
+
+#: spyder/app/mainwindow.py:574 spyder/widgets/shell.py:116
+#: spyder/widgets/sourcecode/codeeditor.py:2571
+msgid "Cut"
+msgstr "Kivágás"
+
+#: spyder/app/mainwindow.py:576 spyder/widgets/shell.py:124
+#: spyder/widgets/sourcecode/codeeditor.py:2577
+#: spyder/widgets/variableexplorer/collectionseditor.py:671
+msgid "Paste"
+msgstr "Beillesztés"
+
+#: spyder/app/mainwindow.py:579 spyder/widgets/shell.py:137
+#: spyder/widgets/sourcecode/codeeditor.py:2580
+msgid "Select All"
+msgstr "Összes kiválasztása"
+
+#: spyder/app/mainwindow.py:589 spyder/plugins/editor.py:1386
+msgid "&File"
+msgstr "&Fájl"
+
+#: spyder/app/mainwindow.py:590 spyder/plugins/editor.py:1374
+msgid "File toolbar"
+msgstr "Fájl eszköztár"
+
+#: spyder/app/mainwindow.py:594 spyder/plugins/editor.py:1387
+msgid "&Edit"
+msgstr "&Szerkesztés"
+
+#: spyder/app/mainwindow.py:595 spyder/plugins/editor.py:1384
+msgid "Edit toolbar"
+msgstr "Szerkesztés eszköztár"
+
+#: spyder/app/mainwindow.py:599 spyder/plugins/editor.py:1388
+msgid "&Search"
+msgstr "&Keresés"
+
+#: spyder/app/mainwindow.py:600 spyder/plugins/editor.py:1376
+msgid "Search toolbar"
+msgstr "Keresés eszköztár"
+
+#: spyder/app/mainwindow.py:604 spyder/plugins/editor.py:1389
+msgid "Sour&ce"
+msgstr "&Forrás"
+
+#: spyder/app/mainwindow.py:605 spyder/plugins/editor.py:1378
+msgid "Source toolbar"
+msgstr "Forrás eszköztár"
+
+#: spyder/app/mainwindow.py:609 spyder/plugins/editor.py:792
+#: spyder/plugins/editor.py:1390
+msgid "&Run"
+msgstr "&Futtatás"
+
+#: spyder/app/mainwindow.py:610 spyder/plugins/editor.py:1380
+msgid "Run toolbar"
+msgstr "&Futtatás eszköztár"
+
+#: spyder/app/mainwindow.py:614 spyder/plugins/editor.py:751
+msgid "&Debug"
+msgstr "&Debug"
+
+#: spyder/app/mainwindow.py:615 spyder/plugins/editor.py:1382
+msgid "Debug toolbar"
+msgstr "Debug eszköztár"
+
+#: spyder/app/mainwindow.py:619
+msgid "C&onsoles"
+msgstr "&Konzolok"
+
+#: spyder/app/mainwindow.py:622
+msgid "&Projects"
+msgstr "&Projectek"
+
+#: spyder/app/mainwindow.py:625 spyder/plugins/editor.py:1391
+msgid "&Tools"
+msgstr "&Eszközök"
+
+#: spyder/app/mainwindow.py:628 spyder/plugins/editor.py:1392
+msgid "&View"
+msgstr "&Nézet"
+
+#: spyder/app/mainwindow.py:631 spyder/plugins/editor.py:1393
+msgid "&Help"
+msgstr "&Segítség"
+
+#: spyder/app/mainwindow.py:636
+msgid "Welcome to Spyder!"
+msgstr "Üdv a Spyderben!"
+
+#: spyder/app/mainwindow.py:641
+msgid "Pre&ferences"
+msgstr "&Beállítások"
+
+#: spyder/app/mainwindow.py:648 spyder/widgets/pathmanager.py:49
+msgid "PYTHONPATH manager"
+msgstr "PYTHONPATH manager"
+
+#: spyder/app/mainwindow.py:651
+msgid "Python Path Manager"
+msgstr "Python Path Manager"
+
+#: spyder/app/mainwindow.py:654
+msgid "Update module names list"
+msgstr "Modulnevek frissítése"
+
+#: spyder/app/mainwindow.py:657
+msgid "Refresh list of module names available in PYTHONPATH"
+msgstr "felfrissíti a PYTHONPATH-on levő modul neveket"
+
+#: spyder/app/mainwindow.py:660
+msgid "Reset Spyder to factory defaults"
+msgstr "A Spyder visszaállítása az alapértékekre"
+
+#: spyder/app/mainwindow.py:665
+msgid "Current user environment variables..."
+msgstr "A jelenlegi felhasználó környezeti változói..."
+
+#: spyder/app/mainwindow.py:667
+msgid "Show and edit current user environment variables in Windows registry (i.e. for all sessions)"
+msgstr "Mutatni és szerkeszteni jelenlegi használó Windows kornyezetet(minden szakaszra)"
+
+#: spyder/app/mainwindow.py:676 spyder/app/mainwindow.py:1089
+msgid "External Tools"
+msgstr "Külső eszközök"
+
+#: spyder/app/mainwindow.py:679
+msgid "WinPython control panel"
+msgstr "WinPython irányítópanel"
+
+#: spyder/app/mainwindow.py:688
+msgid "Qt Designer"
+msgstr "Qt Designer"
+
+#: spyder/app/mainwindow.py:693
+msgid "Qt Linguist"
+msgstr "Qt Linguist"
+
+#: spyder/app/mainwindow.py:699
+msgid "Qt examples"
+msgstr "Qt példák"
+
+#: spyder/app/mainwindow.py:719
+msgid "guidata examples"
+msgstr "Guidata példák:"
+
+#: spyder/app/mainwindow.py:730
+msgid "guiqwt examples"
+msgstr "guiqwt példák"
+
+#: spyder/app/mainwindow.py:735
+msgid "Sift"
+msgstr "Sift"
+
+#: spyder/app/mainwindow.py:745
+msgid "ViTables"
+msgstr "ViTables"
+
+#: spyder/app/mainwindow.py:759
+msgid "Fullscreen mode"
+msgstr "Teljes képernyős mód"
+
+#: spyder/app/mainwindow.py:771
+msgid "Main toolbar"
+msgstr "Fő eszköztár"
+
+#: spyder/app/mainwindow.py:780
+msgid "Spyder Internal Console\n"
+"\n"
+"This console is used to report application\n"
+"internal errors and to inspect Spyder\n"
+"internals with the following commands:\n"
+" spy.app, spy.window, dir(spy)\n"
+"\n"
+"Please don't use it to run your code\n"
+"\n"
+msgstr "Spyder belső konzol\n"
+"Ez a konzol belső applikaciói hibákjegyzésére és Syder belső vizsgálásárahasznál. Parancsok: spy.app, spy.window, dir(spy)\n"
+"\n"
+"Kérjük ne futtassa saját kódját\n"
+"\n"
+
+#: spyder/app/mainwindow.py:797
+msgid "Loading help..."
+msgstr "Segítség betöltése..."
+
+#: spyder/app/mainwindow.py:804
+#, fuzzy
+msgid "Loading outline explorer..."
+msgstr "Outline felfedező betöltése..."
+
+#: spyder/app/mainwindow.py:812
+msgid "Loading editor..."
+msgstr "Szerkesztő betöltése..."
+
+#: spyder/app/mainwindow.py:818 spyder/plugins/console.py:134
+#: spyder/widgets/ipythonconsole/client.py:290
+msgid "&Quit"
+msgstr "&Kilépés"
+
+#: spyder/app/mainwindow.py:820 spyder/plugins/console.py:136
+msgid "Quit"
+msgstr "Kilépés"
+
+#: spyder/app/mainwindow.py:824
+msgid "&Restart"
+msgstr "&Újraindítás"
+
+#: spyder/app/mainwindow.py:826
+msgid "Restart"
+msgstr "Újraindítás"
+
+#: spyder/app/mainwindow.py:843
+#, fuzzy
+msgid "Loading file explorer..."
+msgstr "Fájlböngésző betöltése..."
+
+#: spyder/app/mainwindow.py:850
+#, fuzzy
+msgid "Loading history plugin..."
+msgstr "Előzmény alkatrész betöltése..."
+
+#: spyder/app/mainwindow.py:861
+#, fuzzy
+msgid "Loading online help..."
+msgstr "Segítség betöltése..."
+
+#: spyder/app/mainwindow.py:866
+#, fuzzy
+msgid "Loading project explorer..."
+msgstr "Projectböngésző betöltése..."
+
+#: spyder/app/mainwindow.py:873
+#, fuzzy
+msgid "Loading external console..."
+msgstr "Külső konsozl betöltése..."
+
+#: spyder/app/mainwindow.py:879
+#, fuzzy
+msgid "Loading namespace browser..."
+msgstr "Névtérböngésző betöltése..."
+
+#: spyder/app/mainwindow.py:886
+#, fuzzy
+msgid "Loading IPython console..."
+msgstr "IPYthon konzol betöltése..."
+
+#: spyder/app/mainwindow.py:891
+#, fuzzy
+msgid "Setting up main window..."
+msgstr "Főablak indít"
+
+#: spyder/app/mainwindow.py:894
+msgid "Dependencies..."
+msgstr "Függőségek..."
+
+#: spyder/app/mainwindow.py:898
+msgid "Report issue..."
+msgstr "Hibajelentés.."
+
+#: spyder/app/mainwindow.py:902
+msgid "Spyder support..."
+msgstr "Spyder támogatás..."
+
+#: spyder/app/mainwindow.py:905
+#, fuzzy
+msgid "Check for updates..."
+msgstr "Frissítések ellenőrzése"
+
+#: spyder/app/mainwindow.py:928
+#, fuzzy
+msgid "Spyder documentation"
+msgstr "Spyder dokumentáció"
+
+#: spyder/app/mainwindow.py:936
+#, fuzzy
+msgid "Spyder tutorial"
+msgstr "Spyderben oktató"
+
+#: spyder/app/mainwindow.py:943
+#, fuzzy
+msgid "Interactive tours"
+msgstr "Párbeszédes túra"
+
+#: spyder/app/mainwindow.py:968
+msgid "Python documentation"
+msgstr "Python-dokumentáció"
+
+#: spyder/app/mainwindow.py:974
+#, fuzzy
+msgid "IPython documentation"
+msgstr "IPython Dokumentáció"
+
+#: spyder/app/mainwindow.py:975
+#, fuzzy
+msgid "Intro to IPython"
+msgstr "IPython bevezető"
+
+#: spyder/app/mainwindow.py:977
+#, fuzzy
+msgid "Quick reference"
+msgstr "Gyors referencia"
+
+#: spyder/app/mainwindow.py:979
+#, fuzzy
+msgid "Console help"
+msgstr "Terminál segítség"
+
+#: spyder/app/mainwindow.py:1009
+#, fuzzy
+msgid "Installed Python modules"
+msgstr "Telepített modulok"
+
+#: spyder/app/mainwindow.py:1013
+#, fuzzy
+msgid "Online documentation"
+msgstr "online dokumentáció"
+
+#: spyder/app/mainwindow.py:1025
+#, fuzzy
+msgid "Qt documentation"
+msgstr "Qt Dokumentáció..."
+
+#: spyder/app/mainwindow.py:1031
+#, fuzzy
+msgid "About %s..."
+msgstr "%sról"
+
+#: spyder/app/mainwindow.py:1055
+#, fuzzy
+msgid "Panes"
+msgstr "Lapok"
+
+#: spyder/app/mainwindow.py:1057
+msgid "Toolbars"
+msgstr "Eszköztárak"
+
+#: spyder/app/mainwindow.py:1058
+#, fuzzy
+msgid "Window layouts"
+msgstr "Ablak kirendezés"
+
+#: spyder/app/mainwindow.py:1067 spyder/app/mainwindow.py:1874
+#: spyder/app/mainwindow.py:1875
+#, fuzzy
+msgid "Show toolbars"
+msgstr "Eszköztárak mutatni"
+
+#: spyder/app/mainwindow.py:1082
+#, fuzzy
+msgid "Attached console window (debugging)"
+msgstr "Akonadi kezelő és debugoló konzol"
+
+#: spyder/app/mainwindow.py:1264 spyder/plugins/projects.py:244
+#: spyder/widgets/explorer.py:639 spyder/widgets/explorer.py:744
+#: spyder/widgets/externalshell/pythonshell.py:533
+#: spyder/widgets/externalshell/systemshell.py:105
+#: spyder/widgets/variableexplorer/arrayeditor.py:574
+#: spyder/widgets/variableexplorer/collectionseditor.py:433
+#: spyder/widgets/variableexplorer/dataframeeditor.py:735
+#: spyder/widgets/variableexplorer/dataframeeditor.py:739
+msgid "Error"
+msgstr "Hiba"
+
+#: spyder/app/mainwindow.py:1265
+msgid "You have missing dependencies!
%s
Please install them to avoid this message.
Note: Spyder could work without some of these dependencies, however to have a smooth experience when using Spyder we strongly recommend you to install all the listed missing dependencies.
Failing to install these dependencies might result in bugs. Please be sure that any found bugs are not the direct result of missing dependencies, prior to reporting a new issue."
+msgstr ""
+
+#: spyder/app/mainwindow.py:1721
+#, fuzzy
+msgid "Spyder Default Layout"
+msgstr "Spyder alap kirendezés"
+
+#: spyder/app/mainwindow.py:1739
+#, fuzzy
+msgid "Save current layout"
+msgstr "A jelenlegi kirendezés mentése"
+
+#: spyder/app/mainwindow.py:1743
+#, fuzzy
+msgid "Layout preferences"
+msgstr "Kirendezés beállítása"
+
+#: spyder/app/mainwindow.py:1747
+#, fuzzy
+msgid "Reset to spyder default"
+msgstr "Vissza a spyder alapra"
+
+#: spyder/app/mainwindow.py:1767 spyder/app/mainwindow.py:1789
+#: spyder/app/mainwindow.py:1852 spyder/app/mainwindow.py:2642
+#: spyder/plugins/configdialog.py:1254 spyder/plugins/externalconsole.py:447
+#: spyder/plugins/ipythonconsole.py:120 spyder/plugins/ipythonconsole.py:840
+#: spyder/plugins/ipythonconsole.py:1186 spyder/plugins/maininterpreter.py:147
+#: spyder/plugins/maininterpreter.py:175 spyder/plugins/maininterpreter.py:203
+#: spyder/utils/environ.py:100 spyder/utils/environ.py:113
+#: spyder/widgets/variableexplorer/arrayeditor.py:497
+#: spyder/widgets/variableexplorer/collectionseditor.py:422
+#: spyder/widgets/variableexplorer/collectionseditor.py:1091
+msgid "Warning"
+msgstr "Figyelmeztetés"
+
+#: spyder/app/mainwindow.py:1768
+msgid "Window layout will be reset to default settings: this affects window position, size and dockwidgets.\n"
+"Do you want to continue?"
+msgstr "Ablak kirendezetet vissza az alapra: ablak helyzet, nagyság változandó.Folytatni?"
+
+#: spyder/app/mainwindow.py:1790
+msgid "Layout %s will be overwritten. Do you want to continue?"
+msgstr "Kirendezés %s át lesz írva.Folytatni?"
+
+#: spyder/app/mainwindow.py:1853
+msgid "Quick switch layout #%s has not yet been defined."
+msgstr "Kirendezés gyorsváltó #%s nincs definálva"
+
+#: spyder/app/mainwindow.py:1871 spyder/app/mainwindow.py:1872
+msgid "Hide toolbars"
+msgstr "Eszköztárak elrejtése"
+
+#: spyder/app/mainwindow.py:2171 spyder/app/mainwindow.py:2172
+#, fuzzy
+msgid "Maximize current pane"
+msgstr "Tábla maximalizálás"
+
+#: spyder/app/mainwindow.py:2175
+#, fuzzy
+msgid "Restore current pane"
+msgstr "Tábla helyreállítása"
+
+#: spyder/app/mainwindow.py:2176
+#, fuzzy
+msgid "Restore pane to its original size"
+msgstr "Táblát méretre"
+
+#: spyder/app/mainwindow.py:2260
+msgid "About %s"
+msgstr "%sról"
+
+#: spyder/app/mainwindow.py:2387 spyder/plugins/editor.py:157
+#: spyder/plugins/runconfig.py:334 spyder/plugins/runconfig.py:456
+#: spyder/plugins/runconfig.py:461 spyder/utils/programs.py:285
+#: spyder/widgets/explorer.py:271 spyder/widgets/externalshell/baseshell.py:127
+msgid "Run"
+msgstr "Futtatás"
+
+#: spyder/app/mainwindow.py:2388
+msgid "Running an external system terminal is not supported on platform %s."
+msgstr "Külső terminál futtatása %s-en nem lehet"
+
+#: spyder/app/mainwindow.py:2643
+msgid "Spyder will restart and reset to default settings:
Do you want to continue?"
+msgstr "Spyder-t indítani eredeti beállításokkal.Folytatni?"
+
+#: spyder/app/mainwindow.py:2740 spyder/widgets/helperwidgets.py:250
+msgid "Spyder updates"
+msgstr "Spyder frissítések"
+
+#: spyder/app/mainwindow.py:2741 spyder/plugins/configdialog.py:819
+#, fuzzy
+msgid "Check for updates on startup"
+msgstr "Frissítések ellenőrzése"
+
+#: spyder/app/mainwindow.py:2761
+msgid "Spyder %s is available!
Please use your package manager to update Spyder or go to our Releases page to download this new version.
If you are not sure how to proceed to update Spyder please refer to our Installation instructions."
+msgstr "Spyder %s kapható!
Kérjük használja csomag menedzserjét vagy fáradjon a Kiadás oldalra.
További tájékozatatásÉ Installation."
+
+#: spyder/app/mainwindow.py:2773
+#, fuzzy
+msgid "Spyder is up to date."
+msgstr "Spyder a legőjabb"
+
+#: spyder/app/restart.py:133
+msgid "It was not possible to close the previous Spyder instance.\n"
+"Restart aborted."
+msgstr "Spydert leállítani nem sikerültÚjakezdés elmaradt."
+
+#: spyder/app/restart.py:135
+msgid "Spyder could not reset to factory defaults.\n"
+"Restart aborted."
+msgstr "Viszzaállítas eredeti beállításokra nem sikerültÚjakezdés elmaradt."
+
+#: spyder/app/restart.py:137
+msgid "It was not possible to restart Spyder.\n"
+"Operation aborted."
+msgstr "Újakezdés nem sikerült"
+
+#: spyder/app/restart.py:139
+#, fuzzy
+msgid "Spyder exit error"
+msgstr "Spyder kilépési hiba"
+
+#: spyder/app/restart.py:140
+#, fuzzy
+msgid "Spyder reset error"
+msgstr "Spyder visszállítás hiba"
+
+#: spyder/app/restart.py:141
+#, fuzzy
+msgid "Spyder restart error"
+msgstr "Spyderben újrakezdés hiba"
+
+#: spyder/app/restart.py:165
+msgid "Closing Spyder"
+msgstr "Spyder bezárása"
+
+#: spyder/app/restart.py:239
+#, fuzzy
+msgid "Resetting Spyder to defaults"
+msgstr "Spyder visszaállítás alapra"
+
+#: spyder/app/restart.py:271
+msgid "Restarting"
+msgstr "Újraindítás"
+
+#: spyder/app/tour.py:124
+#, fuzzy
+msgid "Welcome to the Introduction tour"
+msgstr "Üdvözöljük!"
+
+#: spyder/app/tour.py:125
+msgid "Spyder is a powerful Interactive Development Environment (or IDE) for the Python programming language.
Here we are going to guide you through its most important features.
Please use the arrow keys or click on the buttons below to move along the tour."
+msgstr ""
+
+#: spyder/app/tour.py:134
+msgid "The Editor"
+msgstr "A szerkesztő"
+
+#: spyder/app/tour.py:135
+msgid "This is the pane where you write Python code before evaluating it. You can get automatic suggestions and completions while writing, by pressing the Tab key next to a given text.
The Editor comes with a line number area (highlighted here in red), where Spyder shows warnings and syntax errors. They can help you to detect potential problems before running the code.
You can also set debug breakpoints in the line number area, by doing a double click next to a non-empty line."
+msgstr ""
+
+#: spyder/app/tour.py:150
+#, fuzzy
+msgid "The IPython console"
+msgstr "Terminálban:"
+
+#: spyder/app/tour.py:151
+msgid "This is one of panes where you can run or execute the code you wrote on the Editor. To do it you need to press the F5 key.
This console comes with several useful features that greatly improve your programming workflow (like syntax highlighting and inline plots). If you want to know more about them, please follow this link.
Please click on the button below to run some simple code in this console. This will be useful to show you other important features."
+msgstr ""
+
+#: spyder/app/tour.py:167
+#, fuzzy
+msgid "The Variable Explorer"
+msgstr "Változóböngésző"
+
+#: spyder/app/tour.py:168
+msgid "In this pane you can view and edit the variables generated during the execution of a program, or those entered directly in one of Spyder consoles.
As you can see, the Variable Explorer is showing the variables generated during the last step of this tour. By doing a double-click on any of them, a new window will be opened, where you can inspect and modify their contents."
+msgstr ""
+
+#: spyder/app/tour.py:180
+#, fuzzy
+msgid "The Python console"
+msgstr "Python-konzol"
+
+#: spyder/app/tour.py:181
+msgid "You can also run your code on a Python console. These consoles are useful because they let you run a file in a console dedicated only to it.To select this behavior, please press the F6 key.
By pressing the button below and then focusing the Variable Explorer, you will notice that Python consoles are also connected to that pane, and that the Variable Explorer only shows the variables of the currently focused console."
+msgstr ""
+
+#: spyder/app/tour.py:195 spyder/plugins/help.py:485 spyder/plugins/help.py:929
+#: spyder/widgets/internalshell.py:270
+msgid "Help"
+msgstr "Segítség"
+
+#: spyder/app/tour.py:196
+msgid "This pane displays documentation of the functions, classes, methods or modules you are currently using in the Editor or the Consoles.
To use it, you need to press Ctrl+I in front of an object. If that object has some documentation associated with it, it will be displayed here."
+msgstr ""
+
+#: spyder/app/tour.py:206
+#, fuzzy
+msgid "The File Explorer"
+msgstr "Fájlböngésző"
+
+#: spyder/app/tour.py:207
+msgid "This pane lets you navigate through the directories and files present in your computer.
You can also open any of these files with its corresponding application, by doing a double click on it.
There is one exception to this rule: plain-text files will always be opened in the Spyder Editor."
+msgstr ""
+
+#: spyder/app/tour.py:217
+#, fuzzy
+msgid "The History Log"
+msgstr "Előzmények"
+
+#: spyder/app/tour.py:218
+msgid "This pane records all commands introduced in the Python and IPython consoles."
+msgstr "Ez a tábla minden konzol parancsot megjegyez"
+
+#: spyder/app/tour.py:266
+msgid "Spyder is an interactive development environment based on bla"
+msgstr ""
+
+#: spyder/app/tour.py:270
+#, fuzzy
+msgid "Welcome to Spyder introduction tour"
+msgstr "Üdv a Spyderben!"
+
+#: spyder/app/tour.py:271
+msgid "Spyder is an interactive development environment based on bla"
+msgstr ""
+
+#: spyder/app/tour.py:276
+#, fuzzy
+msgid "Introduction tour"
+msgstr "Bevezető túra"
+
+#: spyder/app/tour.py:277
+#, fuzzy
+msgid "New features in version 3.0"
+msgstr "3.0 újdonságai"
+
+#: spyder/app/tour.py:571 spyder/plugins/ipythonconsole.py:432
+#, fuzzy
+msgid "Run code"
+msgstr "Kód Futtatás"
+
+#: spyder/app/tour.py:846
+#, fuzzy
+msgid "Go to step: "
+msgstr "Lépéshez: "
+
+#: spyder/config/base.py:254
+msgid "Update LANGUAGE_CODES (inside config/base.py) if a new translation has been added to Spyder"
+msgstr "Ha új nyelvet adot spyderben, frissítse LANGUAGE_CODES-ot (config/base.py)"
+
+#: spyder/config/ipython.py:23
+#, fuzzy
+msgid "Integrate the IPython console"
+msgstr "IPython konzol integráció"
+
+#: spyder/config/ipython.py:25
+msgid "Manipulate Jupyter notebooks on the Editor"
+msgstr "Jupyter jegyzetkönyv manipuláció"
+
+#: spyder/config/utils.py:24
+#, fuzzy
+msgid "Python files"
+msgstr "Python-fájlok"
+
+#: spyder/config/utils.py:25
+#, fuzzy
+msgid "Cython/Pyrex files"
+msgstr "Cython/Pyrex fájlok."
+
+#: spyder/config/utils.py:26
+#, fuzzy
+msgid "C files"
+msgstr "C fájlok"
+
+#: spyder/config/utils.py:27
+#, fuzzy
+msgid "C++ files"
+msgstr "C++ fájlok"
+
+#: spyder/config/utils.py:28
+#, fuzzy
+msgid "OpenCL files"
+msgstr "OpenCL fájlok."
+
+#: spyder/config/utils.py:29
+#, fuzzy
+msgid "Fortran files"
+msgstr "Fortran fájlok"
+
+#: spyder/config/utils.py:30
+#, fuzzy
+msgid "IDL files"
+msgstr "IDL-fájlok"
+
+#: spyder/config/utils.py:31
+#, fuzzy
+msgid "MATLAB files"
+msgstr "Matlab fájlok"
+
+#: spyder/config/utils.py:32
+#, fuzzy
+msgid "Julia files"
+msgstr "Julia fájlok"
+
+#: spyder/config/utils.py:33
+#, fuzzy
+msgid "Yaml files"
+msgstr "YAML fájlok"
+
+#: spyder/config/utils.py:34
+#, fuzzy
+msgid "Patch and diff files"
+msgstr "Patch-diff fájlok"
+
+#: spyder/config/utils.py:35
+#, fuzzy
+msgid "Batch files"
+msgstr "Kötegelt"
+
+#: spyder/config/utils.py:36 spyder/utils/iofuncs.py:426
+#, fuzzy
+msgid "Text files"
+msgstr "Szövegfájlok"
+
+#: spyder/config/utils.py:37
+#, fuzzy
+msgid "reStructuredText files"
+msgstr "reST fájlok."
+
+#: spyder/config/utils.py:38
+#, fuzzy
+msgid "gettext files"
+msgstr "gettext fájlok"
+
+#: spyder/config/utils.py:39
+#, fuzzy
+msgid "NSIS files"
+msgstr "NSIS fájlok."
+
+#: spyder/config/utils.py:40
+#, fuzzy
+msgid "Web page files"
+msgstr "weboldal fájlok"
+
+#: spyder/config/utils.py:41
+#, fuzzy
+msgid "XML files"
+msgstr "XML Fájlok"
+
+#: spyder/config/utils.py:42
+#, fuzzy
+msgid "Javascript files"
+msgstr "Javascript fájlok"
+
+#: spyder/config/utils.py:43
+#, fuzzy
+msgid "Json files"
+msgstr "JSON fájlok"
+
+#: spyder/config/utils.py:44
+msgid "IPython notebooks"
+msgstr "IPython jegyzetkönyvek"
+
+#: spyder/config/utils.py:45
+#, fuzzy
+msgid "Enaml files"
+msgstr "Enaml fájlok."
+
+#: spyder/config/utils.py:46
+msgid "Configuration files"
+msgstr "Beállítófájlok"
+
+#: spyder/config/utils.py:51 spyder/widgets/explorer.py:712
+msgid "All files"
+msgstr "Az összes fájl"
+
+#: spyder/config/utils.py:122
+#, fuzzy
+msgid "Supported text files"
+msgstr "Támogatott szövegfájltípus"
+
+#: spyder/plugins/__init__.py:508 spyder/plugins/editor.py:97
+#: spyder/plugins/editor.py:544 spyder/plugins/editor.py:1769
+#: spyder/plugins/help.py:118 spyder/plugins/help.py:385
+#: spyder/widgets/editor.py:375 spyder/widgets/sourcecode/codeeditor.py:96
+#: spyder/widgets/sourcecode/codeeditor.py:3058
+msgid "Editor"
+msgstr "Szerkesztő"
+
+#: spyder/plugins/configdialog.py:139
+msgid "Reset to defaults"
+msgstr "Alapértelmezések visszaállítása"
+
+#: spyder/plugins/configdialog.py:151
+msgid "Preferences"
+msgstr "Beállítások"
+
+#: spyder/plugins/configdialog.py:491
+#, fuzzy
+msgid "Invalid directory path"
+msgstr "Érvénytelen útvonal"
+
+#: spyder/plugins/configdialog.py:494 spyder/plugins/configdialog.py:509
+#: spyder/plugins/runconfig.py:185 spyder/plugins/runconfig.py:251
+#: spyder/plugins/workingdirectory.py:291 spyder/widgets/explorer.py:626
+#: spyder/widgets/externalshell/pythonshell.py:616
+#: spyder/widgets/findinfiles.py:504 spyder/widgets/pathmanager.py:224
+#: spyder/widgets/projects/projectdialog.py:155
+msgid "Select directory"
+msgstr "Válassza ki a könyvtárat"
+
+#: spyder/plugins/configdialog.py:521
+#, fuzzy
+msgid "Invalid file path"
+msgstr "Érvénytelen irányító"
+
+#: spyder/plugins/configdialog.py:524 spyder/plugins/configdialog.py:541
+#, fuzzy
+msgid "Select file"
+msgstr "Fájl kiválasztása"
+
+#: spyder/plugins/configdialog.py:540
+#, fuzzy
+msgid "All files (*)"
+msgstr "Minden fájl (*)"
+
+#: spyder/plugins/configdialog.py:613 spyder/widgets/formlayout.py:215
+msgid "Bold"
+msgstr "félkövér"
+
+#: spyder/plugins/configdialog.py:616 spyder/widgets/formlayout.py:210
+msgid "Italic"
+msgstr "Dőlt"
+
+#: spyder/plugins/configdialog.py:670
+#, fuzzy
+msgid "Font: "
+msgstr "Betűkészlet:"
+
+#: spyder/plugins/configdialog.py:676
+#, fuzzy
+msgid "Size: "
+msgstr "Méret:"
+
+#: spyder/plugins/configdialog.py:695
+msgid "Font style"
+msgstr "Betűstílus"
+
+#: spyder/plugins/configdialog.py:772
+msgid "Spyder needs to restart to change the following setting:"
+msgstr "Spyder újraindul ezek a beállítások miatt"
+
+#: spyder/plugins/configdialog.py:775
+msgid "Spyder needs to restart to change the following settings:"
+msgstr "Spyder újraindul ezek a beállítások miatt"
+
+#: spyder/plugins/configdialog.py:777
+#, fuzzy
+msgid "Do you wish to restart now?"
+msgstr "Most újra kezdődni?"
+
+#: spyder/plugins/configdialog.py:783
+msgid "Information"
+msgstr "Információ"
+
+#: spyder/plugins/configdialog.py:797 spyder/plugins/configdialog.py:804
+#: spyder/widgets/projects/configdialog.py:74
+msgid "General"
+msgstr "Általános"
+
+#: spyder/plugins/configdialog.py:807
+msgid "Language"
+msgstr "Nyelv"
+
+#: spyder/plugins/configdialog.py:810
+#, fuzzy
+msgid "Use a single instance"
+msgstr "Egy példány"
+
+#: spyder/plugins/configdialog.py:812
+msgid "Set this to open external
Python files in an already running instance (Requires a restart)"
+msgstr "Külső Pytho fájlokat futó példányban nyitni(muszáj újraindítani)"
+
+#: spyder/plugins/configdialog.py:815
+#, fuzzy
+msgid "Prompt when exiting"
+msgstr " Kilépés..."
+
+#: spyder/plugins/configdialog.py:816
+msgid "Pop up internal console when internal errors appear"
+msgstr "Mutatni belső konzólt belső hiba helyzetben"
+
+#: spyder/plugins/configdialog.py:836 spyder/plugins/editor.py:106
+#: spyder/plugins/externalconsole.py:57 spyder/plugins/ipythonconsole.py:274
+#: spyder/widgets/projects/configdialog.py:81
+msgid "Interface"
+msgstr "Csatoló"
+
+#: spyder/plugins/configdialog.py:844
+#, fuzzy
+msgid "Qt windows style"
+msgstr "Qt ablak stílus"
+
+#: spyder/plugins/configdialog.py:850
+#, fuzzy
+msgid "Icon theme"
+msgstr "Ikontéma"
+
+#: spyder/plugins/configdialog.py:854
+msgid "Vertical title bars in panes"
+msgstr "Függőleges tábla címerek"
+
+#: spyder/plugins/configdialog.py:856
+#, fuzzy
+msgid "Vertical tabs in panes"
+msgstr "Fügőleges tábla címkék"
+
+#: spyder/plugins/configdialog.py:858
+#, fuzzy
+msgid "Animated toolbars and panes"
+msgstr "Eszköztár animáció"
+
+#: spyder/plugins/configdialog.py:860
+#, fuzzy
+msgid "Tear off menus"
+msgstr "Tépendő menüelem"
+
+#: spyder/plugins/configdialog.py:861
+msgid "Set this to detach any
menu from the main window"
+msgstr "Bármelyik főablaki menüelemet letépendővé"
+
+#: spyder/plugins/configdialog.py:863
+#, fuzzy
+msgid "Enable high DPI scaling"
+msgstr "Magas DPI megengedni"
+
+#: spyder/plugins/configdialog.py:865
+#, fuzzy
+msgid "Set this for high DPI displays"
+msgstr "Magas DPI ernyő"
+
+#: spyder/plugins/configdialog.py:866
+#, fuzzy
+msgid "Custom margin for panes:"
+msgstr "Táblák saját pereme:"
+
+#: spyder/plugins/configdialog.py:868
+msgid "pixels"
+msgstr "pixelek"
+
+#: spyder/plugins/configdialog.py:897
+#, fuzzy
+msgid "Status bar"
+msgstr "Status Bar"
+
+#: spyder/plugins/configdialog.py:898
+#, fuzzy
+msgid "Show status bar"
+msgstr "Állapotot mutatni"
+
+#: spyder/plugins/configdialog.py:900
+#, fuzzy
+msgid "Show memory usage every"
+msgstr "A memóriahasználat mutatni minden"
+
+#: spyder/plugins/configdialog.py:902 spyder/plugins/configdialog.py:911
+#: spyder/plugins/editor.py:132 spyder/plugins/editor.py:260
+#: spyder/plugins/variableexplorer.py:28
+msgid " ms"
+msgstr " ms"
+
+#: spyder/plugins/configdialog.py:909
+#, fuzzy
+msgid "Show CPU usage every"
+msgstr "CPU használat minden"
+
+#: spyder/plugins/configdialog.py:944
+#, fuzzy
+msgid "Plain text font"
+msgstr "Sima Text"
+
+#: spyder/plugins/configdialog.py:950
+#, fuzzy
+msgid "Rich text font"
+msgstr "Gazdag Text"
+
+#: spyder/plugins/configdialog.py:953
+msgid "Fonts"
+msgstr "Betűk"
+
+#: spyder/plugins/configdialog.py:967
+msgid "Appearance"
+msgstr "Nézet"
+
+#: spyder/plugins/configdialog.py:969 spyder/plugins/ipythonconsole.py:565
+msgid "Advanced Settings"
+msgstr "Haladó beállítások"
+
+#: spyder/plugins/configdialog.py:1005
+msgid "Syntax coloring"
+msgstr "Sintaxis színezés"
+
+#: spyder/plugins/configdialog.py:1018
+msgid "Here you can select the color scheme used in the Editor and all other Spyder plugins.
You can also edit the color schemes provided by Spyder or create your own ones by using the options provided below.
"
+msgstr "Színezések"
+
+#: spyder/plugins/configdialog.py:1023
+#, fuzzy
+msgid "Edit selected"
+msgstr "A kijelölt sor szerkesztése"
+
+#: spyder/plugins/configdialog.py:1024
+#, fuzzy
+msgid "Create new scheme"
+msgstr "Ha beállította a kívánt színeket, kattintson erre a gombra egy új színséma létrehozásához. A színséma bekerül a listába, és elérhető lesz a főablak \"Beállítások\" menüjéből."
+
+#: spyder/plugins/configdialog.py:1025 spyder/widgets/explorer.py:512
+#: spyder/widgets/projects/explorer.py:242 spyder/widgets/shell.py:133
+msgid "Delete"
+msgstr "Törlés"
+
+#: spyder/plugins/configdialog.py:1028
+msgid "Reset"
+msgstr "Alaphelyzetbe"
+
+#: spyder/plugins/configdialog.py:1035
+#, fuzzy
+msgid "Scheme:"
+msgstr "Színséma"
+
+#: spyder/plugins/configdialog.py:1066
+#, fuzzy
+msgid "Manage color schemes"
+msgstr "Színsémák"
+
+#: spyder/plugins/configdialog.py:1255
+#, fuzzy
+msgid "Are you sure you want to delete this scheme?"
+msgstr "Biztosan törölni szeretné a kijelölt aliasokat?"
+
+#: spyder/plugins/configdialog.py:1372
+msgid "Text"
+msgstr "Szöveg"
+
+#: spyder/plugins/configdialog.py:1374
+msgid "Highlight"
+msgstr "Kiemelés"
+
+#: spyder/plugins/configdialog.py:1376
+msgid "Background"
+msgstr "Háttér"
+
+#: spyder/plugins/configdialog.py:1380
+#, fuzzy
+msgid "Scheme name:"
+msgstr "Stílusséma neve"
+
+#: spyder/plugins/configdialog.py:1387
+#, fuzzy
+msgid "Color scheme editor"
+msgstr "Színösszeállítás-szerkesztő"
+
+#: spyder/plugins/console.py:109
+#, fuzzy
+msgid "Internal console"
+msgstr "Belső konzol"
+
+#: spyder/plugins/console.py:139 spyder/plugins/externalconsole.py:751
+msgid "&Run..."
+msgstr "&Futtatás"
+
+#: spyder/plugins/console.py:141 spyder/plugins/externalconsole.py:752
+msgid "Run a Python script"
+msgstr "Egy Python script futtatása"
+
+#: spyder/plugins/console.py:144
+#, fuzzy
+msgid "Environment variables..."
+msgstr "Környezeti változók"
+
+#: spyder/plugins/console.py:146
+msgid "Show and edit environment variables (for current session)"
+msgstr "Mutatni-szerkeszteni környezet változókat (jelen szakaszra)"
+
+#: spyder/plugins/console.py:150
+#, fuzzy
+msgid "Show sys.path contents..."
+msgstr "sys.path tartalom"
+
+#: spyder/plugins/console.py:152
+#, fuzzy
+msgid "Show (read-only) sys.path"
+msgstr "sys.path mutatni (olvasandó)"
+
+#: spyder/plugins/console.py:155
+#, fuzzy
+msgid "Buffer..."
+msgstr "Tároló"
+
+#: spyder/plugins/console.py:156 spyder/plugins/externalconsole.py:75
+#: spyder/plugins/history.py:43
+#, fuzzy
+msgid "Set maximum line count"
+msgstr "Maximum sorszám: %s"
+
+#: spyder/plugins/console.py:159
+#, fuzzy
+msgid "External editor path..."
+msgstr "A külső szövegszerkesztő elérési útja"
+
+#: spyder/plugins/console.py:160
+#, fuzzy
+msgid "Set external editor executable path"
+msgstr "A külső szövegszerkesztő elérési útja"
+
+#: spyder/plugins/console.py:163 spyder/plugins/editor.py:138
+#: spyder/plugins/externalconsole.py:76 spyder/plugins/help.py:157
+#: spyder/plugins/help.py:360 spyder/plugins/history.py:46
+#: spyder/plugins/history.py:157
+#, fuzzy
+msgid "Wrap lines"
+msgstr "Ha be van állítva, a túl széles szövegsorok áttördelésre kerülnek"
+
+#: spyder/plugins/console.py:166 spyder/plugins/editor.py:174
+#: spyder/plugins/externalconsole.py:121 spyder/plugins/ipythonconsole.py:284
+#, fuzzy
+msgid "Display balloon tips"
+msgstr "Legyenek-e tippablakban megjelenő értesítések."
+
+#: spyder/plugins/console.py:170 spyder/plugins/editor.py:168
+#: spyder/plugins/externalconsole.py:115
+#, fuzzy
+msgid "Automatic code completion"
+msgstr "Kódkiegészítés"
+
+#: spyder/plugins/console.py:174 spyder/plugins/editor.py:172
+#: spyder/plugins/externalconsole.py:119
+#, fuzzy
+msgid "Enter key selects completion"
+msgstr "Kódkiegészítés választás "
+
+#: spyder/plugins/console.py:179
+#, fuzzy
+msgid "Internal console settings"
+msgstr "Belső konzol beállítása"
+
+#: spyder/plugins/console.py:232 spyder/plugins/externalconsole.py:926
+#, fuzzy
+msgid "Run Python script"
+msgstr "Egy Python script futtatása"
+
+#: spyder/plugins/console.py:233 spyder/plugins/externalconsole.py:146
+#: spyder/plugins/externalconsole.py:927 spyder/widgets/explorer.py:727
+#, fuzzy
+msgid "Python scripts"
+msgstr "Scriptek"
+
+#: spyder/plugins/console.py:278
+msgid "Buffer"
+msgstr "Tároló"
+
+#: spyder/plugins/console.py:279
+#, fuzzy
+msgid "Maximum line count"
+msgstr "Maximum sorszám: %s"
+
+#: spyder/plugins/console.py:289
+#, fuzzy
+msgid "External editor"
+msgstr "Külső szövegszerkesztő"
+
+#: spyder/plugins/console.py:290
+#, fuzzy
+msgid "External editor executable path:"
+msgstr "A külső szövegszerkesztő elérési útja"
+
+#: spyder/plugins/editor.py:103
+#, fuzzy
+msgid "Edit template for new modules"
+msgstr "Új modul sablon..."
+
+#: spyder/plugins/editor.py:108
+msgid "Sort files according to full path"
+msgstr "Elérési út szerint sorrendbe rakás"
+
+#: spyder/plugins/editor.py:110
+#, fuzzy
+msgid "Show tab bar"
+msgstr "Címkéket mutatni"
+
+#: spyder/plugins/editor.py:117 spyder/plugins/editor.py:188
+#: spyder/plugins/externalconsole.py:71 spyder/plugins/externalconsole.py:114
+#: spyder/plugins/help.py:156 spyder/plugins/history.py:45
+#: spyder/plugins/ipythonconsole.py:318
+msgid "Source code"
+msgstr "Forráskód"
+
+#: spyder/plugins/editor.py:118
+msgid "Show line numbers"
+msgstr "Sorszámok mutatása"
+
+#: spyder/plugins/editor.py:119 spyder/plugins/editor.py:963
+#, fuzzy
+msgid "Show blank spaces"
+msgstr "Üres betüt mutatni"
+
+#: spyder/plugins/editor.py:120
+#, fuzzy
+msgid "Show vertical line after"
+msgstr "Függőleges vonal oszlop"
+
+#: spyder/plugins/editor.py:121
+#, fuzzy
+msgid "characters"
+msgstr "betük"
+
+#: spyder/plugins/editor.py:126
+msgid "Highlight current line"
+msgstr "A jelenlegi sor kiemelése"
+
+#: spyder/plugins/editor.py:128
+#, fuzzy
+msgid "Highlight current cell"
+msgstr "A jelenlegi cella kiemelése"
+
+#: spyder/plugins/editor.py:130
+#, fuzzy
+msgid "Highlight occurrences after"
+msgstr "példa kiemelés .. után"
+
+#: spyder/plugins/editor.py:158
+msgid "Save all files before running script"
+msgstr "Fájl mentés script futtatás elött"
+
+#: spyder/plugins/editor.py:161
+#, fuzzy
+msgid "Run selection"
+msgstr "Kejelöltet futtatni"
+
+#: spyder/plugins/editor.py:162
+msgid "Maintain focus in the Editor after running cells or selections"
+msgstr "Futtatás után szerkesztőben a fokusz"
+
+#: spyder/plugins/editor.py:165 spyder/plugins/externalconsole.py:252
+msgid "Introspection"
+msgstr "Viszgálás"
+
+#: spyder/plugins/editor.py:170 spyder/plugins/externalconsole.py:117
+#, fuzzy
+msgid "Case sensitive code completion"
+msgstr "Nagybetűérzékeny"
+
+#: spyder/plugins/editor.py:175
+#, fuzzy
+msgid "Link to object definition"
+msgstr "Definíció"
+
+#: spyder/plugins/editor.py:177
+msgid "If this option is enabled, clicking on an object\n"
+"name (left-click + Ctrl key) will go this object\n"
+"definition (if resolved)."
+msgstr ""
+
+#: spyder/plugins/editor.py:181
+msgid "Warning:
The Python module rope is not installed on this computer: calltips, code completion and go-to-definition features won't be available."
+msgstr "Figyelem - calltips modul nem talált"
+
+#: spyder/plugins/editor.py:189
+msgid "Automatic insertion of parentheses, braces and brackets"
+msgstr "Automatikus zárójel beillesztés"
+
+#: spyder/plugins/editor.py:192
+msgid "Automatic insertion of closing quotes"
+msgstr "Automatikus idézőjel beillesztés"
+
+#: spyder/plugins/editor.py:194
+msgid "Automatic insertion of colons after 'for', 'if', 'def', etc"
+msgstr "Automatikus kettőspont beillesztés"
+
+#: spyder/plugins/editor.py:197
+msgid "Automatic indentation after 'else', 'elif', etc."
+msgstr "Automatikus behúzás"
+
+#: spyder/plugins/editor.py:199
+#, fuzzy
+msgid "Indentation characters: "
+msgstr "behúzási betü"
+
+#: spyder/plugins/editor.py:200
+#, fuzzy
+msgid "2 spaces"
+msgstr "2 space"
+
+#: spyder/plugins/editor.py:201
+#, fuzzy
+msgid "3 spaces"
+msgstr "3 space"
+
+#: spyder/plugins/editor.py:202
+#, fuzzy
+msgid "4 spaces"
+msgstr "4 space"
+
+#: spyder/plugins/editor.py:203
+#, fuzzy
+msgid "5 spaces"
+msgstr "5 space"
+
+#: spyder/plugins/editor.py:204
+#, fuzzy
+msgid "6 spaces"
+msgstr "6 space"
+
+#: spyder/plugins/editor.py:205
+#, fuzzy
+msgid "7 spaces"
+msgstr "7 space"
+
+#: spyder/plugins/editor.py:206
+#, fuzzy
+msgid "8 spaces"
+msgstr "8 space"
+
+#: spyder/plugins/editor.py:207
+#, fuzzy
+msgid "Tabulations"
+msgstr "Tab"
+
+#: spyder/plugins/editor.py:208
+#, fuzzy
+msgid "Tab stop width:"
+msgstr "Tab méret"
+
+#: spyder/plugins/editor.py:208
+#, fuzzy
+msgid "spaces"
+msgstr "space"
+
+#: spyder/plugins/editor.py:210
+#, fuzzy
+msgid "Tab always indent"
+msgstr "Behúzás tabnál"
+
+#: spyder/plugins/editor.py:212
+msgid "If enabled, pressing Tab will always indent,\n"
+"even when the cursor is not at the beginning\n"
+"of a line (when this option is enabled, code\n"
+"completion may be triggered using the alternate\n"
+"shortcut: Ctrl+Space)"
+msgstr ""
+
+#: spyder/plugins/editor.py:217
+#, fuzzy
+msgid "Intelligent backspace"
+msgstr "Intelligens backspace"
+
+#: spyder/plugins/editor.py:219
+msgid "Automatically remove trailing spaces when saving files"
+msgstr "Automatikus üres betük törlése"
+
+#: spyder/plugins/editor.py:223
+msgid "Analysis"
+msgstr "Elemzés"
+
+#: spyder/plugins/editor.py:225
+#, fuzzy
+msgid "(Refer to the {} page)"
+msgstr "(Nézze a {} oldalt)"
+
+#: spyder/plugins/editor.py:229
+#, fuzzy
+msgid "Real-time code analysis"
+msgstr "Valós idejű kód elemzés"
+
+#: spyder/plugins/editor.py:231
+msgid "If enabled, Python source code will be analyzed using pyflakes, lines containing errors or warnings will be highlighted.
Note: add analysis:ignore in a comment to ignore code analysis warnings.
"
+msgstr "Python forráskód elemzés pyflakes használatával. Figyelmeztetéses és hibás vonalok kiemelve.
Jegyzet: addjonanalysis:ignore mint megjegyzés, a jelölést kihagyni bizonyos vonalban.
\""
+
+#: spyder/plugins/editor.py:239
+msgid "Code analysis requires pyflakes %s+"
+msgstr "Kód elemzéshez kell pyflakes %s+"
+
+#: spyder/plugins/editor.py:241
+msgid "Real-time code style analysis"
+msgstr "Élő kód stílus elemzés"
+
+#: spyder/plugins/editor.py:243
+msgid "If enabled, Python source code will be analyzedusing pep8, lines that are not following PEP8 style guide will be highlighted.
Note: add analysis:ignore in a comment to ignore style analysis warnings.
"
+msgstr "Python forráskód elemzés pep8 használatával. Kiemel vonalakat amik nem tartanak a PEP8 stílus előírásokkal
Jegyzet: addjon analysis:ignore mint megjegyzés, a jelölést kihagyni bizonyos vonalban.
"
+
+#: spyder/plugins/editor.py:250
+msgid "Code annotations (TODO, FIXME, XXX, HINT, TIP, @todo)"
+msgstr "Kód jelölés (TODO, FIXME, XXX, HINT, TIP, @todo)"
+
+#: spyder/plugins/editor.py:253
+msgid "Perform analysis when saving file and every"
+msgstr "Elemzés mentéskor és minden"
+
+#: spyder/plugins/editor.py:257
+msgid "Perform analysis only when saving file"
+msgstr "Elemzés csak mentéskor"
+
+#: spyder/plugins/editor.py:316
+#, fuzzy
+msgid "End-of-line characters"
+msgstr "Sor vége"
+
+#: spyder/plugins/editor.py:317
+msgid "When opening a text file containing mixed end-of-line characters (this may raise syntax errors in the consoles on Windows platforms), Spyder may fix the file automatically."
+msgstr "Ha szövegfájlban többféle sorvég van (ami szintax hibát okozhat)spyder automatikusan rendbe hozhatja."
+
+#: spyder/plugins/editor.py:323
+msgid "Fix automatically and show warning message box"
+msgstr "Automatikus rendbe hozás, és figyelmetetés mutatása"
+
+#: spyder/plugins/editor.py:334 spyder/plugins/externalconsole.py:250
+#: spyder/plugins/ipythonconsole.py:559 spyder/plugins/variableexplorer.py:41
+msgid "Display"
+msgstr "Kijelző"
+
+#: spyder/plugins/editor.py:336
+#, fuzzy
+msgid "Code Introspection/Analysis"
+msgstr "Kód Elemzés"
+
+#: spyder/plugins/editor.py:339 spyder/plugins/externalconsole.py:253
+#, fuzzy
+msgid "Advanced settings"
+msgstr "Haladó beállítások"
+
+#: spyder/plugins/editor.py:612 spyder/widgets/editortools.py:510
+#, fuzzy
+msgid "Show/hide outline explorer"
+msgstr "Mutatni a vázlat böngészőt"
+
+#: spyder/plugins/editor.py:621
+msgid "&New file..."
+msgstr "&Új fájl"
+
+#: spyder/plugins/editor.py:622 spyder/plugins/workingdirectory.py:83
+#: spyder/widgets/explorer.py:704 spyder/widgets/explorer.py:711
+msgid "New file"
+msgstr "Új fájl"
+
+#: spyder/plugins/editor.py:631
+#, fuzzy
+msgid "O&pen last closed"
+msgstr "Utosó zártat nyítni"
+
+#: spyder/plugins/editor.py:632
+#, fuzzy
+msgid "Open last closed"
+msgstr "Utosó zártat nyítni"
+
+#: spyder/plugins/editor.py:638
+msgid "&Open..."
+msgstr "&Megnyitás"
+
+#: spyder/plugins/editor.py:639 spyder/plugins/editor.py:1818
+#: spyder/plugins/workingdirectory.py:70
+msgid "Open file"
+msgstr "Fájl megnyitása"
+
+#: spyder/plugins/editor.py:645 spyder/widgets/editor.py:346
+#, fuzzy
+msgid "File switcher..."
+msgstr "Fájlváltó..."
+
+#: spyder/plugins/editor.py:647
+#, fuzzy
+msgid "Fast switch between files"
+msgstr "Fájl gyorsváltó"
+
+#: spyder/plugins/editor.py:653
+#, fuzzy
+msgid "Symbol finder..."
+msgstr "Szimbólum keresés"
+
+#: spyder/plugins/editor.py:655
+#, fuzzy
+msgid "Fast symbol search in file"
+msgstr "Szimbólim gyorskeresés fájlban"
+
+#: spyder/plugins/editor.py:661
+msgid "&Revert"
+msgstr "&Visszatérés"
+
+#: spyder/plugins/editor.py:662
+#, fuzzy
+msgid "Revert file from disk"
+msgstr "Visszatérés a lemezenlevő fájlhoz"
+
+#: spyder/plugins/editor.py:665
+msgid "&Save"
+msgstr "&Mentés"
+
+#: spyder/plugins/editor.py:666 spyder/widgets/editor.py:1361
+msgid "Save file"
+msgstr "Fájl mentése"
+
+#: spyder/plugins/editor.py:672
+msgid "Sav&e all"
+msgstr "&Minden mentése"
+
+#: spyder/plugins/editor.py:673
+msgid "Save all files"
+msgstr "Minden fájl mentése"
+
+#: spyder/plugins/editor.py:679
+msgid "Save &as..."
+msgstr "Mentés másként"
+
+#: spyder/plugins/editor.py:680
+#, fuzzy
+msgid "Save current file as..."
+msgstr "A jelenlegi fájl mentése"
+
+#: spyder/plugins/editor.py:685 spyder/plugins/editor.py:686
+#, fuzzy
+msgid "Print preview..."
+msgstr "Nyomtatási előnézet"
+
+#: spyder/plugins/editor.py:687
+msgid "&Print..."
+msgstr "&Nyomtatás..."
+
+#: spyder/plugins/editor.py:688
+#, fuzzy
+msgid "Print current file..."
+msgstr "A jelenlegi fájl nyomtatása"
+
+#: spyder/plugins/editor.py:691
+msgid "&Close"
+msgstr "&bezárás"
+
+#: spyder/plugins/editor.py:692
+msgid "Close current file"
+msgstr "Jelenlegi fájl bezárása"
+
+#: spyder/plugins/editor.py:695
+msgid "C&lose all"
+msgstr "&Minden bezárása"
+
+#: spyder/plugins/editor.py:696
+#, fuzzy
+msgid "Close all opened files"
+msgstr "Az összes megnyitott fájl bezárása"
+
+#: spyder/plugins/editor.py:703
+#, fuzzy
+msgid "&Find text"
+msgstr "Szöveg keresés"
+
+#: spyder/plugins/editor.py:709
+#, fuzzy
+msgid "Find &next"
+msgstr "&Következőt"
+
+#: spyder/plugins/editor.py:715
+#, fuzzy
+msgid "Find &previous"
+msgstr "Előző"
+
+#: spyder/plugins/editor.py:721
+#, fuzzy
+msgid "&Replace text"
+msgstr "Szöveget kicserélni"
+
+#: spyder/plugins/editor.py:730
+#, fuzzy
+msgid "Set/Clear breakpoint"
+msgstr "Töréspont állítás"
+
+#: spyder/plugins/editor.py:737
+#, fuzzy
+msgid "Set/Edit conditional breakpoint"
+msgstr "Feltételes töréspont állítás"
+
+#: spyder/plugins/editor.py:744
+#, fuzzy
+msgid "Clear breakpoints in all files"
+msgstr "Az összes töréspont törlése"
+
+#: spyder/plugins/editor.py:746
+#, fuzzy
+msgid "Debug with winpdb"
+msgstr "winpdb"
+
+#: spyder/plugins/editor.py:753
+#, fuzzy
+msgid "Debug file"
+msgstr "Fájlban hibakeresés"
+
+#: spyder/plugins/editor.py:758
+msgid "Step"
+msgstr "Léptet"
+
+#: spyder/plugins/editor.py:759
+#, fuzzy
+msgid "Run current line"
+msgstr "aktuális sor futtatás"
+
+#: spyder/plugins/editor.py:764
+msgid "Continue"
+msgstr "Folytatás"
+
+#: spyder/plugins/editor.py:766
+msgid "Continue execution until next breakpoint"
+msgstr "Fojtatás következő töréspontig"
+
+#: spyder/plugins/editor.py:771
+#, fuzzy
+msgid "Step Into"
+msgstr "Belépés"
+
+#: spyder/plugins/editor.py:773
+msgid "Step into function or method of current line"
+msgstr "Belépés jelenlegi sor funciójába"
+
+#: spyder/plugins/editor.py:778
+#, fuzzy
+msgid "Step Return"
+msgstr "Kilép az aktuális szintről"
+
+#: spyder/plugins/editor.py:780
+msgid "Run until current function or method returns"
+msgstr "Futtatni amig a jelenlegi funció visszatér"
+
+#: spyder/plugins/editor.py:785 spyder/widgets/findinfiles.py:333
+#: spyder/widgets/ipythonconsole/client.py:248
+msgid "Stop"
+msgstr "Állj"
+
+#: spyder/plugins/editor.py:786
+#, fuzzy
+msgid "Stop debugging"
+msgstr "Nyomkövetés vége"
+
+#: spyder/plugins/editor.py:793
+#, fuzzy
+msgid "Run file"
+msgstr "Fájl futtatása"
+
+#: spyder/plugins/editor.py:798
+msgid "&Configure..."
+msgstr "B&eállítások..."
+
+#: spyder/plugins/editor.py:800 spyder/widgets/externalshell/pythonshell.py:304
+#, fuzzy
+msgid "Run settings"
+msgstr "Futtatás beállítások"
+
+#: spyder/plugins/editor.py:806
+#, fuzzy
+msgid "Re-run &last script"
+msgstr "Legutóbbi script megismétlése"
+
+#: spyder/plugins/editor.py:808
+#, fuzzy
+msgid "Run again last file"
+msgstr "Fájl újra futtatása"
+
+#: spyder/plugins/editor.py:814 spyder/widgets/sourcecode/codeeditor.py:2608
+#, fuzzy
+msgid "Run &selection or current line"
+msgstr "Vállasztás vagy vonal futtatása"
+
+#: spyder/plugins/editor.py:817
+#, fuzzy
+msgid "Run selection or current line"
+msgstr "Vállasztás vagy vonal futtatása"
+
+#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2600
+#, fuzzy
+msgid "Run cell"
+msgstr "Cella futtatása"
+
+#: spyder/plugins/editor.py:828
+msgid "Run current cell (Ctrl+Enter)\n"
+"[Use #%% to create cells]"
+msgstr "Jelenlegi cellát futtatni (CTR+ENTER)\n"
+"[Új cella: #%%]\""
+
+#: spyder/plugins/editor.py:834 spyder/widgets/sourcecode/codeeditor.py:2604
+#, fuzzy
+msgid "Run cell and advance"
+msgstr "Cellát futtatni, tovább lépni"
+
+#: spyder/plugins/editor.py:837
+msgid "Run current cell and go to the next one (Shift+Enter)"
+msgstr "Jelenlegi cellát futtatni, következőhöz lépni (Shift+Enter)"
+
+#: spyder/plugins/editor.py:844
+#, fuzzy
+msgid "Show todo list"
+msgstr "Teendők listát mutatni"
+
+#: spyder/plugins/editor.py:845
+msgid "Show TODO/FIXME/XXX/HINT/TIP/@todo comments list"
+msgstr "TODO/FIXME/XXX/HINT/TIP/@todo megjegyzés listát mutatni"
+
+#: spyder/plugins/editor.py:852
+#, fuzzy
+msgid "Show warning/error list"
+msgstr "Megjelenítendő figyelmeztető ablakok"
+
+#: spyder/plugins/editor.py:853
+msgid "Show code analysis warnings/errors"
+msgstr "Cód analizis jelsés és hibát mutatni"
+
+#: spyder/plugins/editor.py:859
+#, fuzzy
+msgid "Previous warning/error"
+msgstr "Előző hiba"
+
+#: spyder/plugins/editor.py:860
+msgid "Go to previous code analysis warning/error"
+msgstr "Előző jelzés vagy hiba"
+
+#: spyder/plugins/editor.py:863
+#, fuzzy
+msgid "Next warning/error"
+msgstr "Következő hiba keresése"
+
+#: spyder/plugins/editor.py:864
+msgid "Go to next code analysis warning/error"
+msgstr "Következő jelzés vagy hiba"
+
+#: spyder/plugins/editor.py:868
+#, fuzzy
+msgid "Last edit location"
+msgstr "Újbóli ütés a legutolsó pozícióból"
+
+#: spyder/plugins/editor.py:869
+#, fuzzy
+msgid "Go to last edit location"
+msgstr "Ugrás a helymegadási sorra"
+
+#: spyder/plugins/editor.py:877
+#, fuzzy
+msgid "Previous cursor position"
+msgstr "to previous position"
+
+#: spyder/plugins/editor.py:878
+#, fuzzy
+msgid "Go to previous cursor position"
+msgstr "Ugrás az &előző elrendezésre"
+
+#: spyder/plugins/editor.py:886
+#, fuzzy
+msgid "Next cursor position"
+msgstr "Kurzorpozíció"
+
+#: spyder/plugins/editor.py:887
+#, fuzzy
+msgid "Go to next cursor position"
+msgstr "Ugrás a &következőre"
+
+#: spyder/plugins/editor.py:897 spyder/widgets/sourcecode/codeeditor.py:2584
+msgid "Comment"
+msgstr "Megjegyzés"
+
+#: spyder/plugins/editor.py:897 spyder/widgets/sourcecode/codeeditor.py:2584
+msgid "Uncomment"
+msgstr "Kommentálást vissza"
+
+#: spyder/plugins/editor.py:898
+#, fuzzy
+msgid "Comment current line or selection"
+msgstr "Current &Selection"
+
+#: spyder/plugins/editor.py:902
+#, fuzzy
+msgid "Add &block comment"
+msgstr "Megjegyzés hozzáadása..."
+
+#: spyder/plugins/editor.py:903
+msgid "Add block comment around current line or selection"
+msgstr "Kommentálni a vállasztott vonal vagy kivállasztást"
+
+#: spyder/plugins/editor.py:909
+#, fuzzy
+msgid "R&emove block comment"
+msgstr "&Eltávolítás"
+
+#: spyder/plugins/editor.py:910
+msgid "Remove comment block around current line or selection"
+msgstr "Kommentálást vissza a vállasztott vonal vagy kivállasztással"
+
+#: spyder/plugins/editor.py:921
+msgid "Indent"
+msgstr "Behúzás"
+
+#: spyder/plugins/editor.py:922
+#, fuzzy
+msgid "Indent current line or selection"
+msgstr "Kijelölés"
+
+#: spyder/plugins/editor.py:925
+#, fuzzy
+msgid "Unindent"
+msgstr "&Behúzás megszüntetése"
+
+#: spyder/plugins/editor.py:926
+#, fuzzy
+msgid "Unindent current line or selection"
+msgstr "Current &Selection"
+
+#: spyder/plugins/editor.py:930
+#, fuzzy
+msgid "Toggle Uppercase"
+msgstr "&Nagybetűs"
+
+#: spyder/plugins/editor.py:931
+msgid "Change to uppercase current line or selection"
+msgstr "Vonal vagy kivállasztást nagy betükre"
+
+#: spyder/plugins/editor.py:937
+#, fuzzy
+msgid "Toggle Lowercase"
+msgstr "&Kisbetűs"
+
+#: spyder/plugins/editor.py:938
+msgid "Change to lowercase current line or selection"
+msgstr "Vonal vagy kivállasztást kis betükre"
+
+#: spyder/plugins/editor.py:945
+msgid "Carriage return and line feed (Windows)"
+msgstr "CR + LF (Windows)"
+
+#: spyder/plugins/editor.py:948
+#, fuzzy
+msgid "Line feed (UNIX)"
+msgstr "Csatorna"
+
+#: spyder/plugins/editor.py:951
+#, fuzzy
+msgid "Carriage return (Mac)"
+msgstr "Kocsivissza (CR)"
+
+#: spyder/plugins/editor.py:957
+#, fuzzy
+msgid "Convert end-of-line characters"
+msgstr "Konvertálás le&záró tag-re"
+
+#: spyder/plugins/editor.py:961
+#, fuzzy
+msgid "Remove trailing spaces"
+msgstr "Sorvégi szókö&zök eltávolítása"
+
+#: spyder/plugins/editor.py:965
+#, fuzzy
+msgid "Fix indentation"
+msgstr "Nincs behúzás"
+
+#: spyder/plugins/editor.py:966
+#, fuzzy
+msgid "Replace tab characters by space characters"
+msgstr ", Ignore white-space characters"
+
+#: spyder/plugins/editor.py:969
+#, fuzzy
+msgid "Go to line..."
+msgstr "Ugrás adott sorra..."
+
+#: spyder/plugins/editor.py:977
+#, fuzzy
+msgid "Set console working directory"
+msgstr "A munkakönyvtár nem módosítható"
+
+#: spyder/plugins/editor.py:979
+msgid "Set current console (and file explorer) working directory to current script directory"
+msgstr "Konzól és fájlböngésző directory-t állítani aktuális szerkesztett fájl directoryhoz"
+
+#: spyder/plugins/editor.py:984
+#, fuzzy
+msgid "Maximum number of recent files..."
+msgstr "Nemrégi fájlok"
+
+#: spyder/plugins/editor.py:987
+#, fuzzy
+msgid "Clear recent files list"
+msgstr "Törölni kívánja a dokumentumelőzmények listáját?"
+
+#: spyder/plugins/editor.py:987 spyder/plugins/projects.py:100
+#, fuzzy
+msgid "Clear this list"
+msgstr "Valóban újra felderíti a lemezeszközöket? Ez törölni fogja a függő műveletek listáját. "
+
+#: spyder/plugins/editor.py:991
+#, fuzzy
+msgid "Open &recent"
+msgstr "Leg&utóbbi megnyitása"
+
+#: spyder/plugins/editor.py:1621
+#, fuzzy
+msgid "Spyder Editor"
+msgstr "Spyder frissítések"
+
+#: spyder/plugins/editor.py:1622
+#, fuzzy
+msgid "This is a temporary script file."
+msgstr "Nem sikerült létrehozni egy ideiglenes szkriptet"
+
+#: spyder/plugins/editor.py:1691
+msgid "untitled"
+msgstr "névtelen"
+
+#: spyder/plugins/editor.py:1770
+#, fuzzy
+msgid "Maximum number of recent files"
+msgstr "Nemrégi fájlok"
+
+#: spyder/plugins/editor.py:1903
+msgid "Printing..."
+msgstr "Nyomtatás..."
+
+#: spyder/plugins/explorer.py:53
+#, fuzzy
+msgid "File explorer"
+msgstr "X fájlböngésző"
+
+#: spyder/plugins/externalconsole.py:46
+#, fuzzy
+msgid "Interactive data plotting in the consoles"
+msgstr "Párbeszédes konzol ábrázolás"
+
+#: spyder/plugins/externalconsole.py:54 spyder/plugins/externalconsole.py:725
+#, fuzzy
+msgid "Python console"
+msgstr "Python-konzol"
+
+#: spyder/plugins/externalconsole.py:59
+#, fuzzy
+msgid "One tab per script"
+msgstr "Egy lap per fájl"
+
+#: spyder/plugins/externalconsole.py:60
+#: spyder/widgets/externalshell/baseshell.py:160
+#, fuzzy
+msgid "Show elapsed time"
+msgstr "Eltelt idő"
+
+#: spyder/plugins/externalconsole.py:61 spyder/widgets/explorer.py:1094
+#, fuzzy
+msgid "Show icons and text"
+msgstr "Szöveg és szimólum "
+
+#: spyder/plugins/externalconsole.py:73
+#, fuzzy
+msgid "Buffer: "
+msgstr "Tároló: "
+
+#: spyder/plugins/externalconsole.py:73 spyder/plugins/ipythonconsole.py:320
+msgid " lines"
+msgstr " sor"
+
+#: spyder/plugins/externalconsole.py:78
+msgid "Merge process standard output/error channels"
+msgstr "Error és kimenet egyben"
+
+#: spyder/plugins/externalconsole.py:80
+msgid "Merging the output channels of the process means that\n"
+"the standard error won't be written in red anymore,\n"
+"but this has the effect of speeding up display."
+msgstr "Ha az error csatorna egyben van a kimenettel\n"
+"az error nem mutat pirosul, de gyorsabb a bemutató\n"
+
+#: spyder/plugins/externalconsole.py:84
+msgid "Colorize standard error channel using ANSI escape codes"
+msgstr "ANSI erroro csatorna szinezés"
+
+#: spyder/plugins/externalconsole.py:86
+msgid "This method is the only way to have colorized standard\n"
+"error channel when the output channels have been merged."
+msgstr "Ha az error csatorna egyben van a kimenettel,\n"
+"csak így lehet szinezve."
+
+#: spyder/plugins/externalconsole.py:102 spyder/plugins/ipythonconsole.py:307
+#: spyder/widgets/variableexplorer/arrayeditor.py:541
+#: spyder/widgets/variableexplorer/dataframeeditor.py:688
+msgid "Background color"
+msgstr "Háttérszín"
+
+#: spyder/plugins/externalconsole.py:103
+msgid "This option will be applied the next time a Python console or a terminal is opened."
+msgstr "Ez az opció csak új konzol vagy terminállal használ"
+
+#: spyder/plugins/externalconsole.py:106
+#, fuzzy
+msgid "Light background (white color)"
+msgstr "Világos háttér (fehér szín)"
+
+#: spyder/plugins/externalconsole.py:131
+#, fuzzy
+msgid "PYTHONSTARTUP replacement"
+msgstr "PYTHONSTARTUP Csere"
+
+#: spyder/plugins/externalconsole.py:133
+msgid "This option will override the PYTHONSTARTUP environment variable which\n"
+"defines the script to be executed during the Python console startup."
+msgstr "A PYTHONSTARTUP környezet változót átírni, ami a konzol kezdő fájlt\n"
+"határozza."
+
+#: spyder/plugins/externalconsole.py:138
+#, fuzzy
+msgid "Default PYTHONSTARTUP script"
+msgstr "Alap PYTHONSTARTUP szkript:"
+
+#: spyder/plugins/externalconsole.py:142
+#, fuzzy
+msgid "Use the following startup script:"
+msgstr "Ezt a kezdő fajlt használni:"
+
+#: spyder/plugins/externalconsole.py:159
+msgid "Monitor"
+msgstr "Monitor"
+
+#: spyder/plugins/externalconsole.py:160
+msgid "The monitor provides introspection features to console: code completion, calltips and variable explorer. Because it relies on several modules, disabling the monitor may be useful to accelerate console startup."
+msgstr "A monitor ezeket a vizsgáló eszközöket ad: kód egészítés, hívás-segítő és változó bongésző. Használata nélkül gyorsabb lehet a konzol kezdése."
+
+#: spyder/plugins/externalconsole.py:167
+#, fuzzy
+msgid "Enable monitor"
+msgstr "Monitort használni"
+
+#: spyder/plugins/externalconsole.py:180
+#, fuzzy
+msgid "Default library"
+msgstr "Köny&vtár"
+
+#: spyder/plugins/externalconsole.py:185
+msgid "Qt-Python Bindings"
+msgstr "Qt-python köttetés"
+
+#: spyder/plugins/externalconsole.py:187
+#, fuzzy
+msgid "Library:"
+msgstr "Köny&vtár"
+
+#: spyder/plugins/externalconsole.py:189
+msgid "This option will act on
libraries such as Matplotlib, guidata or ETS"
+msgstr "Matplotlib, guidata, ETS stb.-re vonatkozó"
+
+#: spyder/plugins/externalconsole.py:198 spyder/plugins/ipythonconsole.py:561
+msgid "Graphics"
+msgstr "Grafika"
+
+#: spyder/plugins/externalconsole.py:199
+msgid "Decide which backend to use to display graphics. If unsure, please select the Automatic backend.
Note: We support a very limited number of backends in our Python consoles. If you prefer to work with a different one, please use an IPython console."
+msgstr "Melyik grafikuz csomagot használni. Ha nem tudja, válasszon Automatikus-at.
Note: Ha másik csomag kellene, próbálja a IPython konzolt."
+
+#: spyder/plugins/externalconsole.py:208
+#, fuzzy
+msgid "None"
+msgstr "Semmi"
+
+#: spyder/plugins/externalconsole.py:208 spyder/plugins/ipythonconsole.py:352
+msgid "Automatic"
+msgstr "Automatikus"
+
+#: spyder/plugins/externalconsole.py:213 spyder/plugins/ipythonconsole.py:374
+#, fuzzy
+msgid "Backend:"
+msgstr "Backend:"
+
+#: spyder/plugins/externalconsole.py:215 spyder/plugins/ipythonconsole.py:376
+msgid "This option will be applied the next time a console is opened."
+msgstr "Csak új konsol nyitással használ"
+
+#: spyder/plugins/externalconsole.py:226
+#, fuzzy
+msgid "Enthought Tool Suite"
+msgstr "Enthought Szerszám"
+
+#: spyder/plugins/externalconsole.py:227
+msgid "Enthought Tool Suite (ETS) supports PyQt4 (qt4) and wxPython (wx) graphical user interfaces."
+msgstr "Az ETS PyQt4 (qt4) vagy wxPython (wx) graphikai interfacet használ."
+
+#: spyder/plugins/externalconsole.py:231
+#, fuzzy
+msgid "ETS_TOOLKIT:"
+msgstr "ETS_TOOLKIT:"
+
+#: spyder/plugins/externalconsole.py:255
+#, fuzzy
+msgid "External modules"
+msgstr "Külső modulok\n"
+
+#: spyder/plugins/externalconsole.py:448
+msgid "No Python console is currently selected to run %s.
Please select or open a new Python console and try again."
+msgstr "Nincs Python konzol kiválasztva %s futtatására.
Válasszon vagy nyisson Python konzolt és próbálja megint."
+
+#: spyder/plugins/externalconsole.py:519
+msgid "%s is already running in a separate process.\n"
+"Do you want to kill the process before starting a new one?"
+msgstr "%s már fut másik processzben.\n"
+"Processzt lezárni mielött újjabb indul?"
+
+#: spyder/plugins/externalconsole.py:651
+#, fuzzy
+msgid "Command Window"
+msgstr "Parancs ablak"
+
+#: spyder/plugins/externalconsole.py:653 spyder/plugins/ipythonconsole.py:298
+msgid "Terminal"
+msgstr "Terminál"
+
+#: spyder/plugins/externalconsole.py:739
+#, fuzzy
+msgid "Open a &Python console"
+msgstr "Python-konzol"
+
+#: spyder/plugins/externalconsole.py:743
+#, fuzzy
+msgid "Open &command prompt"
+msgstr "&Parancssolót nyitni"
+
+#: spyder/plugins/externalconsole.py:744
+#, fuzzy
+msgid "Open a Windows command prompt"
+msgstr "Windows parancsolót nyitni"
+
+#: spyder/plugins/externalconsole.py:746
+#, fuzzy
+msgid "Open a &terminal"
+msgstr "Terminál megnyitása"
+
+#: spyder/plugins/externalconsole.py:747
+#, fuzzy
+msgid "Open a terminal window"
+msgstr "&Terminál ablak nyitása"
+
+#: spyder/plugins/findinfiles.py:127 spyder/widgets/findinfiles.py:689
+#, fuzzy
+msgid "Find in files"
+msgstr "Fájlkereső"
+
+#: spyder/plugins/findinfiles.py:148
+#, fuzzy
+msgid "&Find in files"
+msgstr "Fájlkereső"
+
+#: spyder/plugins/findinfiles.py:151
+#, fuzzy
+msgid "Search text in multiple files"
+msgstr "Szövegkeresés több fájlban"
+
+#: spyder/plugins/help.py:44
+msgid "Show help for objects in the Editor and Consoles in a dedicated pane"
+msgstr "Szerkesztő és konzol segítséget saját lapokban"
+
+#: spyder/plugins/help.py:110
+#, fuzzy
+msgid "Automatic connections"
+msgstr "Automatikus connekció"
+
+#: spyder/plugins/help.py:111
+msgid "This pane can automatically show an object's help information after a left parenthesis is written next to it. Below you can decide to which plugin you want to connect it to turn on this feature."
+msgstr "Ez a lap automatkusan mutathat tárgyok segítségét zárójel nyításánál. Melyik eszközhöz kapcsoljon."
+
+#: spyder/plugins/help.py:123
+msgid "This feature requires the Rope or Jedi libraries.\n"
+"It seems you don't have either installed."
+msgstr "Rope vagy Jedi csomag kell.\n"
+"Semejiket sem találni.."
+
+#: spyder/plugins/help.py:126
+msgid "Python Console"
+msgstr "Python-konzol"
+
+#: spyder/plugins/help.py:128
+#, fuzzy
+msgid "IPython Console"
+msgstr "IPython konzol"
+
+#: spyder/plugins/help.py:140
+#, fuzzy
+msgid "Additional features"
+msgstr "Extra "
+
+#: spyder/plugins/help.py:141
+#, fuzzy
+msgid "Render mathematical equations"
+msgstr "Egyenletek rajzolása"
+
+#: spyder/plugins/help.py:147
+msgid "This feature requires Sphinx 1.1 or superior."
+msgstr "Sphinx 1.1 vagy jobb kell"
+
+#: spyder/plugins/help.py:148
+#, fuzzy
+msgid "Sphinx %s is currently installed."
+msgstr "Sphinx %s van telepítve."
+
+#: spyder/plugins/help.py:309
+#, fuzzy
+msgid "No further documentation available"
+msgstr "Nem érhető több dokumentáció"
+
+#: spyder/plugins/help.py:347
+#, fuzzy
+msgid "No documentation available"
+msgstr "Nincs dokumentáció"
+
+#: spyder/plugins/help.py:378
+msgid "Source"
+msgstr "Forrás"
+
+#: spyder/plugins/help.py:385 spyder/plugins/runconfig.py:196
+#: spyder/plugins/runconfig.py:468 spyder/widgets/externalshell/baseshell.py:94
+#: spyder/widgets/ipythonconsole/client.py:221
+msgid "Console"
+msgstr "Konzol"
+
+#: spyder/plugins/help.py:393
+msgid "Object"
+msgstr "Tárgy"
+
+#: spyder/plugins/help.py:407
+msgid "Plain Text"
+msgstr "Egyszerű szöveges"
+
+#: spyder/plugins/help.py:411
+#, fuzzy
+msgid "Show Source"
+msgstr "Forrást mutatni"
+
+#: spyder/plugins/help.py:415
+#, fuzzy
+msgid "Rich Text"
+msgstr "Gazdag szöveg"
+
+#: spyder/plugins/help.py:425
+#, fuzzy
+msgid "Automatic import"
+msgstr "Automatikus import"
+
+#: spyder/plugins/help.py:437 spyder/plugins/history.py:106
+#: spyder/widgets/editor.py:533 spyder/widgets/explorer.py:1105
+#: spyder/widgets/externalshell/baseshell.py:140
+#: spyder/widgets/ipythonconsole/client.py:261
+#: spyder/widgets/variableexplorer/namespacebrowser.py:171
+msgid "Options"
+msgstr "Paraméterek"
+
+#: spyder/plugins/help.py:695
+msgid "Here you can get help of any object by pressing %s in front of it, either on the Editor or the Console.%sHelp can also be shown automatically after writing a left parenthesis next to an object. You can activate this behavior in %s."
+msgstr "Itt segítség kapható bármilyen tárgyra, %s -al A szerkesztő vagy a konzolban.%sAutomatikus segítség kapható zárójel nyítással ha itt aktivált: %s."
+
+#: spyder/plugins/help.py:701
+#, fuzzy
+msgid "Preferences > Help"
+msgstr "beállítások > Segítség"
+
+#: spyder/plugins/help.py:708
+msgid "Usage"
+msgstr "Használat"
+
+#: spyder/plugins/help.py:709
+#, fuzzy
+msgid "New to Spyder? Read our"
+msgstr "Új a Spyderben? Olvassa"
+
+#: spyder/plugins/help.py:710
+#, fuzzy
+msgid "tutorial"
+msgstr "Oktató"
+
+#: spyder/plugins/help.py:717
+msgid "Please consider installing Sphinx to get documentation rendered in rich text."
+msgstr "Telepítse Sphinx-et gazdag szövegü dokumetációért."
+
+#: spyder/plugins/help.py:886
+msgid "Lock"
+msgstr "Zárolás"
+
+#: spyder/plugins/help.py:886
+msgid "Unlock"
+msgstr "Feloldás"
+
+#: spyder/plugins/help.py:930
+msgid "The following error occured when calling Sphinx %s.
Incompatible Sphinx version or doc string decoding failed.
Error message:
%s"
+msgstr "Sphinx %s error.
Incompatible Sphinx version or doc string decoding failed.
Szöveg:
%s"
+
+#: spyder/plugins/help.py:974
+#, fuzzy
+msgid "No source code available."
+msgstr "forráskód nincs"
+
+#: spyder/plugins/history.py:39
+msgid "Settings"
+msgstr "Beállítások"
+
+#: spyder/plugins/history.py:41
+msgid " entries"
+msgstr " bejegyzés"
+
+#: spyder/plugins/history.py:41
+#, fuzzy
+msgid "History depth: "
+msgstr " Előzmény mélység"
+
+#: spyder/plugins/history.py:48
+#, fuzzy
+msgid "Scroll automatically to last entry"
+msgstr "Utolsó bejegyzést mutatni"
+
+#: spyder/plugins/history.py:126
+#, fuzzy
+msgid "History log"
+msgstr "Előzmény jegyző"
+
+#: spyder/plugins/history.py:153
+#, fuzzy
+msgid "History..."
+msgstr "Előzmények..."
+
+#: spyder/plugins/history.py:155
+#, fuzzy
+msgid "Set history maximum entries"
+msgstr "Előzmények maximum bejegyzések"
+
+#: spyder/plugins/history.py:260
+msgid "History"
+msgstr "Előzmények"
+
+#: spyder/plugins/history.py:261
+#, fuzzy
+msgid "Maximum entries"
+msgstr "maximum bejegyzések"
+
+#: spyder/plugins/ipythonconsole.py:65
+msgid "Symbolic mathematics in the IPython Console"
+msgstr "Szimbolikus matematika az IPython konzolban"
+
+#: spyder/plugins/ipythonconsole.py:117
+msgid "The authenticity of host %s can't be established. Are you sure you want to continue connecting?"
+msgstr "A %s identitása nem igazolva. Tovább?"
+
+#: spyder/plugins/ipythonconsole.py:129
+msgid "The authenticity of the host can't be established"
+msgstr "számítógép identitása nem igazolva"
+
+#: spyder/plugins/ipythonconsole.py:136
+#, fuzzy
+msgid "Tunnel '%s' failed to start"
+msgstr "Alagút '%s' nem sikerültr."
+
+#: spyder/plugins/ipythonconsole.py:141
+#, fuzzy
+msgid "Could not connect to remote host"
+msgstr "Nem lehet kapcsolódni a távoli számítógéphez."
+
+#: spyder/plugins/ipythonconsole.py:158 spyder/plugins/ipythonconsole.py:750
+#, fuzzy
+msgid "Connect to an existing kernel"
+msgstr "Kapcsolat létező maghoz"
+
+#: spyder/plugins/ipythonconsole.py:160
+msgid "Please enter the connection info of the kernel you want to connect to. For that you can either select its JSON connection file using the Browse button, or write directly its id, in case it's a local kernel (for example kernel-3764.json or just 3764)."
+msgstr "Beírni a mag kapcsolat adatokat.JSON kapcsolat fájlt keresni: Bongésző, vagy nevét beírni (például kernel-3764.json vagy 3764)."
+
+#: spyder/plugins/ipythonconsole.py:171
+#, fuzzy
+msgid "Connection info:"
+msgstr "Kapcsolat adatok"
+
+#: spyder/plugins/ipythonconsole.py:173
+msgid "Path to connection file or kernel id"
+msgstr "Kapcsolat fájl vagy mag név helyszíne"
+
+#: spyder/plugins/ipythonconsole.py:175 spyder/plugins/ipythonconsole.py:192
+msgid "Browse"
+msgstr "Bongésző"
+
+#: spyder/plugins/ipythonconsole.py:184
+#, fuzzy
+msgid "This is a remote kernel"
+msgstr "Távoli mag"
+
+#: spyder/plugins/ipythonconsole.py:188
+msgid "username@hostname:port"
+msgstr "felhasználó@gép:kapu"
+
+#: spyder/plugins/ipythonconsole.py:191
+#, fuzzy
+msgid "Path to ssh key file"
+msgstr "SSH kulcs fájl helyszíne"
+
+#: spyder/plugins/ipythonconsole.py:200
+msgid "Password or ssh key passphrase"
+msgstr "Jelszó vagy ssh kulcs jelmondat"
+
+#: spyder/plugins/ipythonconsole.py:204
+msgid "Host name"
+msgstr "Gépnév"
+
+#: spyder/plugins/ipythonconsole.py:205
+#, fuzzy
+msgid "Ssh key"
+msgstr "SSH kulcs"
+
+#: spyder/plugins/ipythonconsole.py:206
+msgid "Password"
+msgstr "Jelszó"
+
+#: spyder/plugins/ipythonconsole.py:235
+#, fuzzy
+msgid "Open connection file"
+msgstr "Kapcsolat Fájl megnyitása"
+
+#: spyder/plugins/ipythonconsole.py:240
+#, fuzzy
+msgid "Select ssh key"
+msgstr "SSH kulcs választás"
+
+#: spyder/plugins/ipythonconsole.py:268 spyder/plugins/ipythonconsole.py:687
+#, fuzzy
+msgid "IPython console"
+msgstr "IPython konzol"
+
+#: spyder/plugins/ipythonconsole.py:275
+#, fuzzy
+msgid "Display initial banner"
+msgstr "Köszöntő szöveget mutatni"
+
+#: spyder/plugins/ipythonconsole.py:276
+msgid "This option lets you hide the message shown at\n"
+"the top of the console when it's opened."
+msgstr "Ez elbujtatja a kezdő üzenetet amikor új konzol nyílik."
+
+#: spyder/plugins/ipythonconsole.py:278
+msgid "Use a pager to display additional text inside the console"
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:280
+msgid "Useful if you don't want to fill the console with long help or completion texts.\n"
+"Note: Use the Q key to get out of the pager."
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:285
+#, fuzzy
+msgid "Ask for confirmation before closing"
+msgstr "Megerősítés kérése a zárás elött."
+
+#: spyder/plugins/ipythonconsole.py:295
+msgid "Completion Type"
+msgstr "Kiegészítés típusa"
+
+#: spyder/plugins/ipythonconsole.py:296
+msgid "Decide what type of completion to use"
+msgstr "Befejezés tipus vállasztása"
+
+#: spyder/plugins/ipythonconsole.py:298
+msgid "Graphical"
+msgstr "Grafikai"
+
+#: spyder/plugins/ipythonconsole.py:298
+msgid "Plain"
+msgstr "Egyszerű"
+
+#: spyder/plugins/ipythonconsole.py:299
+msgid "Completion:"
+msgstr "Kiegészítés:"
+
+#: spyder/plugins/ipythonconsole.py:308
+#, fuzzy
+msgid "Light background"
+msgstr "Világos háttér"
+
+#: spyder/plugins/ipythonconsole.py:310
+#, fuzzy
+msgid "Dark background"
+msgstr "Sötét háttér"
+
+#: spyder/plugins/ipythonconsole.py:320
+#, fuzzy
+msgid "Buffer: "
+msgstr "Tároló: "
+
+#: spyder/plugins/ipythonconsole.py:322
+msgid "Set the maximum number of lines of text shown in the\n"
+"console before truncation. Specifying -1 disables it\n"
+"(not recommended!)"
+msgstr "Hány sort tároljon a konzol. -1 kikapcsolja \n"
+"(nem javasolt!)"
+
+#: spyder/plugins/ipythonconsole.py:331
+#, fuzzy
+msgid "Support for graphics (Matplotlib)"
+msgstr "Matplotlib grafika segély"
+
+#: spyder/plugins/ipythonconsole.py:332
+#, fuzzy
+msgid "Activate support"
+msgstr "Aktiválás:"
+
+#: spyder/plugins/ipythonconsole.py:333
+msgid "Automatically load Pylab and NumPy modules"
+msgstr "Automatikusan betölteni pylab/numpy modulokat"
+
+#: spyder/plugins/ipythonconsole.py:336
+msgid "This lets you load graphics support without importing \n"
+"the commands to do plots. Useful to work with other\n"
+"plotting libraries different to Matplotlib or to develop \n"
+"GUIs with Spyder."
+msgstr "Importálás nélküli grafikus ábrázolás \n"
+"\""
+
+#: spyder/plugins/ipythonconsole.py:351
+msgid "Inline"
+msgstr "Inline"
+
+#: spyder/plugins/ipythonconsole.py:353
+#, fuzzy
+msgid "Graphics backend"
+msgstr "Graphikus csomag"
+
+#: spyder/plugins/ipythonconsole.py:354
+msgid "Decide how graphics are going to be displayed in the console. If unsure, please select %s to put graphics inside the console or %s to interact with them (through zooming and panning) in a separate window."
+msgstr "Grafika mutatása a konzolban. Használjon %s hogy a konzolban jelenjen vagy %s külön ablakban."
+
+#: spyder/plugins/ipythonconsole.py:387
+msgid "Inline backend"
+msgstr "Inline graficai hátsó"
+
+#: spyder/plugins/ipythonconsole.py:388
+msgid "Decide how to render the figures created by this backend"
+msgstr "Ennek a hátsórésznek grafikai kimenetei mutatását vállasztani"
+
+#: spyder/plugins/ipythonconsole.py:392
+msgid "Format:"
+msgstr "Formátum:"
+
+#: spyder/plugins/ipythonconsole.py:395
+msgid "Resolution:"
+msgstr "Felbontás:"
+
+#: spyder/plugins/ipythonconsole.py:395
+#, fuzzy
+msgid "dpi"
+msgstr " dpi"
+
+#: spyder/plugins/ipythonconsole.py:397
+msgid "Only used when the format is PNG. Default is 72"
+msgstr "Csak PNG-vel számít. Alap: 72"
+
+#: spyder/plugins/ipythonconsole.py:400
+msgid "Width:"
+msgstr "Szélesség:"
+
+#: spyder/plugins/ipythonconsole.py:400 spyder/plugins/ipythonconsole.py:404
+msgid "inches"
+msgstr "hüvelyk"
+
+#: spyder/plugins/ipythonconsole.py:402
+#, fuzzy
+msgid "Default is 6"
+msgstr "Alap: 6"
+
+#: spyder/plugins/ipythonconsole.py:404
+msgid "Height:"
+msgstr "Magasság:"
+
+#: spyder/plugins/ipythonconsole.py:406
+#, fuzzy
+msgid "Default is 4"
+msgstr "Alap: 4"
+
+#: spyder/plugins/ipythonconsole.py:433
+msgid "You can run several lines of code when a console is started. Please introduce each one separated by commas, for example:
import os, import sys"
+msgstr "Konzol kezdéskor ezt a kódot futtatni. Vesszőket használni parancsok közt:
import os, import sys"
+
+#: spyder/plugins/ipythonconsole.py:439
+msgid "Lines:"
+msgstr "Sorok:"
+
+#: spyder/plugins/ipythonconsole.py:448
+#, fuzzy
+msgid "Run a file"
+msgstr "Fájl futtatása"
+
+#: spyder/plugins/ipythonconsole.py:449
+msgid "You can also run a whole file at startup instead of just some lines (This is similar to have a PYTHONSTARTUP file)."
+msgstr "Teljes fájlt futtatni konzol kezdéskor (mint PYTHONSTARTUP)."
+
+#: spyder/plugins/ipythonconsole.py:453
+#, fuzzy
+msgid "Use the following file:"
+msgstr "Ezt a fájlt hsználni:"
+
+#: spyder/plugins/ipythonconsole.py:467
+#, fuzzy
+msgid "Greedy completion"
+msgstr "Mohó Kiegészítés:"
+
+#: spyder/plugins/ipythonconsole.py:468
+msgid "Enable Tab completion on elements of lists, results of function calls, etc, without assigning them to a variable.
For example, you can get completions on things like li[0].<Tab> or ins.meth().<Tab>"
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:476
+#, fuzzy
+msgid "Use the greedy completer"
+msgstr "Mohó kiegészítőt használni"
+
+#: spyder/plugins/ipythonconsole.py:487
+msgid "Autocall"
+msgstr "Auto-hívás"
+
+#: spyder/plugins/ipythonconsole.py:488
+msgid "Autocall makes IPython automatically call any callable object even if you didn't type explicit parentheses.
For example, if you type str 43 it becomes str(43) automatically."
+msgstr "Hogy IPython automatikusan hívjon bármilyen hívható tárgyat zárójel nélkül is.
Példa: str 43-ból str(43) kelekezik automatikusan."
+
+#: spyder/plugins/ipythonconsole.py:495
+msgid "Smart"
+msgstr "Intelligens"
+
+#: spyder/plugins/ipythonconsole.py:496
+msgid "Full"
+msgstr "Teljes"
+
+#: spyder/plugins/ipythonconsole.py:497
+msgid "Off"
+msgstr "Ki"
+
+#: spyder/plugins/ipythonconsole.py:499
+msgid "Autocall: "
+msgstr "Auto-hívás"
+
+#: spyder/plugins/ipythonconsole.py:500
+msgid "On %s mode, Autocall is not applied if there are no arguments after the callable. On %s mode, all callable objects are automatically called (even if no arguments are present)."
+msgstr "%s módban, Auto-hívas nem vonatkozik ha a hívható után nincs több. %s módban, minden hívható automatikusan meg van hívva."
+
+#: spyder/plugins/ipythonconsole.py:512
+#, fuzzy
+msgid "Symbolic Mathematics"
+msgstr "Szimbolikus Matematika"
+
+#: spyder/plugins/ipythonconsole.py:513
+msgid "Perfom symbolic operations in the console (e.g. integrals, derivatives, vector calculus, etc) and get the outputs in a beautifully printed style (it requires the Sympy module)."
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:518
+#, fuzzy
+msgid "Use symbolic math"
+msgstr "Szimbolikus matek használata"
+
+#: spyder/plugins/ipythonconsole.py:519
+msgid "This option loads the Sympy library to work with.
Please refer to its documentation to learn how to use it."
+msgstr "Betölteni a Sympy könyvtárt.
Olvassa a dokumentációját."
+
+#: spyder/plugins/ipythonconsole.py:529
+#, fuzzy
+msgid "Prompts"
+msgstr "Promptok"
+
+#: spyder/plugins/ipythonconsole.py:530
+msgid "Modify how Input and Output prompts are shown in the console."
+msgstr "Hogyan mutatni bemenet és kimenet promptokat"
+
+#: spyder/plugins/ipythonconsole.py:533
+#, fuzzy
+msgid "Input prompt:"
+msgstr "Bemenet Prompt"
+
+#: spyder/plugins/ipythonconsole.py:535
+msgid "Default is
In [<span class=\"in-prompt-number\">%i</span>]:"
+msgstr "Alap:
In [<span class=\"in-prompt-number\">%i</span>]:"
+
+#: spyder/plugins/ipythonconsole.py:539
+#, fuzzy
+msgid "Output prompt:"
+msgstr "Kimenet Prompt"
+
+#: spyder/plugins/ipythonconsole.py:541
+msgid "Default is
Out[<span class=\"out-prompt-number\">%i</span>]:"
+msgstr "Alap:
Out[<span class=\"out-prompt-number\">%i</span>]:"
+
+#: spyder/plugins/ipythonconsole.py:563 spyder/plugins/workingdirectory.py:45
+msgid "Startup"
+msgstr "Indítás"
+
+#: spyder/plugins/ipythonconsole.py:735
+#, fuzzy
+msgid "Open an &IPython console"
+msgstr "IPython konzol nyitás.\n"
+
+#: spyder/plugins/ipythonconsole.py:742
+msgid "Restart kernel"
+msgstr "Kernel újraindítása"
+
+#: spyder/plugins/ipythonconsole.py:751
+msgid "Open a new IPython console connected to an existing kernel"
+msgstr "Új IPython konzolt nyitni, létező maghoz kapcsolva"
+
+#: spyder/plugins/ipythonconsole.py:841
+msgid "No IPython console is currently available to run %s.
Please open a new one and try again."
+msgstr "Nincs IPython konzol a %s futtatására.
Kezdjen újjat és probálja megint."
+
+#: spyder/plugins/ipythonconsole.py:883
+msgid "The directory {} is not writable and it is required to create IPython consoles. Please make it writable."
+msgstr "Helyszín {} nem írható!"
+
+#: spyder/plugins/ipythonconsole.py:896
+msgid "Your Python environment or installation doesn't have the ipykernel module installed on it. Without this module is not possible for Spyder to create a console for you.
You can install ipykernel by running in a terminal:
pip install ipykernel
or
conda install ipykernel"
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:1123
+#, fuzzy
+msgid "Do you want to close this console?"
+msgstr "Ezt a konzolt bezárni?"
+
+#: spyder/plugins/ipythonconsole.py:1129
+msgid "Do you want to close all other consoles connected to the same kernel as this one?"
+msgstr "Minden konzolt ehhez a maghoz kapcsolva bezárni?"
+
+#: spyder/plugins/ipythonconsole.py:1187
+msgid "It was not possible to restart the IPython console when switching to this project. The error was {0}"
+msgstr "IPython konzol újraindítás ebben a projektben nem sikerült. Error: {0}"
+
+#: spyder/plugins/ipythonconsole.py:1426
+msgid "IPython"
+msgstr "IPython"
+
+#: spyder/plugins/ipythonconsole.py:1427
+#, fuzzy
+msgid "Unable to connect to %s"
+msgstr "Kapcsolás nem sikerült: %s"
+
+#: spyder/plugins/ipythonconsole.py:1487
+msgid "Connection error"
+msgstr "Csatlakozási hiba"
+
+#: spyder/plugins/ipythonconsole.py:1488
+#, fuzzy
+msgid "Could not open ssh tunnel. The error was:\n"
+"\n"
+msgstr "SSH alagút nyitás hiba. Error: \n"
+
+#: spyder/plugins/layoutdialog.py:177
+msgid "Move Up"
+msgstr "Mozgatás felfelé"
+
+#: spyder/plugins/layoutdialog.py:178
+msgid "Move Down"
+msgstr "Mozgatás lefelé"
+
+#: spyder/plugins/layoutdialog.py:179
+msgid "Delete Layout"
+msgstr "Kirendezés törlése"
+
+#: spyder/plugins/layoutdialog.py:183
+#, fuzzy
+msgid "Layout Display and Order"
+msgstr "Kirendezés mutatás-sorrend:"
+
+#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:66
+#, fuzzy
+msgid "Python interpreter"
+msgstr "Python paracsoló"
+
+#: spyder/plugins/maininterpreter.py:68
+msgid "Select the Python interpreter for all Spyder consoles"
+msgstr "Python paracsoló minden Spyder konzolban"
+
+#: spyder/plugins/maininterpreter.py:71
+msgid "Default (i.e. the same as Spyder's)"
+msgstr "Alap (az mint Spyderé)"
+
+#: spyder/plugins/maininterpreter.py:74
+#, fuzzy
+msgid "Use the following Python interpreter:"
+msgstr "Ezt a python paracsolót használni"
+
+#: spyder/plugins/maininterpreter.py:77
+#, fuzzy
+msgid "Executables"
+msgstr "Futtatható"
+
+#: spyder/plugins/maininterpreter.py:94
+#, fuzzy
+msgid "User Module Reloader (UMR)"
+msgstr "Használói modul újrabetöltő"
+
+#: spyder/plugins/maininterpreter.py:95
+msgid "UMR forces Python to reload modules which were imported when executing a file in a Python or IPython console with the runfile function."
+msgstr ""
+
+#: spyder/plugins/maininterpreter.py:100
+#, fuzzy
+msgid "Enable UMR"
+msgstr "Használni"
+
+#: spyder/plugins/maininterpreter.py:101
+msgid "This option will enable the User Module Reloader (UMR) in Python/IPython consoles. UMR forces Python to reload deeply modules during import when running a Python script using the Spyder's builtin function runfile.
1. UMR may require to restart the console in which it will be called (otherwise only newly imported modules will be reloaded when executing files).
2. If errors occur when re-running a PyQt-based program, please check that the Qt objects are properly destroyed (e.g. you may have to use the attribute Qt.WA_DeleteOnClose on your main window, using the setAttribute method)"
+msgstr ""
+
+#: spyder/plugins/maininterpreter.py:117
+#, fuzzy
+msgid "Show reloaded modules list"
+msgstr "Újrabetöltött modul listát mutatni"
+
+#: spyder/plugins/maininterpreter.py:118
+msgid "Please note that these changes will be applied only to new consoles"
+msgstr "Változások csaj új konzolokkal eredményesek"
+
+#: spyder/plugins/maininterpreter.py:122
+msgid "Set UMR excluded (not reloaded) modules"
+msgstr "Ezeket a odulokat nem újrabetölteni"
+
+#: spyder/plugins/maininterpreter.py:148
+msgid "You selected an invalid Python interpreter for the console so the previous interpreter will stay. Please make sure to select a valid one."
+msgstr ""
+
+#: spyder/plugins/maininterpreter.py:176
+msgid "You selected a Python %d interpreter for the console but Spyder is running on Python %d!.
Although this is possible, we recommend you to install and run Spyder directly with your selected interpreter, to avoid seeing false warnings and errors due to the incompatible syntax between these two Python versions."
+msgstr ""
+
+#: spyder/plugins/maininterpreter.py:186 spyder/plugins/maininterpreter.py:213
+#: spyder/plugins/maininterpreter.py:217
+msgid "UMR"
+msgstr ""
+
+#: spyder/plugins/maininterpreter.py:187
+msgid "Set the list of excluded modules as this: numpy, scipy"
+msgstr "Kizért modulokat így írni: numpy, scipy"
+
+#: spyder/plugins/maininterpreter.py:204
+msgid "You are working with Python 2, this means that you can not import a module that contains non-ascii characters."
+msgstr "YPython 2-val nem lehet modult importálni miben nem-ascii betük vannak."
+
+#: spyder/plugins/maininterpreter.py:214
+msgid "The following modules are not installed on your machine:\n"
+"%s"
+msgstr "Ezek a modulok nem vannak telepítve:\n"
+"%s"
+
+#: spyder/plugins/maininterpreter.py:218
+msgid "Please note that these changes will be applied only to new Python/IPython consoles"
+msgstr "Változások csak új Python/IPython konzollal eredményesek"
+
+#: spyder/plugins/onlinehelp.py:70
+#, fuzzy
+msgid "Online help"
+msgstr "Online Segítség"
+
+#: spyder/plugins/outlineexplorer.py:49 spyder/widgets/editortools.py:195
+msgid "Outline"
+msgstr "Körvonal"
+
+#: spyder/plugins/projects.py:76 spyder/widgets/projects/explorer.py:112
+#: spyder/widgets/projects/explorer.py:126
+#, fuzzy
+msgid "Project explorer"
+msgstr "Projekt böngésző"
+
+#: spyder/plugins/projects.py:88
+#, fuzzy
+msgid "New Project..."
+msgstr "Új projekt"
+
+#: spyder/plugins/projects.py:91
+#, fuzzy
+msgid "Open Project..."
+msgstr "Projekt megnyitása"
+
+#: spyder/plugins/projects.py:94
+#, fuzzy
+msgid "Close Project"
+msgstr "Projekt bezárás"
+
+#: spyder/plugins/projects.py:97
+#, fuzzy
+msgid "Delete Project"
+msgstr "Projekt törlése"
+
+#: spyder/plugins/projects.py:103
+#, fuzzy
+msgid "Project Preferences"
+msgstr "Projekt beállítások"
+
+#: spyder/plugins/projects.py:105
+#, fuzzy
+msgid "Recent Projects"
+msgstr "Utóbbi Projectek"
+
+#: spyder/plugins/projects.py:240
+msgid "Open project"
+msgstr "Projekt megnyitása"
+
+#: spyder/plugins/projects.py:245
+#, fuzzy
+msgid "%s is not a Spyder project!"
+msgstr "%s nem Spyder projekt"
+
+#: spyder/plugins/runconfig.py:29
+msgid "Execute in current Python or IPython console"
+msgstr "Jelenlegi Python vagy IPython konzolban futtatni"
+
+#: spyder/plugins/runconfig.py:30
+msgid "Execute in a new dedicated Python console"
+msgstr "Saját új python konzolban futtatni"
+
+#: spyder/plugins/runconfig.py:31
+#, fuzzy
+msgid "Execute in an external System terminal"
+msgstr "Végrehajtás terminálablakban"
+
+#: spyder/plugins/runconfig.py:41
+msgid "Always show %s on a first file run"
+msgstr "Mindig mutatni %s, amikor először fut egy fájl"
+
+#: spyder/plugins/runconfig.py:44
+msgid "Clear all variables before execution (IPython consoles)"
+msgstr "Minden változót törölni futtatás elött (IPython konzolban)"
+
+#: spyder/plugins/runconfig.py:166 spyder/plugins/runconfig.py:486
+#, fuzzy
+msgid "General settings"
+msgstr "Általános beállítások"
+
+#: spyder/plugins/runconfig.py:171 spyder/plugins/runconfig.py:219
+#, fuzzy
+msgid "Command line options:"
+msgstr "parancssori opciók:"
+
+#: spyder/plugins/runconfig.py:177
+#, fuzzy
+msgid "Working directory:"
+msgstr "Munkahely"
+
+#: spyder/plugins/runconfig.py:189 spyder/plugins/runconfig.py:504
+msgid "Enter debugging mode when errors appear during execution"
+msgstr "Hiba utáni debugging"
+
+#: spyder/plugins/runconfig.py:207 spyder/plugins/runconfig.py:517
+#, fuzzy
+msgid "Dedicated Python console"
+msgstr "Saját Python-konzol"
+
+#: spyder/plugins/runconfig.py:211 spyder/plugins/runconfig.py:519
+msgid "Interact with the Python console after execution"
+msgstr "Futtatás utáni interaktív Python konzol"
+
+#: spyder/plugins/runconfig.py:215
+msgid "Show warning when killing running process"
+msgstr "Figyelmeztetni futó procesz leállításánál"
+
+#: spyder/plugins/runconfig.py:224
+msgid "-u is added to the other options you set here"
+msgstr "-u opcókhoz hozzáadva"
+
+#: spyder/plugins/runconfig.py:234
+#, fuzzy
+msgid "this dialog"
+msgstr "ez az ablak"
+
+#: spyder/plugins/runconfig.py:295
+#, fuzzy
+msgid "Run configuration"
+msgstr "Beállítómodul indítása"
+
+#: spyder/plugins/runconfig.py:296
+msgid "The following working directory is not valid:
%s"
+msgstr "Hely nem érvényes:
%s"
+
+#: spyder/plugins/runconfig.py:374
+#, fuzzy
+msgid "Run settings for %s"
+msgstr "%s futtatási beállításai"
+
+#: spyder/plugins/runconfig.py:406
+#, fuzzy
+msgid "Select a run configuration:"
+msgstr "Futtatás beállítás választás"
+
+#: spyder/plugins/runconfig.py:435 spyder/plugins/runconfig.py:460
+#, fuzzy
+msgid "Run Settings"
+msgstr "Futtatás beállítások"
+
+#: spyder/plugins/runconfig.py:462
+msgid "The following are the default %s. These options may be overriden using the %s dialog box (see the %s menu)"
+msgstr ""
+
+#: spyder/plugins/runconfig.py:488
+#, fuzzy
+msgid "Default working directory is:"
+msgstr "Alap munkahely"
+
+#: spyder/plugins/runconfig.py:490
+msgid "the script directory"
+msgstr "códfájl directory"
+
+#: spyder/plugins/runconfig.py:493 spyder/plugins/workingdirectory.py:57
+msgid "the following directory:"
+msgstr "bizonyos directory:"
+
+#: spyder/plugins/runconfig.py:522
+msgid "Show warning when killing running processes"
+msgstr "Figyelmeztetni futó procesz leállításánál"
+
+#: spyder/plugins/runconfig.py:531
+#, fuzzy
+msgid "Run Settings dialog"
+msgstr "Futtatás beállítások"
+
+#: spyder/plugins/shortcuts.py:137
+msgid "Press the new shortcut and select 'Ok': \n"
+"(Press 'Tab' once to switch focus between the shortcut entry \n"
+"and the buttons below it)"
+msgstr ""
+
+#: spyder/plugins/shortcuts.py:140
+#, fuzzy
+msgid "Current shortcut:"
+msgstr "Billentyűkombináció:"
+
+#: spyder/plugins/shortcuts.py:142
+#, fuzzy
+msgid "New shortcut:"
+msgstr "Új Billentyűkombináció"
+
+#: spyder/plugins/shortcuts.py:155
+#, fuzzy
+msgid "Shortcut: {0}"
+msgstr "Billentyűkombináció: "
+
+#: spyder/plugins/shortcuts.py:276
+msgid "Please introduce a different shortcut"
+msgstr "Adjon új Billentyűkombinációt"
+
+#: spyder/plugins/shortcuts.py:313
+#, fuzzy
+msgid "The new shorcut conflicts with:"
+msgstr "Billentyűkombináció Ütközik ezzel:"
+
+#: spyder/plugins/shortcuts.py:324
+msgid "A compound sequence can have {break} a maximum of 4 subsequences.{break}"
+msgstr ""
+
+#: spyder/plugins/shortcuts.py:329
+#, fuzzy
+msgid "Invalid key entered"
+msgstr "Érvénytelen billentyű."
+
+#: spyder/plugins/shortcuts.py:531
+msgid "Context"
+msgstr "Kontextus"
+
+#: spyder/plugins/shortcuts.py:533
+#: spyder/widgets/variableexplorer/collectionseditor.py:129
+#, fuzzy
+msgid "Name"
+msgstr "NÉV"
+
+#: spyder/plugins/shortcuts.py:535
+msgid "Shortcut"
+msgstr "Gyorsbillentyű"
+
+#: spyder/plugins/shortcuts.py:537
+msgid "Score"
+msgstr "Pontszám"
+
+#: spyder/plugins/shortcuts.py:697
+msgid "Conflicts"
+msgstr "ütközés"
+
+#: spyder/plugins/shortcuts.py:698
+#, fuzzy
+msgid "The following conflicts have been detected:"
+msgstr "Ütközetek:"
+
+#: spyder/plugins/shortcuts.py:783
+#, fuzzy
+msgid "Keyboard shortcuts"
+msgstr "Gyorsbillentyűk"
+
+#: spyder/plugins/shortcuts.py:791
+msgid "Search: "
+msgstr "Keresés: "
+
+#: spyder/plugins/shortcuts.py:792
+msgid "Reset to default values"
+msgstr "Visszaállítás az alapértelmezett értékekre"
+
+#: spyder/plugins/variableexplorer.py:24
+msgid "Autorefresh"
+msgstr "Autofrissétés"
+
+#: spyder/plugins/variableexplorer.py:25
+#, fuzzy
+msgid "Enable autorefresh"
+msgstr "Használni"
+
+#: spyder/plugins/variableexplorer.py:27
+#, fuzzy
+msgid "Refresh interval: "
+msgstr "Frissítés időköz:"
+
+#: spyder/plugins/variableexplorer.py:31
+#, fuzzy
+msgid "Filter"
+msgstr "Szűrés"
+
+#: spyder/plugins/variableexplorer.py:33
+#: spyder/widgets/variableexplorer/namespacebrowser.py:237
+#, fuzzy
+msgid "Exclude private references"
+msgstr "Privát referenciát kihagyni"
+
+#: spyder/plugins/variableexplorer.py:34
+#: spyder/widgets/variableexplorer/namespacebrowser.py:252
+#, fuzzy
+msgid "Exclude capitalized references"
+msgstr "Nagybtűs referenciát kihagyni"
+
+#: spyder/plugins/variableexplorer.py:35
+#: spyder/widgets/variableexplorer/namespacebrowser.py:245
+#, fuzzy
+msgid "Exclude all-uppercase references"
+msgstr "Mind-agybetűs szavak kihagyása"
+
+#: spyder/plugins/variableexplorer.py:36
+#: spyder/widgets/variableexplorer/namespacebrowser.py:260
+#, fuzzy
+msgid "Exclude unsupported data types"
+msgstr "Nem támogatott adat tipust kihagyni."
+
+#: spyder/plugins/variableexplorer.py:42
+#: spyder/widgets/variableexplorer/collectionseditor.py:702
+#, fuzzy
+msgid "Show arrays min/max"
+msgstr "tömbök maxi/mini-t mutatni"
+
+#: spyder/plugins/variableexplorer.py:204
+#, fuzzy
+msgid "Variable explorer"
+msgstr "Változó bongésző"
+
+#: spyder/plugins/workingdirectory.py:38
+msgid "The global working directory is the working directory for newly opened consoles (Python/IPython consoles and terminals), for the file explorer, for the find in files plugin and for new files created in the editor."
+msgstr ""
+
+#: spyder/plugins/workingdirectory.py:47
+#, fuzzy
+msgid "At startup, the global working directory is:"
+msgstr "A munkakönyvtár kezdéskor"
+
+#: spyder/plugins/workingdirectory.py:51
+#, fuzzy
+msgid "the same as in last session"
+msgstr "Mint utolsó munkamenet"
+
+#: spyder/plugins/workingdirectory.py:53
+msgid "At startup, Spyder will restore the global directory from last session"
+msgstr "Kezdéskor, Spder visszállít munkahelyet mint multkor"
+
+#: spyder/plugins/workingdirectory.py:59
+msgid "At startup, the global working directory will be the specified path"
+msgstr "Kezdéskor, Spder visszállít munkahelyet adott helyhez"
+
+#: spyder/plugins/workingdirectory.py:71
+#, fuzzy
+msgid "Files are opened from:"
+msgstr "A fájlok nyitása innen:"
+
+#: spyder/plugins/workingdirectory.py:75 spyder/plugins/workingdirectory.py:88
+#, fuzzy
+msgid "the current file directory"
+msgstr "A jelenlegi könyvtár "
+
+#: spyder/plugins/workingdirectory.py:79 spyder/plugins/workingdirectory.py:92
+#, fuzzy
+msgid "the global working directory"
+msgstr "Globális munkakönyvtár"
+
+#: spyder/plugins/workingdirectory.py:84
+#, fuzzy
+msgid "Files are created in:"
+msgstr "Fájl látrehozésa itt:"
+
+#: spyder/plugins/workingdirectory.py:98
+#, fuzzy
+msgid "Change to file base directory"
+msgstr "Fájlnév (relatív az alapkönyvtárhoz)"
+
+#: spyder/plugins/workingdirectory.py:100
+#, fuzzy
+msgid "When opening a file"
+msgstr "Fájl nyitáskor"
+
+#: spyder/plugins/workingdirectory.py:102
+#, fuzzy
+msgid "When saving a file"
+msgstr "Fájl mentésekor"
+
+#: spyder/plugins/workingdirectory.py:172
+msgid "Back"
+msgstr "Vissza"
+
+#: spyder/plugins/workingdirectory.py:180 spyder/widgets/explorer.py:1099
+#: spyder/widgets/variableexplorer/importwizard.py:529
+msgid "Next"
+msgstr "Következő"
+
+#: spyder/plugins/workingdirectory.py:191
+msgid "This is the working directory for newly\n"
+"opened consoles (Python/IPython consoles and\n"
+"terminals), for the file explorer, for the\n"
+"find in files plugin and for new files\n"
+"created in the editor"
+msgstr ""
+
+#: spyder/plugins/workingdirectory.py:219
+#, fuzzy
+msgid "Browse a working directory"
+msgstr "Munkakönyvtár kiválasztása"
+
+#: spyder/plugins/workingdirectory.py:226
+#, fuzzy
+msgid "Change to parent directory"
+msgstr "Szülő könyvtárra cserél"
+
+#: spyder/plugins/workingdirectory.py:233
+#, fuzzy
+msgid "Global working directory"
+msgstr "Globális munkakönyvtár"
+
+#: spyder/utils/codeanalysis.py:91
+msgid "Real-time code analysis on the Editor"
+msgstr "Élő kód vizsgálat a szerkesztőben"
+
+#: spyder/utils/codeanalysis.py:95
+msgid "Real-time code style analysis on the Editor"
+msgstr "Élő kód-stílus vizsgálat s szerkesztőben"
+
+#: spyder/utils/environ.py:101
+msgid "Module pywin32 was not found.
Please restart this Windows session (not the computer) for changes to take effect."
+msgstr "Modul pywin32 nem találva.
Kezdjen új Windows fázist."
+
+#: spyder/utils/environ.py:114
+msgid "If you accept changes, this will modify the current user environment variables directly in Windows registry. Use it with precautions, at your own risks.
Note that for changes to take effect, you will need to restart the parent process of this application (simply restart Spyder if you have executed it from a Windows shortcut, otherwise restart any application from which you may have executed it, like Python(x,y) Home for example)"
+msgstr ""
+
+#: spyder/utils/help/sphinxify.py:217 spyder/utils/help/sphinxify.py:227
+msgid "It was not possible to generate rich text help for this object.Please see it in plain text."
+msgstr "Gazdag szöveg nem sikerült ezzel a tárgyjal.Lássa sima szövegben."
+
+#: spyder/utils/introspection/manager.py:33
+#: spyder/utils/introspection/manager.py:38
+msgid "Editor's code completion, go-to-definition and help"
+msgstr "Szerkesztő kód kiegészítő, meghatározás és segítség"
+
+#: spyder/utils/iofuncs.py:408
+#, fuzzy
+msgid "Supported files"
+msgstr "Támogatott fájltípus"
+
+#: spyder/utils/iofuncs.py:410
+msgid "All files (*.*)"
+msgstr "Minden fájl (*.*)"
+
+#: spyder/utils/iofuncs.py:420
+#, fuzzy
+msgid "Spyder data files"
+msgstr "Üdv a Spyderben!"
+
+#: spyder/utils/iofuncs.py:422
+#: spyder/widgets/variableexplorer/collectionseditor.py:1057
+#, fuzzy
+msgid "NumPy arrays"
+msgstr "Numpy tömb"
+
+#: spyder/utils/iofuncs.py:423
+#, fuzzy
+msgid "NumPy zip arrays"
+msgstr "Numpy zip tömb"
+
+#: spyder/utils/iofuncs.py:424
+#, fuzzy
+msgid "Matlab files"
+msgstr "Matlab fájl"
+
+#: spyder/utils/iofuncs.py:425
+#, fuzzy
+msgid "CSV text files"
+msgstr "CSV fájl"
+
+#: spyder/utils/iofuncs.py:427
+#, fuzzy
+msgid "JPEG images"
+msgstr "JPEG-képek"
+
+#: spyder/utils/iofuncs.py:428
+#, fuzzy
+msgid "PNG images"
+msgstr "PNG-képek"
+
+#: spyder/utils/iofuncs.py:429
+#, fuzzy
+msgid "GIF images"
+msgstr "GIF-képek"
+
+#: spyder/utils/iofuncs.py:430
+#, fuzzy
+msgid "TIFF images"
+msgstr "TIFF-modul"
+
+#: spyder/utils/iofuncs.py:431 spyder/utils/iofuncs.py:432
+#, fuzzy
+msgid "Pickle files"
+msgstr "Pickle fájl"
+
+#: spyder/utils/iofuncs.py:433
+#, fuzzy
+msgid "JSON files"
+msgstr "JSON"
+
+#: spyder/utils/iofuncs.py:452 spyder/utils/iofuncs.py:459
+#, fuzzy
+msgid "Unsupported file type '%s'"
+msgstr "%s: ismeretlen/nem támogatott fájltípus.\n"
+
+#: spyder/utils/programs.py:286
+msgid "It was not possible to run this file in an external terminal"
+msgstr "Futtatás külső ablakban nem sikerült"
+
+#: spyder/utils/syntaxhighlighters.py:33
+msgid "Syntax highlighting for Matlab, Julia and other file types"
+msgstr "Matlab, Julia és más fájl kiemelés"
+
+#: spyder/utils/syntaxhighlighters.py:42
+msgid "Background:"
+msgstr "Háttér:"
+
+#: spyder/utils/syntaxhighlighters.py:43
+#: spyder/widgets/sourcecode/codeeditor.py:105
+msgid "Current line:"
+msgstr "Az aktuális sor:"
+
+#: spyder/utils/syntaxhighlighters.py:44
+#, fuzzy
+msgid "Current cell:"
+msgstr "Aktuális cella:"
+
+#: spyder/utils/syntaxhighlighters.py:45
+#, fuzzy
+msgid "Occurrence:"
+msgstr "előfordulás"
+
+#: spyder/utils/syntaxhighlighters.py:46
+#, fuzzy
+msgid "Link:"
+msgstr "Link"
+
+#: spyder/utils/syntaxhighlighters.py:47
+#, fuzzy
+msgid "Side areas:"
+msgstr "Oldalhely:"
+
+#: spyder/utils/syntaxhighlighters.py:48
+#, fuzzy
+msgid "Matched
parens:"
+msgstr "Zárójel pár:"
+
+#: spyder/utils/syntaxhighlighters.py:49
+#, fuzzy
+msgid "Unmatched
parens:"
+msgstr "Páratlan zárójel:"
+
+#: spyder/utils/syntaxhighlighters.py:50
+msgid "Normal text:"
+msgstr "Normál szöveg:"
+
+#: spyder/utils/syntaxhighlighters.py:51
+#, fuzzy
+msgid "Keyword:"
+msgstr "Kulcsszó"
+
+#: spyder/utils/syntaxhighlighters.py:52
+#, fuzzy
+msgid "Builtin:"
+msgstr "Beépített"
+
+#: spyder/utils/syntaxhighlighters.py:53
+#, fuzzy
+msgid "Definition:"
+msgstr "Definíció"
+
+#: spyder/utils/syntaxhighlighters.py:54
+msgid "Comment:"
+msgstr "Megjegyzés:"
+
+#: spyder/utils/syntaxhighlighters.py:55
+msgid "String:"
+msgstr "Minta:"
+
+#: spyder/utils/syntaxhighlighters.py:56
+msgid "Number:"
+msgstr "Szám:"
+
+#: spyder/utils/syntaxhighlighters.py:57
+#, fuzzy
+msgid "Instance:"
+msgstr "Példány"
+
+#: spyder/widgets/arraybuilder.py:179
+msgid "\n"
+" Numpy Array/Matrix Helper
\n"
+" Type an array in Matlab : [1 2;3 4]
\n"
+" or Spyder simplified syntax : 1 2;3 4
\n"
+"
\n"
+" Hit 'Enter' for array or 'Ctrl+Enter' for matrix.\n"
+"
\n"
+" Hint:
\n"
+" Use two spaces or two tabs to generate a ';'.\n"
+" "
+msgstr ""
+
+#: spyder/widgets/arraybuilder.py:190
+msgid "\n"
+" Numpy Array/Matrix Helper
\n"
+" Enter an array in the table.
\n"
+" Use Tab to move between cells.\n"
+"
\n"
+" Hit 'Enter' for array or 'Ctrl+Enter' for matrix.\n"
+"
\n"
+" Hint:
\n"
+" Use two tabs at the end of a row to move to the next row.\n"
+" "
+msgstr ""
+
+#: spyder/widgets/arraybuilder.py:365
+#, fuzzy
+msgid "Array dimensions not valid"
+msgstr "Tömb dimensió nem érvényes"
+
+#: spyder/widgets/browser.py:54 spyder/widgets/sourcecode/codeeditor.py:2619
+msgid "Zoom out"
+msgstr "Kicsinyítés"
+
+#: spyder/widgets/browser.py:57 spyder/widgets/sourcecode/codeeditor.py:2615
+msgid "Zoom in"
+msgstr "Nagyítás"
+
+#: spyder/widgets/browser.py:177
+msgid "Home"
+msgstr "Otthoni"
+
+#: spyder/widgets/browser.py:213
+#, fuzzy
+msgid "Find text"
+msgstr "Keres megint"
+
+#: spyder/widgets/browser.py:231
+msgid "Address:"
+msgstr "Cím:"
+
+#: spyder/widgets/browser.py:267
+#, fuzzy
+msgid "Unable to load page"
+msgstr "A lap betöltése nem sikerült"
+
+#: spyder/widgets/comboboxes.py:162
+#, fuzzy
+msgid "Press enter to validate this entry"
+msgstr "ENTER-el érvényesít"
+
+#: spyder/widgets/comboboxes.py:163
+#, fuzzy
+msgid "This entry is incorrect"
+msgstr "Megjezés rossz"
+
+#: spyder/widgets/comboboxes.py:206
+#, fuzzy
+msgid "Press enter to validate this path"
+msgstr "ENTER-el helyszínet érvényesít"
+
+#: spyder/widgets/dependencies.py:63
+#, fuzzy
+msgid " Required "
+msgstr " Kell "
+
+#: spyder/widgets/dependencies.py:63
+msgid "Module"
+msgstr "Modul"
+
+#: spyder/widgets/dependencies.py:64
+#, fuzzy
+msgid " Installed "
+msgstr "(nem telepített)"
+
+#: spyder/widgets/dependencies.py:64
+#, fuzzy
+msgid "Provided features"
+msgstr "Ez biztosítja:"
+
+#: spyder/widgets/dependencies.py:134
+msgid "Dependencies"
+msgstr "Függőségek"
+
+#: spyder/widgets/dependencies.py:141
+msgid "Spyder depends on several Python modules to provide the right functionality for all its panes. The table below shows the required and installed versions (if any) of all of them.
Note: You can safely use Spyder without the following modules installed: %s and %s.
Please also note that new dependencies or changed ones will be correctly detected only after Spyder is restarted."
+msgstr ""
+
+#: spyder/widgets/dependencies.py:157
+msgid "Copy to clipboard"
+msgstr "Másolás a vágólapra"
+
+#: spyder/widgets/editor.py:350
+#, fuzzy
+msgid "Find symbols in file..."
+msgstr "Szimbólumkeresés"
+
+#: spyder/widgets/editor.py:353
+#, fuzzy
+msgid "Copy path to clipboard"
+msgstr "Másolás a vágólapra..."
+
+#: spyder/widgets/editor.py:357
+#, fuzzy
+msgid "Close all to the right"
+msgstr "Bezárás mindent jobbra"
+
+#: spyder/widgets/editor.py:359
+#, fuzzy
+msgid "Close all but this"
+msgstr "Összes többi bezárása"
+
+#: spyder/widgets/editor.py:997
+#, fuzzy
+msgid "Temporary file"
+msgstr "Ideiglenes fájl"
+
+#: spyder/widgets/editor.py:1093
+#, fuzzy
+msgid "New window"
+msgstr "Új ablak"
+
+#: spyder/widgets/editor.py:1094
+#, fuzzy
+msgid "Create a new editor window"
+msgstr "Új szerkesztő ablak létrehozása"
+
+#: spyder/widgets/editor.py:1097
+#, fuzzy
+msgid "Split vertically"
+msgstr "Függőlevesen ketté"
+
+#: spyder/widgets/editor.py:1099
+msgid "Split vertically this editor window"
+msgstr "Függőlegesen ketté vágni ezt a szerkesztú ablakot"
+
+#: spyder/widgets/editor.py:1101
+#, fuzzy
+msgid "Split horizontally"
+msgstr "Viszintesen ketté"
+
+#: spyder/widgets/editor.py:1103
+msgid "Split horizontally this editor window"
+msgstr "Vizszintesen ketté vágni ezt a szerkesztú ablakot"
+
+#: spyder/widgets/editor.py:1105
+#, fuzzy
+msgid "Close this panel"
+msgstr "Lap bezárása"
+
+#: spyder/widgets/editor.py:1278
+msgid "%s has been modified.
Do you want to save changes?"
+msgstr "%s változott.
Menteni?"
+
+#: spyder/widgets/editor.py:1340
+msgid "Save"
+msgstr "Mentés"
+
+#: spyder/widgets/editor.py:1341
+msgid "Unable to save script '%s'
Error message:
%s"
+msgstr "Mentés hiba '%s'
Üzenet:
%s"
+
+#: spyder/widgets/editor.py:1582
+msgid "%s is unavailable (this file may have been removed, moved or renamed outside Spyder).
Do you want to close it?"
+msgstr "%s nem találva.
Bezárni?"
+
+#: spyder/widgets/editor.py:1602
+msgid "%s has been modified outside Spyder.
Do you want to reload it and lose all your changes?"
+msgstr "%s változott Spyderen kívül.
Újrabetölteni és szerkesztést veszíteni? "
+
+#: spyder/widgets/editor.py:1707
+msgid "All changes to %s will be lost.
Do you want to revert file from disk?"
+msgstr ""
+
+#: spyder/widgets/editor.py:1848
+#, fuzzy
+msgid "Loading %s..."
+msgstr "Töltés %s..."
+
+#: spyder/widgets/editor.py:1858
+msgid "%s contains mixed end-of-line characters.
Spyder will fix this automatically."
+msgstr "%s kevert vonalvég betüket tartalmaz.
Spyder ezt magjavítja."
+
+#: spyder/widgets/editor.py:2240
+#, fuzzy
+msgid "Close window"
+msgstr "Ablak bezárása"
+
+#: spyder/widgets/editor.py:2242
+#, fuzzy
+msgid "Close this window"
+msgstr "Ez az Ablak bezárása"
+
+#: spyder/widgets/editortools.py:94 spyder/widgets/editortools.py:130
+#, fuzzy
+msgid "Line %s"
+msgstr "Sor %s"
+
+#: spyder/widgets/editortools.py:99
+#, fuzzy
+msgid "Class defined at line %s"
+msgstr "Osztály meghatározás sor %s"
+
+#: spyder/widgets/editortools.py:107
+msgid "Method defined at line %s"
+msgstr "Eszköz %s vonalon meghatározva"
+
+#: spyder/widgets/editortools.py:117
+#, fuzzy
+msgid "Function defined at line %s"
+msgstr "Funció meghatározás sor %s”"
+
+#: spyder/widgets/editortools.py:149
+#, fuzzy
+msgid "Cell starts at line %s"
+msgstr "Cella kezdetsor %s"
+
+#: spyder/widgets/editortools.py:202 spyder/widgets/editortools.py:539
+#, fuzzy
+msgid "Go to cursor position"
+msgstr "Kurzorhelyhez"
+
+#: spyder/widgets/editortools.py:205
+#, fuzzy
+msgid "Show absolute path"
+msgstr "abzolút helyet mutatni"
+
+#: spyder/widgets/editortools.py:208 spyder/widgets/explorer.py:210
+#, fuzzy
+msgid "Show all files"
+msgstr "Összes fájl megjelenítése"
+
+#: spyder/widgets/editortools.py:211
+#, fuzzy
+msgid "Show special comments"
+msgstr "Megjegyzések mutatása"
+
+#: spyder/widgets/explorer.py:206
+#, fuzzy
+msgid "Edit filename filters..."
+msgstr "A szűrők szerkesztése..."
+
+#: spyder/widgets/explorer.py:220
+#, fuzzy
+msgid "Edit filename filters"
+msgstr "A szűrők szerkesztése..."
+
+#: spyder/widgets/explorer.py:221
+#, fuzzy
+msgid "Name filters:"
+msgstr "Szűrők:"
+
+#: spyder/widgets/explorer.py:240
+msgid "File..."
+msgstr " Fájl..."
+
+#: spyder/widgets/explorer.py:244
+msgid "Module..."
+msgstr "Modul..."
+
+#: spyder/widgets/explorer.py:248
+msgid "Folder..."
+msgstr "Könyvtár..."
+
+#: spyder/widgets/explorer.py:252
+msgid "Package..."
+msgstr "Csomag..."
+
+#: spyder/widgets/explorer.py:273
+#: spyder/widgets/variableexplorer/collectionseditor.py:677
+msgid "Edit"
+msgstr "Szerkesztés"
+
+#: spyder/widgets/explorer.py:275
+msgid "Move..."
+msgstr "Mozgatás..."
+
+#: spyder/widgets/explorer.py:278
+msgid "Delete..."
+msgstr "Törlés..."
+
+#: spyder/widgets/explorer.py:281
+msgid "Rename..."
+msgstr "Átnevezés..."
+
+#: spyder/widgets/explorer.py:284
+msgid "Open"
+msgstr "Megnyitás"
+
+#: spyder/widgets/explorer.py:285 spyder/widgets/sourcecode/codeeditor.py:2591
+#, fuzzy
+msgid "Convert to Python script"
+msgstr "Egy Python script futtatása"
+
+#: spyder/widgets/explorer.py:319
+msgid "Commit"
+msgstr "Eltárolás"
+
+#: spyder/widgets/explorer.py:322
+#, fuzzy
+msgid "Browse repository"
+msgstr "Böngészés"
+
+#: spyder/widgets/explorer.py:333
+#, fuzzy
+msgid "Open command prompt here"
+msgstr "Parancssor nyitás innen"
+
+#: spyder/widgets/explorer.py:335
+#, fuzzy
+msgid "Open terminal here"
+msgstr "Terminál indítás innen"
+
+#: spyder/widgets/explorer.py:340
+#, fuzzy
+msgid "Open Python console here"
+msgstr "Python-konzol innen"
+
+#: spyder/widgets/explorer.py:354
+#, fuzzy
+msgid "New"
+msgstr "Új"
+
+#: spyder/widgets/explorer.py:362
+msgid "Import"
+msgstr "Importálás"
+
+#: spyder/widgets/explorer.py:513
+#, fuzzy
+msgid "Do you really want to delete %s?"
+msgstr "Biztosan törölni: %s?"
+
+#: spyder/widgets/explorer.py:531
+#, fuzzy
+msgid "delete"
+msgstr "törlés"
+
+#: spyder/widgets/explorer.py:532 spyder/widgets/projects/explorer.py:148
+#: spyder/widgets/projects/explorer.py:255
+#, fuzzy
+msgid "Project Explorer"
+msgstr "Projekt Vizsgáló"
+
+#: spyder/widgets/explorer.py:533 spyder/widgets/projects/explorer.py:149
+msgid "Unable to %s %s
Error message:
%s"
+msgstr "\" %s nem sikerült %s
Error üzenet:
%s"
+
+#: spyder/widgets/explorer.py:548
+#, fuzzy
+msgid "File Explorer"
+msgstr "fájlböngésző"
+
+#: spyder/widgets/explorer.py:549
+msgid "The current directory contains a project.
If you want to delete the project, please go to Projects » Delete Project"
+msgstr ""
+
+#: spyder/widgets/explorer.py:566 spyder/widgets/sourcecode/codeeditor.py:2078
+#, fuzzy
+msgid "Conversion error"
+msgstr "Hiba az átalakítás során"
+
+#: spyder/widgets/explorer.py:567 spyder/widgets/sourcecode/codeeditor.py:2079
+msgid "It was not possible to convert this notebook. The error is:\n"
+"\n"
+msgstr "Jegyzetkönyv átalakítása nem sikerült. Error:\n"
+"\n"
+
+#: spyder/widgets/explorer.py:584 spyder/widgets/explorer.py:592
+#: spyder/widgets/explorer.py:603
+#: spyder/widgets/variableexplorer/collectionseditor.py:706
+#: spyder/widgets/variableexplorer/collectionseditor.py:952
+msgid "Rename"
+msgstr "Átnevezés"
+
+#: spyder/widgets/explorer.py:585
+msgid "New name:"
+msgstr "Név:"
+
+#: spyder/widgets/explorer.py:593
+msgid "Do you really want to rename %s and overwrite the existing file %s?"
+msgstr "Fájlt újranevezni %s és létező fájt átírni %s?"
+
+#: spyder/widgets/explorer.py:604
+msgid "Unable to rename file %s
Error message:
%s"
+msgstr "Fájl nevesése nem sikerült %s
Hiba:
%s"
+
+#: spyder/widgets/explorer.py:640
+msgid "Unable to move %s
Error message:
%s"
+msgstr "Nem sikerült mozdítani %s
Hiba jelentés:
%s"
+
+#: spyder/widgets/explorer.py:658
+msgid "Unable to create folder %s
Error message:
%s"
+msgstr "Nem sikerült directory teremptés %s
Hiba jelentés:
%s"
+
+#: spyder/widgets/explorer.py:671 spyder/widgets/explorer.py:705
+msgid "Unable to create file %s
Error message:
%s"
+msgstr "Nem fájl teremptés %s
Hiba jelentés:
%s"
+
+#: spyder/widgets/explorer.py:679
+#, fuzzy
+msgid "New folder"
+msgstr "Új könyvtár"
+
+#: spyder/widgets/explorer.py:680
+msgid "Folder name:"
+msgstr "Könyvtárnév:"
+
+#: spyder/widgets/explorer.py:685
+#, fuzzy
+msgid "New package"
+msgstr "újcsomag"
+
+#: spyder/widgets/explorer.py:686
+msgid "Package name:"
+msgstr "Csomagnév:"
+
+#: spyder/widgets/explorer.py:726
+msgid "New module"
+msgstr "Új modul"
+
+#: spyder/widgets/explorer.py:741
+msgid "For %s support, please install one of the
following tools:
%s"
+msgstr "%s használatához kérjük telepítsen
egyiket:
%s"
+
+#: spyder/widgets/explorer.py:745
+msgid "Unable to find external program.
%s"
+msgstr "Nem sikerült külső programot megtalálni.
%s"
+
+#: spyder/widgets/explorer.py:966
+#, fuzzy
+msgid "Show current directory only"
+msgstr "Csak az aktuális munkaterület megjelenítése"
+
+#: spyder/widgets/explorer.py:1066
+msgid "You don't have the right permissions to open this directory"
+msgstr "Directory nyitás engedély hiba"
+
+#: spyder/widgets/explorer.py:1096
+#: spyder/widgets/variableexplorer/importwizard.py:525
+msgid "Previous"
+msgstr "Előző"
+
+#: spyder/widgets/explorer.py:1102
+msgid "Parent"
+msgstr "Parent"
+
+#: spyder/widgets/externalshell/baseshell.py:129
+#, fuzzy
+msgid "Run again this program"
+msgstr "Futtatás: Végrehajt egy programot"
+
+#: spyder/widgets/externalshell/baseshell.py:132
+msgid "Kill"
+msgstr "Kilövés"
+
+#: spyder/widgets/externalshell/baseshell.py:134
+msgid "Kills the current process, causing it to exit immediately"
+msgstr "Procesz megölése - azonnal lezár"
+
+#: spyder/widgets/externalshell/baseshell.py:206
+msgid "Running..."
+msgstr "Futtat…"
+
+#: spyder/widgets/externalshell/baseshell.py:213
+#, fuzzy
+msgid "Terminated."
+msgstr "Félbeszakítva"
+
+#: spyder/widgets/externalshell/baseshell.py:238
+#: spyder/widgets/ipythonconsole/help.py:125 spyder/widgets/mixins.py:679
+msgid "Arguments"
+msgstr "Argumentumok"
+
+#: spyder/widgets/externalshell/baseshell.py:239
+#, fuzzy
+msgid "Command line arguments:"
+msgstr "Parancssori argumentumok"
+
+#: spyder/widgets/externalshell/pythonshell.py:277
+msgid "Variables"
+msgstr "Változók"
+
+#: spyder/widgets/externalshell/pythonshell.py:278
+msgid "Show/hide global variables explorer"
+msgstr "Mutatni a globális valtozó bongészőt"
+
+#: spyder/widgets/externalshell/pythonshell.py:282
+msgid "Terminate"
+msgstr "Végezni"
+
+#: spyder/widgets/externalshell/pythonshell.py:283
+msgid "Attempts to stop the process. The process\n"
+"may not exit as a result of clicking this\n"
+"button (it is given the chance to prompt\n"
+"the user for any unsaved files, etc)."
+msgstr "Procesz magállítast proóbál. Ha\n"
+"például kérdezne valamit, lehet hogy\n"
+"kattintás nem zárja le a proceszt"
+
+#: spyder/widgets/externalshell/pythonshell.py:296
+#, fuzzy
+msgid "Interact"
+msgstr "A dokumentum űrlapot is tartalmaz. A gombra kattintva (vagy a Nézet -> Űrlapok menüponttal) lehet kezelni őket."
+
+#: spyder/widgets/externalshell/pythonshell.py:298
+msgid "Debug"
+msgstr "Hibakeresés"
+
+#: spyder/widgets/externalshell/pythonshell.py:300
+#: spyder/widgets/externalshell/pythonshell.py:366
+#, fuzzy
+msgid "Arguments..."
+msgstr "Opciók"
+
+#: spyder/widgets/externalshell/pythonshell.py:302
+#, fuzzy
+msgid "Post Mortem Debug"
+msgstr "&Debug"
+
+#: spyder/widgets/externalshell/pythonshell.py:308
+#, fuzzy
+msgid "Working directory"
+msgstr "A munkakönyvtár nem jegyezhető fel"
+
+#: spyder/widgets/externalshell/pythonshell.py:310
+#, fuzzy
+msgid "Set current working directory"
+msgstr "nem érhető el a jelenlegi munkakönyvtár"
+
+#: spyder/widgets/externalshell/pythonshell.py:312
+#, fuzzy
+msgid "Environment variables"
+msgstr "Környezeti változók"
+
+#: spyder/widgets/externalshell/pythonshell.py:316
+#, fuzzy
+msgid "Show sys.path contents"
+msgstr "A tartalom megje&lenítése"
+
+#: spyder/widgets/externalshell/pythonshell.py:362
+#, fuzzy
+msgid "Arguments: %s"
+msgstr "Hiba az argumentumok feldolgozása során: %s\n"
+
+#: spyder/widgets/externalshell/pythonshell.py:364
+#, fuzzy
+msgid "No argument"
+msgstr "Argument"
+
+#: spyder/widgets/externalshell/pythonshell.py:534
+#, fuzzy
+msgid "A Python console failed to start!"
+msgstr "Python-konzol"
+
+#: spyder/widgets/externalshell/systemshell.py:106
+#, fuzzy
+msgid "Process failed to start"
+msgstr "A disztribúciós frissítési folyamat indítása sikertelen."
+
+#: spyder/widgets/fileswitcher.py:109
+#, fuzzy
+msgid "unsaved file"
+msgstr "Nem mentett fájl"
+
+#: spyder/widgets/fileswitcher.py:230
+msgid "Press Enter to switch files or Esc to cancel.
Type to filter filenames.
Use :number to go to a line, e.g. main:42
Use @symbol_text to go to a symbol, e.g. @init
Press Ctrl+W to close current tab.
"
+msgstr ""
+
+#: spyder/widgets/fileswitcher.py:512
+#, fuzzy
+msgid "lines"
+msgstr "Vonalak"
+
+#: spyder/widgets/findinfiles.py:158
+#, fuzzy
+msgid "Unexpected error: see internal console"
+msgstr "Internal error: Caught unexpected exception"
+
+#: spyder/widgets/findinfiles.py:209 spyder/widgets/findinfiles.py:233
+#: spyder/widgets/findinfiles.py:280
+#, fuzzy
+msgid "invalid regular expression"
+msgstr "Érvénytelen reguláris kifejezés"
+
+#: spyder/widgets/findinfiles.py:278
+msgid "permission denied errors were encountered"
+msgstr "Egedély letagadási hiba"
+
+#: spyder/widgets/findinfiles.py:315
+#, fuzzy
+msgid "Search pattern"
+msgstr "Lépésenkénti keresésAz itt megadott szöveget keresve választja ki a program azt a névjegyet, mely leginkább megfelel a keresési feltételnek. A kijelölt mező alapján határozza meg a program, hogy mely adatokban végzi a keresést.
"
+
+#: spyder/widgets/findinfiles.py:318 spyder/widgets/findinfiles.py:352
+#: spyder/widgets/findinfiles.py:364 spyder/widgets/findreplace.py:81
+msgid "Regular expression"
+msgstr "reguláris kifejezés"
+
+#: spyder/widgets/findinfiles.py:327
+msgid "Search"
+msgstr "Search"
+
+#: spyder/widgets/findinfiles.py:330
+#, fuzzy
+msgid "Start search"
+msgstr "&Indítás"
+
+#: spyder/widgets/findinfiles.py:336
+#, fuzzy
+msgid "Stop search"
+msgstr "Keresés &leállítása"
+
+#: spyder/widgets/findinfiles.py:346
+#, fuzzy
+msgid "Included filenames pattern"
+msgstr "Fájlnevek"
+
+#: spyder/widgets/findinfiles.py:355
+#, fuzzy
+msgid "Include:"
+msgstr "Beleértve"
+
+#: spyder/widgets/findinfiles.py:358
+#, fuzzy
+msgid "Excluded filenames pattern"
+msgstr "Fájlnevek"
+
+#: spyder/widgets/findinfiles.py:367
+#, fuzzy
+msgid "Exclude:"
+msgstr "Kihagyás"
+
+#: spyder/widgets/findinfiles.py:377
+#, fuzzy
+msgid "PYTHONPATH"
+msgstr "PYTHONPATH manager"
+
+#: spyder/widgets/findinfiles.py:379
+msgid "Search in all directories listed in sys.path which are outside the Python installation directory"
+msgstr "Minder directory-ban keresni ami sys.path-ban van és python berendezésen kívűl"
+
+#: spyder/widgets/findinfiles.py:382
+#, fuzzy
+msgid "Hg repository"
+msgstr "\" Hg"
+
+#: spyder/widgets/findinfiles.py:385
+msgid "Search in current directory hg repository"
+msgstr "hg repository aktuális directory keresés"
+
+#: spyder/widgets/findinfiles.py:386
+#, fuzzy
+msgid "Here:"
+msgstr "Ikon ide"
+
+#: spyder/widgets/findinfiles.py:390
+#, fuzzy
+msgid "Search recursively in this directory"
+msgstr "A könyvtár nem másolható rekurzívan"
+
+#: spyder/widgets/findinfiles.py:395
+#, fuzzy
+msgid "Browse a search directory"
+msgstr "Kezdőkönyvtár kiválasztása"
+
+#: spyder/widgets/findinfiles.py:425
+#, fuzzy
+msgid "Hide advanced options"
+msgstr "A speciális opciók elrejtése"
+
+#: spyder/widgets/findinfiles.py:428
+#, fuzzy
+msgid "Show advanced options"
+msgstr "A speciális opciók megjelenítése"
+
+#: spyder/widgets/findinfiles.py:569
+msgid "Search canceled"
+msgstr "A keresés félbeszakadt"
+
+#: spyder/widgets/findinfiles.py:573
+#, fuzzy
+msgid "String not found"
+msgstr "A keresett szöveg nem található."
+
+#: spyder/widgets/findinfiles.py:575
+#, fuzzy
+msgid "matches in"
+msgstr "Nincs találat"
+
+#: spyder/widgets/findinfiles.py:576
+#, fuzzy
+msgid "file"
+msgstr "Fájlalapú"
+
+#: spyder/widgets/findinfiles.py:584
+#, fuzzy
+msgid "interrupted"
+msgstr "Megszakítva"
+
+#: spyder/widgets/findreplace.py:63
+#, fuzzy
+msgid "Search string"
+msgstr " Keresendő minta:"
+
+#: spyder/widgets/findreplace.py:87
+msgid "Case Sensitive"
+msgstr "Nagybetűérzékeny"
+
+#: spyder/widgets/findreplace.py:93
+msgid "Whole words"
+msgstr "Egész szavak"
+
+#: spyder/widgets/findreplace.py:99
+#, fuzzy
+msgid "Highlight matches"
+msgstr "Kiemelés"
+
+#: spyder/widgets/findreplace.py:113
+msgid "Replace with:"
+msgstr "Csere ezzel:"
+
+#: spyder/widgets/findreplace.py:115
+#, fuzzy
+msgid "Replace string"
+msgstr "Parancsok &engedélyezése a cseresztringben: [$parancs:opció$]"
+
+#: spyder/widgets/findreplace.py:118
+#, fuzzy
+msgid "Replace/find"
+msgstr "Keresés és csere"
+
+#: spyder/widgets/findreplace.py:125
+#, fuzzy
+msgid "Replace all"
+msgstr "Mindet cseréli"
+
+#: spyder/widgets/internalshell.py:262
+#, fuzzy
+msgid "Help..."
+msgstr "a segítség alapján"
+
+#: spyder/widgets/internalshell.py:279
+#, fuzzy
+msgid "Shell special commands:"
+msgstr "A parancs nem használható parancsértelmező-felületekkel"
+
+#: spyder/widgets/internalshell.py:280
+#, fuzzy
+msgid "Internal editor:"
+msgstr "A belső szerkesztő nem található"
+
+#: spyder/widgets/internalshell.py:281
+#, fuzzy
+msgid "External editor:"
+msgstr "Külső szövegszerkesztő"
+
+#: spyder/widgets/internalshell.py:282
+#, fuzzy
+msgid "Run script:"
+msgstr "Szkript futtatása..."
+
+#: spyder/widgets/internalshell.py:283
+#, fuzzy
+msgid "Remove references:"
+msgstr "Hivatkozások itt: "
+
+#: spyder/widgets/internalshell.py:284
+#, fuzzy
+msgid "System commands:"
+msgstr "A shell parancs segítségével rendszerparancsos futtathatók."
+
+#: spyder/widgets/internalshell.py:285
+#, fuzzy
+msgid "Python help:"
+msgstr "Python"
+
+#: spyder/widgets/internalshell.py:286
+#, fuzzy
+msgid "GUI-based editor:"
+msgstr "Irrlicht grafikus eszköz"
+
+#: spyder/widgets/ipythonconsole/client.py:208
+#, fuzzy
+msgid "An error ocurred while starting the kernel"
+msgstr "Egy hiba történt miközben az appimaged-t próbáltam indítani!"
+
+#: spyder/widgets/ipythonconsole/client.py:250
+#, fuzzy
+msgid "Stop the current command"
+msgstr "Jelenlegi aktivitás leállítása"
+
+#: spyder/widgets/ipythonconsole/client.py:273
+#, fuzzy
+msgid "Inspect current object"
+msgstr "Figyelés..."
+
+#: spyder/widgets/ipythonconsole/client.py:278
+#, fuzzy
+msgid "Clear line or block"
+msgstr "_Tiltás…"
+
+#: spyder/widgets/ipythonconsole/client.py:282
+#, fuzzy
+msgid "Reset namespace"
+msgstr "Névtér"
+
+#: spyder/widgets/ipythonconsole/client.py:285
+#, fuzzy
+msgid "Clear console"
+msgstr "A hibakonzol törlése"
+
+#: spyder/widgets/ipythonconsole/client.py:326
+#, fuzzy
+msgid "Are you sure you want to restart the kernel?"
+msgstr "Adja meg a rendszerindításkor betöltendő kernel nevét elérési úttal együtt."
+
+#: spyder/widgets/ipythonconsole/client.py:328
+#, fuzzy
+msgid "Restart kernel?"
+msgstr "Kernel újraindítása"
+
+#: spyder/widgets/ipythonconsole/client.py:340
+#, fuzzy
+msgid "Error restarting kernel: %s\n"
+msgstr "Hiba az NFS-kiszolgáló újraindítása/újratöltése közben"
+
+#: spyder/widgets/ipythonconsole/client.py:345
+msgid "
Restarting kernel...\n"
+"
"
+msgstr "
Mag újraindít…\n"
+"
"
+
+#: spyder/widgets/ipythonconsole/client.py:350
+msgid "Cannot restart a kernel not started by Spyder\n"
+msgstr "Spyder nem újraindít magot amit nem teremptett\n"
+
+#: spyder/widgets/ipythonconsole/client.py:402
+msgid "Changing backend to Qt for Mayavi"
+msgstr "Mayavi hátsórészét Qt-re"
+
+#: spyder/widgets/ipythonconsole/client.py:413
+#, fuzzy
+msgid "Connecting to kernel..."
+msgstr "Rendszermag"
+
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:76
+msgid "Inspecting and setting values while debugging in IPython consoles is not supported yet by Spyder."
+msgstr "ipython debug közben nem lehet értéket viszgánli vagy határozni"
+
+#: spyder/widgets/ipythonconsole/shell.py:144
+#, fuzzy
+msgid "Reset IPython namespace"
+msgstr "Névtér"
+
+#: spyder/widgets/ipythonconsole/shell.py:145
+msgid "All user-defined variables will be removed.
Are you sure you want to reset the namespace?"
+msgstr "Minden használói vátlozók törölné.
Tovább?"
+
+#: spyder/widgets/ipythonconsole/shell.py:285
+#, fuzzy
+msgid "Kernel died, restarting"
+msgstr "Újraindítás"
+
+#: spyder/widgets/ipythonconsole/shell.py:285
+#, fuzzy
+msgid "Kernel restarting"
+msgstr "Újraindítás"
+
+#: spyder/widgets/onecolumntree.py:52
+#, fuzzy
+msgid "Collapse all"
+msgstr "Teljes összecsukás"
+
+#: spyder/widgets/onecolumntree.py:56
+#, fuzzy
+msgid "Expand all"
+msgstr "Teljes kibontás"
+
+#: spyder/widgets/onecolumntree.py:60
+msgid "Restore"
+msgstr "Visszaállítás"
+
+#: spyder/widgets/onecolumntree.py:61
+#, fuzzy
+msgid "Restore original tree layout"
+msgstr "Visszaállítás az eredeti helyre"
+
+#: spyder/widgets/onecolumntree.py:65
+#, fuzzy
+msgid "Collapse selection"
+msgstr "Összecsukás"
+
+#: spyder/widgets/onecolumntree.py:69
+#, fuzzy
+msgid "Expand selection"
+msgstr "&Expand the selection"
+
+#: spyder/widgets/pathmanager.py:87
+msgid "Move to top"
+msgstr "Mozgatás legfelülre"
+
+#: spyder/widgets/pathmanager.py:93
+msgid "Move up"
+msgstr "Mozgatás fel"
+
+#: spyder/widgets/pathmanager.py:99
+msgid "Move down"
+msgstr "Mozgatás le"
+
+#: spyder/widgets/pathmanager.py:105
+msgid "Move to bottom"
+msgstr "Mozgatás legalulra"
+
+#: spyder/widgets/pathmanager.py:116 spyder/widgets/pathmanager.py:231
+#, fuzzy
+msgid "Add path"
+msgstr "Útvonal hozzáadása"
+
+#: spyder/widgets/pathmanager.py:121 spyder/widgets/pathmanager.py:214
+#, fuzzy
+msgid "Remove path"
+msgstr "Útvonal eltávolítása"
+
+#: spyder/widgets/pathmanager.py:131
+#, fuzzy
+msgid "Synchronize..."
+msgstr "Szinkronizálás"
+
+#: spyder/widgets/pathmanager.py:133
+msgid "Synchronize Spyder's path list with PYTHONPATH environment variable"
+msgstr "Összehangolni Spyder directory pálya és PYTHONPATH"
+
+#: spyder/widgets/pathmanager.py:145
+msgid "Synchronize"
+msgstr "Szinkronizálás"
+
+#: spyder/widgets/pathmanager.py:146
+msgid "This will synchronize Spyder's path list with PYTHONPATH environment variable for current user, allowing you to run your Python modules outside Spyder without having to configure sys.path.
Do you want to clear contents of PYTHONPATH before adding Spyder's path list?"
+msgstr ""
+
+#: spyder/widgets/pathmanager.py:215
+#, fuzzy
+msgid "Do you really want to remove selected path?"
+msgstr "Biztosan törölni szeretné a kijelölt %1 címet?"
+
+#: spyder/widgets/pathmanager.py:232
+msgid "This directory is already included in Spyder path list.
Do you want to move it to the top of the list?"
+msgstr "Ez a mappa más been a Spyder listájában.
Mozduljon a lista tetejéhez?"
+
+#: spyder/widgets/projects/configdialog.py:30
+#, fuzzy
+msgid "Project preferences"
+msgstr "Mint a _beállításokban"
+
+#: spyder/widgets/projects/configdialog.py:82
+#: spyder/widgets/projects/configdialog.py:119
+#, fuzzy
+msgid "Restore data on startup"
+msgstr "Visszaállítás"
+
+#: spyder/widgets/projects/configdialog.py:84
+#: spyder/widgets/projects/configdialog.py:121
+#, fuzzy
+msgid "Save data on exit"
+msgstr "Mentés és kilépés"
+
+#: spyder/widgets/projects/configdialog.py:86
+#: spyder/widgets/projects/configdialog.py:123
+#, fuzzy
+msgid "Save history"
+msgstr "A nap&ló mentése mint..."
+
+#: spyder/widgets/projects/configdialog.py:88
+#: spyder/widgets/projects/configdialog.py:125
+msgid "Save non project files opened"
+msgstr "Projektenükívüli fájlok mentése"
+
+#: spyder/widgets/projects/configdialog.py:111
+msgid "Code"
+msgstr "Kód"
+
+#: spyder/widgets/projects/configdialog.py:118
+#, fuzzy
+msgid "Workspace"
+msgstr "Munkatér:"
+
+#: spyder/widgets/projects/configdialog.py:148
+#: spyder/widgets/projects/configdialog.py:155
+#, fuzzy
+msgid "Version control"
+msgstr "Verziókövetés"
+
+#: spyder/widgets/projects/configdialog.py:156
+#, fuzzy
+msgid "Use version control"
+msgstr "Verziókövetés"
+
+#: spyder/widgets/projects/configdialog.py:161
+#, fuzzy
+msgid "Version control system"
+msgstr "Grafikus felület a 'Bazaar' verzió-felügyelő rendszerhez"
+
+#: spyder/widgets/projects/explorer.py:51
+#, fuzzy
+msgid "Show horizontal scrollbar"
+msgstr "Csúszka mutatása"
+
+#: spyder/widgets/projects/explorer.py:113
+#, fuzzy
+msgid "File %s already exists.
Do you want to overwrite it?"
+msgstr "A(z) %1 nevű fájl már létezik.Felül szeretné írni? "
+
+#: spyder/widgets/projects/explorer.py:127
+#, fuzzy
+msgid "Folder %s already exists."
+msgstr "%1 már létezik, de nem mappa, hanem fájl."
+
+#: spyder/widgets/projects/explorer.py:145
+msgid "copy"
+msgstr "másolás"
+
+#: spyder/widgets/projects/explorer.py:147
+#, fuzzy
+msgid "move"
+msgstr "Áthely"
+
+#: spyder/widgets/projects/explorer.py:243
+msgid "Do you really want to delete {filename}?
Note: This action will only delete the project. Its files are going to be preserved on disk."
+msgstr ""
+
+#: spyder/widgets/projects/explorer.py:256
+msgid "Unable to delete {varpath}
The error message was:
{error}"
+msgstr "Törlés nem sikerült{varpath}
Hiba:
{error}"
+
+#: spyder/widgets/projects/projectdialog.py:69
+#, fuzzy
+msgid "New directory"
+msgstr "Új könyvtár"
+
+#: spyder/widgets/projects/projectdialog.py:70
+#, fuzzy
+msgid "Existing directory"
+msgstr "The file name is the same as an existing directory."
+
+#: spyder/widgets/projects/projectdialog.py:72
+#, fuzzy
+msgid "Project name"
+msgstr "Projekt neve:"
+
+#: spyder/widgets/projects/projectdialog.py:73
+#, fuzzy
+msgid "Location"
+msgstr "hely"
+
+#: spyder/widgets/projects/projectdialog.py:74
+#, fuzzy
+msgid "Project type"
+msgstr "Projekt:"
+
+#: spyder/widgets/projects/projectdialog.py:75
+#, fuzzy
+msgid "Python version"
+msgstr "Python"
+
+#: spyder/widgets/projects/projectdialog.py:83
+#: spyder/widgets/variableexplorer/importwizard.py:519
+msgid "Cancel"
+msgstr "Mégse"
+
+#: spyder/widgets/projects/projectdialog.py:84
+msgid "Create"
+msgstr "Létrehozás"
+
+#: spyder/widgets/projects/projectdialog.py:102
+#, fuzzy
+msgid "Create new project"
+msgstr "Új fordítási projekt létrehozása"
+
+#: spyder/widgets/projects/type/__init__.py:215
+#, fuzzy
+msgid "Empty project"
+msgstr "Válasszon ki egy nem üres hangprojektet a CDDB-lekérdezéshez."
+
+#: spyder/widgets/projects/type/python.py:20
+#, fuzzy
+msgid "Python project"
+msgstr "&Projekt"
+
+#: spyder/widgets/projects/type/python.py:76
+#, fuzzy
+msgid "Python package"
+msgstr "A python-pygame csomag nem található, a modem hang nem elérhető."
+
+#: spyder/widgets/pydocgui.py:110
+#, fuzzy
+msgid "Module or package:"
+msgstr "Csomag: "
+
+#: spyder/widgets/shell.py:128
+#, fuzzy
+msgid "Save history log..."
+msgstr "A nap&ló mentése mint..."
+
+#: spyder/widgets/shell.py:130
+msgid "Save current history log (i.e. all inputs and outputs) in a text file"
+msgstr "Aktuális torténet (parancsüererdmány) mentése "
+
+#: spyder/widgets/shell.py:256
+#, fuzzy
+msgid "Save history log"
+msgstr "A nap&ló mentése mint..."
+
+#: spyder/widgets/shell.py:259
+#, fuzzy
+msgid "History logs"
+msgstr "Naplók"
+
+#: spyder/widgets/shell.py:270
+msgid "Unable to save file '%s'
Error message:
%s"
+msgstr "’%s’ mentése nem sikerült
Hiba:
%s"
+
+#: spyder/widgets/shell.py:716
+#, fuzzy
+msgid "Copy without prompts"
+msgstr "A promptok sikertelenek.\n"
+
+#: spyder/widgets/shell.py:719 spyder/widgets/shell.py:723
+#, fuzzy
+msgid "Clear line"
+msgstr "&Törlés"
+
+#: spyder/widgets/shell.py:725
+#, fuzzy
+msgid "Clear shell"
+msgstr "&Törlés"
+
+#: spyder/widgets/shell.py:729
+msgid "Clear shell contents ('cls' command)"
+msgstr "Konzólt tisztítani (cls)"
+
+#: spyder/widgets/sourcecode/codeeditor.py:99
+#, fuzzy
+msgid "Go to line:"
+msgstr "&Ugrás egy sorra:"
+
+#: spyder/widgets/sourcecode/codeeditor.py:107
+#, fuzzy
+msgid "Line count:"
+msgstr "Sorszám"
+
+#: spyder/widgets/sourcecode/codeeditor.py:1306
+msgid "Breakpoint"
+msgstr "Töréspont"
+
+#: spyder/widgets/sourcecode/codeeditor.py:1307
+#, fuzzy
+msgid "Condition:"
+msgstr "Feltétel"
+
+#: spyder/widgets/sourcecode/codeeditor.py:1713
+#, fuzzy
+msgid "Code analysis"
+msgstr "Elemzés"
+
+#: spyder/widgets/sourcecode/codeeditor.py:1767
+#, fuzzy
+msgid "To do"
+msgstr "Feladat"
+
+#: spyder/widgets/sourcecode/codeeditor.py:2065
+#, fuzzy
+msgid "Removal error"
+msgstr "Az eltávolítás sikertelen"
+
+#: spyder/widgets/sourcecode/codeeditor.py:2066
+msgid "It was not possible to remove outputs from this notebook. The error is:\n"
+"\n"
+msgstr "Nem sikerült jegyzetfüzet kimenetes törölni. Hiba:\n"
+"\n"
+
+#: spyder/widgets/sourcecode/codeeditor.py:2588
+#, fuzzy
+msgid "Clear all ouput"
+msgstr "Clear &All"
+
+#: spyder/widgets/sourcecode/codeeditor.py:2594
+#, fuzzy
+msgid "Go to definition"
+msgstr "Ugrás a definícióra"
+
+#: spyder/widgets/sourcecode/codeeditor.py:2623
+#, fuzzy
+msgid "Zoom reset"
+msgstr "N&agyítás ennyivel:"
+
+#: spyder/widgets/status.py:25
+msgid "CPU and memory usage info in the status bar"
+msgstr "CPU/memória használat a státus mutatóban"
+
+#: spyder/widgets/status.py:94
+#, fuzzy
+msgid "Memory:"
+msgstr "Memór&ia:"
+
+#: spyder/widgets/status.py:95
+msgid "Memory usage status: requires the `psutil` (>=v0.3) library on non-Windows platforms"
+msgstr "Memóri használat - `psutil` (>=v0.3) kell, ha nem Windows"
+
+#: spyder/widgets/status.py:107
+#, fuzzy
+msgid "CPU:"
+msgstr "CPU %"
+
+#: spyder/widgets/status.py:108
+msgid "CPU usage status: requires the `psutil` (>=v0.3) library"
+msgstr "CPU hasznáalat - `psutil` (>=v0.3) kell"
+
+#: spyder/widgets/status.py:130
+msgid "Permissions:"
+msgstr "Engedélyek:"
+
+#: spyder/widgets/status.py:144
+#, fuzzy
+msgid "End-of-lines:"
+msgstr "Auto-adjust the space &format at the end of lines which are aligned right"
+
+#: spyder/widgets/status.py:158
+msgid "Encoding:"
+msgstr "Karakterkódolás:"
+
+#: spyder/widgets/status.py:171
+msgid "Line:"
+msgstr "Sor:"
+
+#: spyder/widgets/status.py:175
+#, fuzzy
+msgid "Column:"
+msgstr "Oszloponként"
+
+#: spyder/widgets/tabs.py:146
+#, fuzzy
+msgid "Browse tabs"
+msgstr "(Tabs)"
+
+#: spyder/widgets/tabs.py:275
+#, fuzzy
+msgid "Close current tab"
+msgstr "Aktuális lap bezárása"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:498
+#, fuzzy
+msgid "It was not possible to copy values for this array"
+msgstr "lehetséges értékek: „on” (be), „off” (ki), és „custom” (egyéni)."
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:533
+#: spyder/widgets/variableexplorer/arrayeditor.py:566
+#: spyder/widgets/variableexplorer/dataframeeditor.py:680
+#: spyder/widgets/variableexplorer/dataframeeditor.py:725
+msgid "Format"
+msgstr "Formázás"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:538
+#: spyder/widgets/variableexplorer/dataframeeditor.py:684
+msgid "Resize"
+msgstr "Átméretez"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:567
+#: spyder/widgets/variableexplorer/dataframeeditor.py:726
+#, fuzzy
+msgid "Float formatting"
+msgstr "Formatálás"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:575
+#, fuzzy
+msgid "Format (%s) is incorrect"
+msgstr "Hibás formátum"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:611
+msgid "Arrays with more than 3 dimensions are not supported"
+msgstr ">3 dimeziós tömböt nem mutat"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:615
+msgid "The 'xlabels' argument length do no match array column number"
+msgstr ""
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:619
+msgid "The 'ylabels' argument length do no match array row number"
+msgstr ""
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:626
+#, fuzzy
+msgid "%s arrays"
+msgstr "------- A szemafortömbök létrehozói/tulajdonosai ------- \n"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:627
+#, fuzzy
+msgid "%s are currently not supported"
+msgstr "A képtípus nem támogatott"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:634
+#, fuzzy
+msgid "NumPy array"
+msgstr "tömb"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:636
+#: spyder/widgets/variableexplorer/arrayeditor.py:790
+#, fuzzy
+msgid "Array editor"
+msgstr "Array"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:638
+#, fuzzy
+msgid "read only"
+msgstr "&Read-only"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:668
+#, fuzzy
+msgid "Record array fields:"
+msgstr "_Felvétel"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:680
+msgid "Data"
+msgstr "Adat"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:680
+msgid "Mask"
+msgstr "Maszk"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:680
+#, fuzzy
+msgid "Masked data"
+msgstr "&Data:"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:691
+#, fuzzy
+msgid "Axis:"
+msgstr "Tengely"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:696
+msgid "Index:"
+msgstr "Index:"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:709
+msgid "Warning: changes are applied separately"
+msgstr "Figyelem: valtazások külön felhasznáalva"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:710
+msgid "For performance reasons, changes applied to masked array won't be reflected in array's data (and vice-versa)."
+msgstr ""
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:127
+msgid "Index"
+msgstr "Index"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:132
+msgid "Tuple"
+msgstr ""
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:135
+msgid "List"
+msgstr "Listázás"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:138
+msgid "Dictionary"
+msgstr "Szótár"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:140
+msgid "Key"
+msgstr "Kulcs"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:145
+msgid "Attribute"
+msgstr "Attribútum"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:149
+#, fuzzy
+msgid "elements"
+msgstr "GUI elemek"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:325
+msgid "Size"
+msgstr "Fájlméret szerint"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:325
+#, fuzzy
+msgid "Type"
+msgstr "TÍPUS"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:325
+#, fuzzy
+msgid "Value"
+msgstr "ÉRTÉK"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:423
+msgid "Opening this variable can be slow\n"
+"\n"
+"Do you want to continue anyway?"
+msgstr "Ezt a vátozót kinyitni lassú lehet\n"
+"\n"
+"Tovább?"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:434
+msgid "Spyder was unable to retrieve the value of this variable from the console.
The error mesage was:
%s"
+msgstr "Ennek a változónak az értékt nem sikerült felfedezni a konzólból.
Hiba:
%s"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:608
+msgid "Edit item"
+msgstr "Bejegyzés szerkesztése"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:609
+msgid "Unable to assign data to item.
Error message:
%s"
+msgstr "Nem sikerült adatot meghatározni
Hiba:
%s"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:669
+#, fuzzy
+msgid "Resize rows to contents"
+msgstr "Ablakméret tartalomhoz igazítása"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:680
+#: spyder/widgets/variableexplorer/collectionseditor.py:1026
+#: spyder/widgets/variableexplorer/collectionseditor.py:1043
+msgid "Plot"
+msgstr "Kirajzolás"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:684
+msgid "Histogram"
+msgstr "Hisztogram"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:688
+msgid "Show image"
+msgstr "Kép megjelenítése"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:692
+#: spyder/widgets/variableexplorer/collectionseditor.py:1051
+#, fuzzy
+msgid "Save array"
+msgstr "Array"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:696
+#: spyder/widgets/variableexplorer/collectionseditor.py:990
+#: spyder/widgets/variableexplorer/collectionseditor.py:998
+msgid "Insert"
+msgstr "Beszúrás"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:699
+#: spyder/widgets/variableexplorer/collectionseditor.py:934
+msgid "Remove"
+msgstr "Eltávolít"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:709
+#: spyder/widgets/variableexplorer/collectionseditor.py:955
+msgid "Duplicate"
+msgstr "Duplikálás"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:932
+#, fuzzy
+msgid "Do you want to remove the selected item?"
+msgstr "Valóban áthelyezi ezt a(z) %1 elemet a szemetesbe?"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:933
+#, fuzzy
+msgid "Do you want to remove all selected items?"
+msgstr "Biztosan törölni szeretné a kijelölt elemeket?"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:953
+#, fuzzy
+msgid "New variable name:"
+msgstr "Változónév"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:956
+#, fuzzy
+msgid "Variable name:"
+msgstr "Változónév:"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:990
+msgid "Key:"
+msgstr "Kulcs:"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:998
+msgid "Value:"
+msgstr "Érték:"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1014
+#, fuzzy
+msgid "Import error"
+msgstr "Importálási hiba egy visszavonási listánál"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1015
+msgid "Please install matplotlib or guiqwt."
+msgstr "Kárjük matplotlib vagy guiqwt telepítést"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1027
+msgid "Unable to plot data.
Error message:
%s"
+msgstr "Adatok ábrázolása nem sikerült.
Hiba:
%s"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1044
+msgid "Unable to show image.
Error message:
%s"
+msgstr "Képet mutatni nem sikerült
Hiba:
%s"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1067
+msgid "Unable to save array
Error message:
%s"
+msgstr "Tömb mentése nem sikerült
Hiba:
%s"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1092
+#, fuzzy
+msgid "It was not possible to copy this array"
+msgstr "tömb"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1117
+msgid "Clipboard contents"
+msgstr "A vágólap tartalma"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1132
+#, fuzzy
+msgid "Import from clipboard"
+msgstr "A _vágólapról"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1134
+#, fuzzy
+msgid "Empty clipboard"
+msgstr "<üres vágólap>"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1135
+#, fuzzy
+msgid "Nothing to be imported from clipboard."
+msgstr "Tanúsítványimportálás történt innen: %1"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:574
+#, fuzzy
+msgid "To bool"
+msgstr "logikai"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:574
+#, fuzzy
+msgid "To complex"
+msgstr "(Complex)"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:575
+#, fuzzy
+msgid "To float"
+msgstr "Le_begő"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:575
+#, fuzzy
+msgid "To int"
+msgstr "egész"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:576
+#, fuzzy
+msgid "To str"
+msgstr "Használat: %s [-0prtx] [--interactive] [--null] [-d|--delimiter=elhat]\n"
+" [-E eof-str] [-e[eof-str]] [--eof[=eof-str]]\n"
+" [-L max-sor] [-l[max-sor]] [--max-lines[=max-sor]]\n"
+" [-I csere-kar] [-i[csere-kar]] [--replace[=csere-kar]]\n"
+" [-n max-arg] [--max-args=max-arg]\n"
+" [-s max-kar] [--max-chars=max-kar]\n"
+" [-P max-proc] [--max-procs=max-proc] [--show-limits]\n"
+" [--verbose] [--exit] [--no-run-if-empty] [--arg-file=fájl]\n"
+" [--version] [--help] [parancs [induló-argumentumok]]\n"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:660
+#, fuzzy
+msgid "%s editor"
+msgstr "(Szöveges terület). Kérem a szöveget. Le-föl nyíl, Tab: kilép. (%s szerkesztő)"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:694
+#, fuzzy
+msgid "Column min/max"
+msgstr "SASL SSF min/max:"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:734
+#, fuzzy
+msgid "Format ({}) is incorrect"
+msgstr "érvénytelen összehasonlítási formátum; rossz sor eleji karakter"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:738
+#, fuzzy
+msgid "Format ({}) should start with '%'"
+msgstr "Az átjáró címének formátuma 1.2.3.4 legyen"
+
+#: spyder/widgets/variableexplorer/importwizard.py:116
+#: spyder/widgets/variableexplorer/importwizard.py:431
+#, fuzzy
+msgid "Import as"
+msgstr "IMPORTÁLÁS"
+
+#: spyder/widgets/variableexplorer/importwizard.py:118
+#, fuzzy
+msgid "data"
+msgstr "&Data:"
+
+#: spyder/widgets/variableexplorer/importwizard.py:122
+msgid "code"
+msgstr "kód"
+
+#: spyder/widgets/variableexplorer/importwizard.py:125
+#: spyder/widgets/variableexplorer/importwizard.py:504
+msgid "text"
+msgstr "szöveg"
+
+#: spyder/widgets/variableexplorer/importwizard.py:138
+msgid "Column separator:"
+msgstr "Oszlopválasztó"
+
+#: spyder/widgets/variableexplorer/importwizard.py:142
+msgid "Tab"
+msgstr "Tabulátor"
+
+#: spyder/widgets/variableexplorer/importwizard.py:145
+#: spyder/widgets/variableexplorer/importwizard.py:163
+msgid "other"
+msgstr "más"
+
+#: spyder/widgets/variableexplorer/importwizard.py:156
+msgid "Row separator:"
+msgstr "Sorválasztó"
+
+#: spyder/widgets/variableexplorer/importwizard.py:160
+msgid "EOL"
+msgstr "EOL"
+
+#: spyder/widgets/variableexplorer/importwizard.py:175
+#, fuzzy
+msgid "Additional options"
+msgstr "További beállítások"
+
+#: spyder/widgets/variableexplorer/importwizard.py:179
+#, fuzzy
+msgid "Skip rows:"
+msgstr " sor és "
+
+#: spyder/widgets/variableexplorer/importwizard.py:190
+msgid "Comments:"
+msgstr "Megjegyzések:"
+
+#: spyder/widgets/variableexplorer/importwizard.py:196
+msgid "Transpose"
+msgstr "Transpose"
+
+#: spyder/widgets/variableexplorer/importwizard.py:434
+msgid "array"
+msgstr "tömb"
+
+#: spyder/widgets/variableexplorer/importwizard.py:439
+msgid "list"
+msgstr "lista"
+
+#: spyder/widgets/variableexplorer/importwizard.py:444
+msgid "DataFrame"
+msgstr "Adat-keret"
+
+#: spyder/widgets/variableexplorer/importwizard.py:487
+#: spyder/widgets/variableexplorer/importwizard.py:571
+#, fuzzy
+msgid "Import wizard"
+msgstr "Text Import Wizard - Step %1 of 3"
+
+#: spyder/widgets/variableexplorer/importwizard.py:492
+#, fuzzy
+msgid "Raw text"
+msgstr "Nincs cél a nyers szöveghez!"
+
+#: spyder/widgets/variableexplorer/importwizard.py:495
+#, fuzzy
+msgid "variable_name"
+msgstr "Változónév"
+
+#: spyder/widgets/variableexplorer/importwizard.py:506
+msgid "table"
+msgstr "táblázat"
+
+#: spyder/widgets/variableexplorer/importwizard.py:507
+msgid "Preview"
+msgstr "Előnézet"
+
+#: spyder/widgets/variableexplorer/importwizard.py:511
+msgid "Variable Name"
+msgstr "Változónév"
+
+#: spyder/widgets/variableexplorer/importwizard.py:534
+msgid "Done"
+msgstr "Kész"
+
+#: spyder/widgets/variableexplorer/importwizard.py:572
+msgid "Unable to proceed to next step
Please check your entries.
Error message:
%s"
+msgstr "Lépés nem sikerült
Ellenőrízze bejegyzéseket
Hiba:
%s"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:207
+msgid "Refresh"
+msgstr "Frissítés"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:211
+msgid "Refresh periodically"
+msgstr "Frissítés periodikusan"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:218
+#: spyder/widgets/variableexplorer/namespacebrowser.py:493
+msgid "Import data"
+msgstr "Adat importálása"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:221
+#: spyder/widgets/variableexplorer/namespacebrowser.py:571
+#: spyder/widgets/variableexplorer/namespacebrowser.py:590
+msgid "Save data"
+msgstr "Adat mentése"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:226
+msgid "Save data as..."
+msgstr "Adat mentése másként"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:238
+msgid "Exclude references which name starts with an underscore"
+msgstr "Kizárni aláhúzássalükezdő referenciákat"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:246
+msgid "Exclude references which name is uppercase"
+msgstr "Kizárni nagybetüs referenciákat"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:253
+msgid "Exclude references which name starts with an uppercase character"
+msgstr "Kizárni nagybetüvelükezdő referenciákat"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:261
+msgid "Exclude references to unsupported data types (i.e. which won't be handled/saved correctly)"
+msgstr "Kizárni nemütámogatott adat tipusu referenciákat"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:513
+msgid "Unsupported file extension '%s'
Would you like to import it anyway (by selecting a known file format)?"
+msgstr "Nem támogatott fájlvég ‘%s’
Mégis betölteni?"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:521
+msgid "Open file as:"
+msgstr "Fájl megnyitása másként"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:559
+msgid "Unable to load '%s'
Error message:
%s"
+msgstr "’%s’ betöltés nem sikerült
Hiba:
%s"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:591
+msgid "Unable to save current workspace
Error message:
%s"
+msgstr "Munkaterület nem mentve
Hiba:
%s"
+
+#: spyder/widgets/variableexplorer/texteditor.py:74
+msgid "Text editor"
+msgstr "Szövegszerkesztő"
+
+#: spyder/widgets/variableexplorer/utils.py:29
+msgid "View and edit DataFrames and Series in the Variable Explorer"
+msgstr "Mutatni-szerkeszteni adat-keretet/sort a változó böngészőben"
+
+#: spyder/widgets/variableexplorer/utils.py:34
+msgid "View and edit two and three dimensional arrays in the Variable Explorer"
+msgstr "Mutatni-szerkeszteni 2D/3D tömbökett a változó böngészőben"
+
+#: spyder/workers/updates.py:89 spyder/workers/updates.py:91
+#, fuzzy
+msgid "Unable to retrieve information."
+msgstr "Nem sikerült beolvasni a számítógépen tárolt cookie-k jellemzőit."
+
+#: spyder/workers/updates.py:93
+msgid "Unable to connect to the internet.
Make sure the connection is working properly."
+msgstr "Internet kapcsolat nem sikerült.
"
+
+#: spyder/workers/updates.py:96
+#, fuzzy
+msgid "Unable to check for updates."
+msgstr "Frissítések ellenőrzése"
+
+#: spyder/plugins/breakpoints/plugin.py:55
+msgid "Breakpoints"
+msgstr "Töréspontok"
+
+#: spyder/plugins/breakpoints/plugin.py:91
+msgid "List breakpoints"
+msgstr "Töréspontok listája"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:98
+msgid "Condition"
+msgstr "Feltétel"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:98
+msgid "File"
+msgstr "Fájl"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:98
+msgid "Line"
+msgstr "Vonal"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:181
+msgid "Clear breakpoints in all files"
+msgstr "Töröl töréspontot minden fájlban"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:202
+msgid "Clear this breakpoint"
+msgstr "Törölje ezt a töréspontot"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:207
+msgid "Edit this breakpoint"
+msgstr "Szekeszti ezt a töréspontot"
+#: spyder/plugins/profiler/plugin.py:33
+msgid "Results"
+msgstr "Eredmények"
+#: spyder/plugins/profiler/plugin.py:34
+msgid ""
+"Profiler plugin results (the output of python's profile/cProfile)\n"
+"are stored here:"
+msgstr "Profilozó (python profile/cProfile kimenetei) eredményeket"
+"ide tárolni"
+#: spyder/plugins/profiler/plugin.py:75
+msgid "Profiler"
+msgstr "Profilozó"
+#: spyder/plugins/profiler/plugin.py:104 spyder/plugins/profiler/widgets/profilergui.py:81
+msgid "Profile"
+msgstr "Profilozni"
+#: spyder/plugins/profiler/widgets/profilergui.py:82
+msgid "Run profiler"
+msgstr "A profilozó futtatása"
+#: spyder/plugins/profiler/widgets/profilergui.py:87
+msgid "Stop"
+msgstr "Megáll"
+#: spyder/plugins/profiler/widgets/profilergui.py:88
+msgid "Stop current profiling"
+msgstr "A jelenlegi profilozó leállítása"
+#: spyder/plugins/profiler/widgets/profilergui.py:96
+#: spyder/plugins/profiler/widgets/profilergui.py:219
+msgid "Select Python script"
+msgstr "Python script kiválasztása"
+#: spyder/plugins/profiler/widgets/profilergui.py:102
+msgid "Output"
+msgstr "Kimenet"
+#: spyder/plugins/profiler/widgets/profilergui.py:104
+msgid "Show program's output"
+msgstr "A program kimenetét mutatni"
+#: spyder/plugins/profiler/widgets/profilergui.py:113
+msgid "Collapse one level up"
+msgstr "Egy szintet felfelé összeomlít"
+#: spyder/plugins/profiler/widgets/profilergui.py:118
+msgid "Expand one level down"
+msgstr "Egy szintet lefelé terjeszt"
+#: spyder/plugins/profiler/widgets/profilergui.py:121
+msgid "Save data"
+msgstr "Adat mentése"
+#: spyder/plugins/profiler/widgets/profilergui.py:124
+msgid "Save profiling data"
+msgstr "Profilozó adatok mentése"
+#: spyder/plugins/profiler/widgets/profilergui.py:126
+msgid "Load data"
+msgstr "Adatbetöltés"
+#: spyder/plugins/profiler/widgets/profilergui.py:129
+msgid "Load profiling data for comparison"
+msgstr "Profilozó adatok betöltése összehasonlításhoz"
+#: spyder/plugins/profiler/widgets/profilergui.py:131
+msgid "Clear comparison"
+msgstr "Összehasonlítás törlése"
+#: spyder/plugins/profiler/widgets/profilergui.py:171
+msgid "Please install"
+msgstr "Kérjük telepítse"
+#: spyder/plugins/profiler/widgets/profilergui.py:172
+msgid "the Python profiler modules"
+msgstr "python profilozó modulok"
+#: spyder/plugins/profiler/widgets/profilergui.py:179
+msgid "Save profiler result"
+msgstr "A profilozó eredmények mentése"
+#: spyder/plugins/profiler/widgets/profilergui.py:182
+#: spyder/plugins/profiler/widgets/profilergui.py:188
+msgid "Profiler result"
+msgstr "Profilozó eredmények"
+#: spyder/plugins/profiler/widgets/profilergui.py:187
+msgid "Select script to compare"
+msgstr "Script kiválasztása összehasonlításhoz"
+#: spyder/plugins/profiler/widgets/profilergui.py:220
+msgid "Python scripts"
+msgstr "Python scriptek"
+#: spyder/plugins/profiler/widgets/profilergui.py:227
+#: spyder/plugins/profiler/widgets/profilergui.py:232
+msgid "Profiler output"
+msgstr "Profilozó kimenete"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:251
+msgid "Profiling, please wait..."
+msgstr "Profilozás, kérlek várj..."
+
+#: spyder/plugins/profiler/widgets/profilergui.py:295
+msgid "Error"
+msgstr "Hiba"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:296
+msgid "Process failed to start"
+msgstr "Folyamat inditás nem sikerült"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:343
+msgid "Sorting data, please wait..."
+msgstr "Adat rendezés, kérem várjon"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Function/Module"
+msgstr "Funkció/Modul"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Total Time"
+msgstr "Teljes idő"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Diff"
+msgstr "Diff"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Calls"
+msgstr "Hívások"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Local Time"
+msgstr "Helyi idő"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:391
+msgid "File:line"
+msgstr "Fájl:vonal"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:565
+msgid "Function or module name"
+msgstr "Funkció vagy modul neve"
+msgstr "Python script kiválasztása"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:569
+msgid "Time in function (including sub-functions)"
+msgstr "Idő funkcióban (alfunckiókat beleszámítva)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:578
+msgid "Local time in function (not in sub-functions)"
+msgstr "Helyi idő funckióban (nem alfuncióban)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:588
+msgid "Total number of calls (including recursion)"
+msgstr "Teljes hívás száma (rekurzió beleszámítva)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:598
+msgid "File:line where function is defined"
+msgstr "Fájl:vonal ahol megértelmez funkciót"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:603
+msgid "recursion"
+msgstr "rekurzió"
+
+#: spyder/plugins/pylint/plugin.py:35
+msgid "Settings"
+msgstr "Beállítások"
+
+#: spyder/plugins/pylint/plugin.py:36
+msgid "Save file before analyzing it"
+msgstr "Menteni elemzés előtt"
+
+#: spyder/plugins/pylint/plugin.py:39 spyder/plugins/pylint/plugin.py:160
+msgid "History"
+msgstr "Előzmények"
+
+#: spyder/plugins/pylint/plugin.py:40
+msgid "The following option will be applied at next startup."
+msgstr "Következő "
+
+#: spyder/plugins/pylint/plugin.py:43
+msgid "History: "
+msgstr "Előzmények:"
+
+#: spyder/plugins/pylint/plugin.py:44
+msgid " results"
+msgstr " eredmények"
+
+#: spyder/plugins/pylint/plugin.py:47
+msgid "Results"
+msgstr "Eredmények"
+
+#: spyder/plugins/pylint/plugin.py:48
+msgid "Results are stored here:"
+msgstr "Az eredmények itt tárolva:"
+msgstr "Profilozó eredmények"
+
+#: spyder/plugins/pylint/plugin.py:98 spyder/plugins/pylint/widgets/pylintgui.py:83
+msgid "Static code analysis"
+msgstr "Statkikus kód elemzés"
+
+#: spyder/plugins/pylint/plugin.py:115
+msgid "History..."
+msgstr "Előzmények..."
+
+#: spyder/plugins/pylint/plugin.py:117
+msgid "Set history maximum entries"
+msgstr "Maximális előzményelemek beállítása"
+msgstr "Profilozó kimenete"
+
+#: spyder/plugins/pylint/plugin.py:133
+msgid "Run static code analysis"
+msgstr "Statikus kód elemzés futtatása"
+
+#: spyder/plugins/pylint/plugin.py:161
+msgid "Maximum entries"
+msgstr "Elemek maximuma"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:117
+msgid "Results for "
+msgstr "Eredmények ehhez:"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:122
+msgid "Convention"
+msgstr "Egy, két vagy három betűs nemzetközi rövidítés egy elem nevére."
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:124
+msgid "Refactor"
+msgstr "Újrafaktorizálás"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:126
+msgid "Warning"
+msgstr "Figyelem"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:128
+#: spyder/plugins/pylint/widgets/pylintgui.py:363
+#: spyder/plugins/pylint/widgets/pylintgui.py:391
+msgid "Error"
+msgstr "Hiba"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:206
+msgid "Analyze"
+msgstr "Elemzés"
+msgstr "Diff"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:207
+msgid "Run analysis"
+msgstr "Elemzés futtatása"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:211
+msgid "Stop"
+msgstr "Megállítás"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:212
+msgid "Stop current analysis"
+msgstr "A jelenlegi elemzés megállítása"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:218
+#: spyder/plugins/pylint/widgets/pylintgui.py:288
+msgid "Select Python file"
+msgstr "Python fájl választás"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:224
+msgid "Output"
+msgstr "Kimenet"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:226
+msgid "Complete output"
+msgstr "Teljes kimenet"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:260
+msgid "Pylint script was not found. Please add \"%s\" to PATH."
+msgstr "Pylint script nem találva. Kérem hozzáadni \"%s\"-ot a PATH-hoz"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:263
+msgid "Please install pylint:"
+msgstr "Kérjük telepítse a pylint-et:"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:289
+msgid "Python files"
+msgstr "Python-fájlok"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:326
+msgid "Pylint output"
+msgstr "Pylint kimenet"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:364
+msgid "Process failed to start"
+msgstr "A folyamat indítása nem sikerült"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:465
+msgid "Source code has not been rated yet."
+msgstr "Forráskód még nem becsülve"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:471
+msgid "Analysis did not succeed (see output for more details)."
+msgstr "Elemzés nem sikerült (részletekért lássa a kimenetet)"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:484
+msgid "Global evaluation:"
+msgstr "Általános értékalés"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:488
+msgid "previous run:"
+msgstr "Előző futtatás:"
+
+#: spyder/plugins/pylint/plugin.py:44
+msgid " results"
+msgstr " eredmények"
+
+#: spyder/plugins/pylint/plugin.py:47
+msgid "Results"
+msgstr "Eredmények"
+
+#: spyder/plugins/pylint/plugin.py:48
+msgid "Results are stored here:"
+msgstr "Az eredmények itt tárolva:"
+
+#: spyder/plugins/pylint/plugin.py:98 spyder/plugins/pylint/widgets/pylintgui.py:83
+msgid "Static code analysis"
+msgstr "Statkikus kód elemzés"
+
+#: spyder/plugins/pylint/plugin.py:115
+msgid "History..."
+msgstr "Előzmények..."
+
+#: spyder/plugins/pylint/plugin.py:117
+msgid "Set history maximum entries"
+msgstr "Maximális előzményelemek beállítása"
+
+#: spyder/plugins/pylint/plugin.py:133
+msgid "Run static code analysis"
+msgstr "Statikus kód elemzés futtatása"
+
+#: spyder/plugins/pylint/plugin.py:161
+msgid "Maximum entries"
+msgstr "Elemek maximuma"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:117
+msgid "Results for "
+msgstr "Eredmények ehhez:"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:122
+#, fuzzy
+msgid "Convention"
+msgstr "Egy, két vagy három betűs nemzetközi rövidítés egy elem nevére."
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:124
+msgid "Refactor"
+msgstr "Újrafaktorizálás"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:126
+msgid "Warning"
+msgstr "Figyelem"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:128
+#: spyder/plugins/pylint/widgets/pylintgui.py:363
+#: spyder/plugins/pylint/widgets/pylintgui.py:391
+msgid "Error"
+msgstr "Hiba"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:206
+msgid "Analyze"
+msgstr "Elemzés"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:207
+msgid "Run analysis"
+msgstr "Elemzés futtatása"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:211
+msgid "Stop"
+msgstr "Megállítás"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:212
+msgid "Stop current analysis"
+msgstr "A jelenlegi elemzés megállítása"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:218
+#: spyder/plugins/pylint/widgets/pylintgui.py:288
+msgid "Select Python file"
+msgstr "Python fájl választás"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:224
+msgid "Output"
+msgstr "Kimenet"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:226
+msgid "Complete output"
+msgstr "Teljes kimenet"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:260
+msgid "Pylint script was not found. Please add \"%s\" to PATH."
+msgstr "Pylint script nem találva. Kérem hozzáadni \"%s\"-ot a PATH-hoz"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:263
+msgid "Please install pylint:"
+msgstr "Kérjük telepítse a pylint-et:"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:289
+msgid "Python files"
+msgstr "Python-fájlok"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:326
+msgid "Pylint output"
+msgstr "Pylint kimenet"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:364
+msgid "Process failed to start"
+msgstr "A folyamat indítása nem sikerült"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:465
+msgid "Source code has not been rated yet."
+msgstr "Forráskód még nem becsülve"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:471
+msgid "Analysis did not succeed (see output for more details)."
+msgstr "Elemzés nem sikerült (részletekért lássa a kimenetet)"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:484
+msgid "Global evaluation:"
+msgstr "Általános értékalés"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:488
+msgid "previous run:"
+msgstr "Előző futtatás:"
+
diff --git a/spyder/locale/ja/LC_MESSAGES/spyder.mo b/spyder/locale/ja/LC_MESSAGES/spyder.mo
index 08ee852f8ed..cf8d7fe7df4 100644
Binary files a/spyder/locale/ja/LC_MESSAGES/spyder.mo and b/spyder/locale/ja/LC_MESSAGES/spyder.mo differ
diff --git a/spyder/locale/ja/LC_MESSAGES/spyder.po b/spyder/locale/ja/LC_MESSAGES/spyder.po
index fa09db82bd8..7c51a7ae686 100644
--- a/spyder/locale/ja/LC_MESSAGES/spyder.po
+++ b/spyder/locale/ja/LC_MESSAGES/spyder.po
@@ -1,15 +1,22 @@
-# Japanese translations for PACKAGE package
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+#
+# Spyder's Japanese gettext translation file
+#
# PACKAGE パッケージに対する英訳.
-# Copyright (C) 2016 THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
# Ohnishi Seiki , 2016.
#
msgid ""
msgstr ""
"Project-Id-Version: Spyder3\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-19 11:56+-05\n"
-"PO-Revision-Date: 2018-02-21 19:02+0900\n"
+"POT-Creation-Date: 2018-11-13 11:49+-05\n"
+"PO-Revision-Date: 2018-11-16 20:14+0900\n"
"Last-Translator: \n"
"Language-Team: Japanese \n"
"Language: ja\n"
@@ -20,47 +27,39 @@ msgstr ""
"X-Generator: Poedit 1.8.11\n"
"X-Poedit-SourceCharset: UTF-8\n"
-#: spyder/app/mainwindow.py:134
+#: spyder/app/mainwindow.py:139
msgid "Initializing..."
msgstr "初期化中..."
-#: spyder/app/mainwindow.py:238
+#: spyder/app/mainwindow.py:252
msgid "Python2 documentation"
msgstr "Python2ドキュメント"
-#: spyder/app/mainwindow.py:240
+#: spyder/app/mainwindow.py:254
msgid "Python3 documentation"
msgstr "Python3ドキュメント"
-#: spyder/app/mainwindow.py:242
+#: spyder/app/mainwindow.py:256
msgid "Numpy and Scipy documentation"
msgstr "NumpyとScipyのドキュメント"
-#: spyder/app/mainwindow.py:244
+#: spyder/app/mainwindow.py:258
msgid "Matplotlib documentation"
msgstr "Matplotlibドキュメント"
-#: spyder/app/mainwindow.py:247
-msgid "PyQt4 Reference Guide"
-msgstr "PyQt4リファレンスガイド"
-
-#: spyder/app/mainwindow.py:250
-msgid "PyQt4 API Reference"
-msgstr "PyQt4 APIリファレンス"
-
-#: spyder/app/mainwindow.py:253
+#: spyder/app/mainwindow.py:261
msgid "PyQt5 Reference Guide"
msgstr "PyQt5リファレンスガイド"
-#: spyder/app/mainwindow.py:256
+#: spyder/app/mainwindow.py:264
msgid "PyQt5 API Reference"
msgstr "PyQt5 APIリファレンス"
-#: spyder/app/mainwindow.py:258
+#: spyder/app/mainwindow.py:266
msgid "WinPython"
msgstr "WinPython"
-#: spyder/app/mainwindow.py:518
+#: spyder/app/mainwindow.py:525
msgid ""
"An error occurred while creating a socket needed by Spyder. Please, try to "
"run as an Administrator from cmd.exe the following command and then restart "
@@ -71,222 +70,214 @@ msgstr ""
"限で実行し、PCを再起動して下さい:
netsh winsock reset
"
-#: spyder/app/mainwindow.py:550
+#: spyder/app/mainwindow.py:557
msgid "Close current pane"
msgstr "現在のペインを閉じる"
-#: spyder/app/mainwindow.py:555
+#: spyder/app/mainwindow.py:562
msgid "Lock panes"
msgstr "ペインをロック"
-#: spyder/app/mainwindow.py:562
+#: spyder/app/mainwindow.py:569
msgid "Use next layout"
msgstr "次のレイアウトを使用"
-#: spyder/app/mainwindow.py:566
+#: spyder/app/mainwindow.py:573
msgid "Use previous layout"
msgstr "前のレイアウトを使用"
-#: spyder/app/mainwindow.py:576 spyder/widgets/editor.py:497
+#: spyder/app/mainwindow.py:583 spyder/widgets/editor.py:507
msgid "File switcher..."
msgstr "ファイル切り替え..."
-#: spyder/app/mainwindow.py:578
+#: spyder/app/mainwindow.py:585
msgid "Fast switch between files"
msgstr "フィルを高速で切り替え"
-#: spyder/app/mainwindow.py:584
+#: spyder/app/mainwindow.py:591
msgid "Symbol finder..."
msgstr "シンボルファインダー..."
-#: spyder/app/mainwindow.py:586
+#: spyder/app/mainwindow.py:593
msgid "Fast symbol search in file"
msgstr "ファイル内の高速シンボル検索"
-#: spyder/app/mainwindow.py:605 spyder/widgets/sourcecode/codeeditor.py:2673
+#: spyder/app/mainwindow.py:612 spyder/widgets/sourcecode/codeeditor.py:2680
msgid "Undo"
msgstr "元に戻す"
-#: spyder/app/mainwindow.py:607 spyder/widgets/sourcecode/codeeditor.py:2676
+#: spyder/app/mainwindow.py:614 spyder/widgets/sourcecode/codeeditor.py:2683
msgid "Redo"
msgstr "やり直す"
-#: spyder/app/mainwindow.py:609 spyder/widgets/shell.py:123
-#: spyder/widgets/sourcecode/codeeditor.py:2682
-#: spyder/widgets/variableexplorer/arrayeditor.py:467
-#: spyder/widgets/variableexplorer/collectionseditor.py:674
-#: spyder/widgets/variableexplorer/dataframeeditor.py:592
+#: spyder/app/mainwindow.py:616 spyder/widgets/shell.py:123
+#: spyder/widgets/sourcecode/codeeditor.py:2689
+#: spyder/widgets/variableexplorer/arrayeditor.py:465
+#: spyder/widgets/variableexplorer/collectionseditor.py:710
+#: spyder/widgets/variableexplorer/dataframeeditor.py:616
msgid "Copy"
msgstr "コピー"
-#: spyder/app/mainwindow.py:611 spyder/widgets/shell.py:119
-#: spyder/widgets/sourcecode/codeeditor.py:2679
+#: spyder/app/mainwindow.py:618 spyder/widgets/shell.py:119
+#: spyder/widgets/sourcecode/codeeditor.py:2686
msgid "Cut"
msgstr "切り取り"
-#: spyder/app/mainwindow.py:613 spyder/widgets/shell.py:127
-#: spyder/widgets/sourcecode/codeeditor.py:2685
-#: spyder/widgets/variableexplorer/collectionseditor.py:671
+#: spyder/app/mainwindow.py:620 spyder/widgets/shell.py:127
+#: spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/widgets/variableexplorer/collectionseditor.py:707
msgid "Paste"
msgstr "貼り付け"
-#: spyder/app/mainwindow.py:616 spyder/widgets/shell.py:140
-#: spyder/widgets/sourcecode/codeeditor.py:2688
+#: spyder/app/mainwindow.py:623 spyder/widgets/shell.py:140
+#: spyder/widgets/sourcecode/codeeditor.py:2695
msgid "Select All"
msgstr "全て選択"
-#: spyder/app/mainwindow.py:626 spyder/plugins/editor.py:1422
+#: spyder/app/mainwindow.py:633 spyder/plugins/editor.py:1421
msgid "&File"
msgstr "ファイル(&A)"
-#: spyder/app/mainwindow.py:627 spyder/plugins/editor.py:1410
+#: spyder/app/mainwindow.py:634 spyder/plugins/editor.py:1409
msgid "File toolbar"
msgstr "ファイルツールバー"
-#: spyder/app/mainwindow.py:631 spyder/plugins/editor.py:1423
+#: spyder/app/mainwindow.py:638 spyder/plugins/editor.py:1422
msgid "&Edit"
msgstr "編集(&E)"
-#: spyder/app/mainwindow.py:632 spyder/plugins/editor.py:1420
+#: spyder/app/mainwindow.py:639 spyder/plugins/editor.py:1419
msgid "Edit toolbar"
msgstr "編集ツールバー"
-#: spyder/app/mainwindow.py:636 spyder/plugins/editor.py:1424
+#: spyder/app/mainwindow.py:643 spyder/plugins/editor.py:1423
msgid "&Search"
msgstr "検索(&S)"
-#: spyder/app/mainwindow.py:637 spyder/plugins/editor.py:1412
+#: spyder/app/mainwindow.py:644 spyder/plugins/editor.py:1411
msgid "Search toolbar"
msgstr "検索ツールバー"
-#: spyder/app/mainwindow.py:641 spyder/plugins/editor.py:1425
+#: spyder/app/mainwindow.py:648 spyder/plugins/editor.py:1424
msgid "Sour&ce"
msgstr "ソース(&C)"
-#: spyder/app/mainwindow.py:642 spyder/plugins/editor.py:1414
+#: spyder/app/mainwindow.py:649 spyder/plugins/editor.py:1413
msgid "Source toolbar"
msgstr "ソースツールバー"
-#: spyder/app/mainwindow.py:646 spyder/plugins/editor.py:803
-#: spyder/plugins/editor.py:1426
+#: spyder/app/mainwindow.py:653 spyder/plugins/editor.py:803
+#: spyder/plugins/editor.py:1425
msgid "&Run"
msgstr "実行(&R)"
-#: spyder/app/mainwindow.py:647 spyder/plugins/editor.py:1416
+#: spyder/app/mainwindow.py:654 spyder/plugins/editor.py:1415
msgid "Run toolbar"
msgstr "実行ツールバー"
-#: spyder/app/mainwindow.py:651 spyder/plugins/editor.py:762
+#: spyder/app/mainwindow.py:658 spyder/plugins/editor.py:762
msgid "&Debug"
msgstr "デバッグ(&D)"
-#: spyder/app/mainwindow.py:652 spyder/plugins/editor.py:1418
+#: spyder/app/mainwindow.py:659 spyder/plugins/editor.py:1417
msgid "Debug toolbar"
msgstr "デバッグツールバー"
-#: spyder/app/mainwindow.py:656
+#: spyder/app/mainwindow.py:663
msgid "C&onsoles"
msgstr "コンソール(&O)"
-#: spyder/app/mainwindow.py:659
+#: spyder/app/mainwindow.py:666
msgid "&Projects"
msgstr "プロジェクト(&P)"
-#: spyder/app/mainwindow.py:662 spyder/plugins/editor.py:1427
+#: spyder/app/mainwindow.py:669 spyder/plugins/editor.py:1426
msgid "&Tools"
msgstr "ツール(&T)"
-#: spyder/app/mainwindow.py:665 spyder/plugins/editor.py:1428
+#: spyder/app/mainwindow.py:672 spyder/plugins/editor.py:1427
msgid "&View"
msgstr "表示(&V)"
-#: spyder/app/mainwindow.py:668 spyder/plugins/editor.py:1429
+#: spyder/app/mainwindow.py:675 spyder/plugins/editor.py:1428
msgid "&Help"
msgstr "ヘルプ(&H)"
-#: spyder/app/mainwindow.py:673
+#: spyder/app/mainwindow.py:680
msgid "Welcome to Spyder!"
msgstr "Spyderへようこそ!"
-#: spyder/app/mainwindow.py:678
+#: spyder/app/mainwindow.py:685
msgid "Pre&ferences"
msgstr "設定(&F)"
-#: spyder/app/mainwindow.py:685 spyder/widgets/pathmanager.py:53
+#: spyder/app/mainwindow.py:692 spyder/widgets/pathmanager.py:54
msgid "PYTHONPATH manager"
msgstr "PYTHONPATHマネージャ"
-#: spyder/app/mainwindow.py:688
+#: spyder/app/mainwindow.py:695
msgid "Python Path Manager"
msgstr "Pythonパスマネージャ"
-#: spyder/app/mainwindow.py:691
+#: spyder/app/mainwindow.py:698
msgid "Update module names list"
msgstr "モジュール名リストの更新"
-#: spyder/app/mainwindow.py:694
+#: spyder/app/mainwindow.py:701
msgid "Refresh list of module names available in PYTHONPATH"
msgstr "PYTHONPATH上で利用可能なモジュールリストの更新"
-#: spyder/app/mainwindow.py:697
+#: spyder/app/mainwindow.py:704
msgid "Reset Spyder to factory defaults"
msgstr "Spyderをデフォルト設定へ戻す"
-#: spyder/app/mainwindow.py:702
+#: spyder/app/mainwindow.py:709
msgid "Current user environment variables..."
msgstr "現在のユーザー環境変数..."
-#: spyder/app/mainwindow.py:704
+#: spyder/app/mainwindow.py:711
msgid ""
"Show and edit current user environment variables in Windows registry (i.e. "
"for all sessions)"
msgstr "レジストリ内のユーザー環境変数を表示・編集する"
-#: spyder/app/mainwindow.py:713 spyder/app/mainwindow.py:1137
+#: spyder/app/mainwindow.py:720 spyder/app/mainwindow.py:1115
msgid "External Tools"
msgstr "外部ツール"
-#: spyder/app/mainwindow.py:716
+#: spyder/app/mainwindow.py:723
msgid "WinPython control panel"
msgstr "WinPythonコントロールパネル"
-#: spyder/app/mainwindow.py:725
+#: spyder/app/mainwindow.py:733
msgid "Qt Designer"
msgstr "Qt Designer"
-#: spyder/app/mainwindow.py:730
+#: spyder/app/mainwindow.py:737
msgid "Qt Linguist"
msgstr "Qt Linguist"
-#: spyder/app/mainwindow.py:736
-msgid "Qt examples"
-msgstr "Qt examples"
-
-#: spyder/app/mainwindow.py:756
+#: spyder/app/mainwindow.py:758
msgid "guidata examples"
msgstr "guidata examples"
-#: spyder/app/mainwindow.py:767
+#: spyder/app/mainwindow.py:769
msgid "guiqwt examples"
msgstr "guiqwt examples"
-#: spyder/app/mainwindow.py:772
+#: spyder/app/mainwindow.py:774
msgid "Sift"
msgstr "選別する"
-#: spyder/app/mainwindow.py:782
-msgid "ViTables"
-msgstr "Viテーブル"
-
-#: spyder/app/mainwindow.py:796
+#: spyder/app/mainwindow.py:792
msgid "Fullscreen mode"
msgstr "フルスクリーンモード"
-#: spyder/app/mainwindow.py:808
+#: spyder/app/mainwindow.py:804
msgid "Main toolbar"
msgstr "メインツールバー"
-#: spyder/app/mainwindow.py:817
+#: spyder/app/mainwindow.py:813
msgid ""
"Spyder Internal Console\n"
"\n"
@@ -308,167 +299,172 @@ msgstr ""
"ユーザーのpythonコードを実行するために使わないでください。\n"
"\n"
-#: spyder/app/mainwindow.py:834
+#: spyder/app/mainwindow.py:830
msgid "Loading help..."
msgstr "ヘルプをロードしています..."
-#: spyder/app/mainwindow.py:841
+#: spyder/app/mainwindow.py:837
msgid "Loading outline explorer..."
msgstr "アウトラインエクスプローラーをロードしています..."
-#: spyder/app/mainwindow.py:847
+#: spyder/app/mainwindow.py:843
msgid "Loading editor..."
msgstr "エディタをロードしています..."
-#: spyder/app/mainwindow.py:853 spyder/plugins/console.py:141
-#: spyder/widgets/ipythonconsole/client.py:414
+#: spyder/app/mainwindow.py:849 spyder/plugins/console.py:141
+#: spyder/widgets/ipythonconsole/client.py:453
msgid "&Quit"
msgstr "終了(&Q)"
-#: spyder/app/mainwindow.py:855 spyder/plugins/console.py:143
+#: spyder/app/mainwindow.py:851 spyder/plugins/console.py:143
msgid "Quit"
msgstr "終了"
-#: spyder/app/mainwindow.py:859
+#: spyder/app/mainwindow.py:855
msgid "&Restart"
msgstr "再起動(&R)"
-#: spyder/app/mainwindow.py:861
+#: spyder/app/mainwindow.py:857
msgid "Restart"
msgstr "再起動"
-#: spyder/app/mainwindow.py:875
+#: spyder/app/mainwindow.py:871
msgid "Loading file explorer..."
msgstr "ファイルエクスプローラーをロードしています..."
-#: spyder/app/mainwindow.py:882
+#: spyder/app/mainwindow.py:878
msgid "Loading history plugin..."
msgstr "ヒストリプラグインをロードしています..."
-#: spyder/app/mainwindow.py:893
+#: spyder/app/mainwindow.py:889
msgid "Loading online help..."
msgstr "オンラインヘルプをロードしています..."
-#: spyder/app/mainwindow.py:898
+#: spyder/app/mainwindow.py:894
msgid "Loading project explorer..."
msgstr "プロジェクトエクスプローラーをロード中..."
-#: spyder/app/mainwindow.py:911
+#: spyder/app/mainwindow.py:907
msgid "Loading namespace browser..."
msgstr "名前空間ブラウザをロード中..."
-#: spyder/app/mainwindow.py:917
+#: spyder/app/mainwindow.py:913
msgid "Loading IPython console..."
msgstr "IPythonコンソールをロード中..."
-#: spyder/app/mainwindow.py:922
+#: spyder/app/mainwindow.py:918
msgid "Setting up main window..."
msgstr "メインウインドウを設定中..."
-#: spyder/app/mainwindow.py:926
+#: spyder/app/mainwindow.py:922
msgid "Troubleshooting..."
msgstr "トラブルシュート..."
-#: spyder/app/mainwindow.py:928
+#: spyder/app/mainwindow.py:924
msgid "Dependencies..."
msgstr "依存性..."
-#: spyder/app/mainwindow.py:932
+#: spyder/app/mainwindow.py:928
msgid "Report issue..."
msgstr "問題をレポート..."
-#: spyder/app/mainwindow.py:936
+#: spyder/app/mainwindow.py:932
msgid "Spyder support..."
msgstr "Spyderサポート..."
-#: spyder/app/mainwindow.py:939
+#: spyder/app/mainwindow.py:935
msgid "Check for updates..."
msgstr "更新をチェック..."
-#: spyder/app/mainwindow.py:962
+#: spyder/app/mainwindow.py:940
msgid "Spyder documentation"
msgstr "spyderドキュメント"
-#: spyder/app/mainwindow.py:970
+#: spyder/app/mainwindow.py:948
msgid "Spyder tutorial"
msgstr "Spyderチュートリアル"
-#: spyder/app/mainwindow.py:975
+#: spyder/app/mainwindow.py:953
msgid "Shortcuts Summary"
msgstr "ショートカットサマリー"
-#: spyder/app/mainwindow.py:981
+#: spyder/app/mainwindow.py:959
msgid "Interactive tours"
msgstr "インタラクティブツアー"
-#: spyder/app/mainwindow.py:1008
+#: spyder/app/mainwindow.py:986
msgid "Python documentation"
msgstr "Pythonドキュメント"
-#: spyder/app/mainwindow.py:1014
+#: spyder/app/mainwindow.py:992
msgid "IPython documentation"
msgstr "IPythonドキュメント"
-#: spyder/app/mainwindow.py:1015
+#: spyder/app/mainwindow.py:993
msgid "Intro to IPython"
msgstr "IPythonの紹介"
-#: spyder/app/mainwindow.py:1017
+#: spyder/app/mainwindow.py:995
msgid "Quick reference"
msgstr "クイックリファレンス"
-#: spyder/app/mainwindow.py:1019
+#: spyder/app/mainwindow.py:997
msgid "Console help"
msgstr "コンソールヘルプ"
-#: spyder/app/mainwindow.py:1049
+#: spyder/app/mainwindow.py:1027
msgid "Installed Python modules"
msgstr "インストールされたPythonモジュール"
-#: spyder/app/mainwindow.py:1053
+#: spyder/app/mainwindow.py:1031
msgid "Online documentation"
msgstr "オンラインドキュメント"
-#: spyder/app/mainwindow.py:1066
+#: spyder/app/mainwindow.py:1044
msgid "Qt documentation"
msgstr "Qtドキュメント"
-#: spyder/app/mainwindow.py:1072
+#: spyder/app/mainwindow.py:1050
msgid "About %s..."
msgstr "%s について..."
-#: spyder/app/mainwindow.py:1103
+#: spyder/app/mainwindow.py:1081
msgid "Panes"
msgstr "ペイン"
-#: spyder/app/mainwindow.py:1105
+#: spyder/app/mainwindow.py:1083
msgid "Toolbars"
msgstr "ツールバー"
-#: spyder/app/mainwindow.py:1106
+#: spyder/app/mainwindow.py:1084
msgid "Window layouts"
msgstr "ウインドウレイアウト"
-#: spyder/app/mainwindow.py:1115 spyder/app/mainwindow.py:1943
-#: spyder/app/mainwindow.py:1944
+#: spyder/app/mainwindow.py:1093 spyder/app/mainwindow.py:1920
+#: spyder/app/mainwindow.py:1921
msgid "Show toolbars"
msgstr "ツールバーを表示"
-#: spyder/app/mainwindow.py:1130
+#: spyder/app/mainwindow.py:1108
msgid "Attached console window (debugging)"
msgstr "接続されたコンソールウインドウ(デバッグ)"
-#: spyder/app/mainwindow.py:1322 spyder/plugins/projects.py:254
-#: spyder/widgets/explorer.py:721 spyder/widgets/explorer.py:826
-#: spyder/widgets/variableexplorer/arrayeditor.py:587
-#: spyder/widgets/variableexplorer/collectionseditor.py:427
-#: spyder/widgets/variableexplorer/dataframeeditor.py:758
-#: spyder/widgets/variableexplorer/dataframeeditor.py:762
-#: spyder/widgets/variableexplorer/namespacebrowser.py:299
+#: spyder/app/mainwindow.py:1298 spyder/app/mainwindow.py:1988
+#: spyder/plugins/configdialog.py:1154 spyder/plugins/projects.py:269
+#: spyder/widgets/explorer.py:723 spyder/widgets/explorer.py:828
+#: spyder/widgets/reporterror.py:285
+#: spyder/widgets/variableexplorer/arrayeditor.py:586
+#: spyder/widgets/variableexplorer/collectionseditor.py:460
+#: spyder/widgets/variableexplorer/dataframeeditor.py:797
+#: spyder/plugins/pylint/widgets/pylintgui.py:128
+#: spyder/widgets/variableexplorer/namespacebrowser.py:311
+#: spyder/plugins/pylint/widgets/pylintgui.py:363
+#: spyder/plugins/pylint/widgets/pylintgui.py:391
+#: spyder/plugins/profiler/widgets/profilergui.py:295
msgid "Error"
msgstr "エラー"
-#: spyder/app/mainwindow.py:1323
+#: spyder/app/mainwindow.py:1299
msgid ""
"You have missing dependencies!
%s
Please "
"install them to avoid this message.
Note: Spyder could "
@@ -486,38 +482,41 @@ msgstr ""
"新しい問題を報告する前には、発生した不具合が依存性の欠如によるものではないこ"
"とを確認してください。"
-#: spyder/app/mainwindow.py:1779
+#: spyder/app/mainwindow.py:1756
msgid "Spyder Default Layout"
msgstr "Spyderデフォルトレイアウト"
-#: spyder/app/mainwindow.py:1797
+#: spyder/app/mainwindow.py:1774
msgid "Save current layout"
msgstr "現在のレイアウトを保存"
-#: spyder/app/mainwindow.py:1801
+#: spyder/app/mainwindow.py:1778
msgid "Layout preferences"
msgstr "レイアウト設定"
-#: spyder/app/mainwindow.py:1805
+#: spyder/app/mainwindow.py:1782
msgid "Reset to spyder default"
msgstr "Spyderのデフォルト値に戻す"
-#: spyder/app/mainwindow.py:1825 spyder/app/mainwindow.py:1847
-#: spyder/app/mainwindow.py:1913 spyder/app/mainwindow.py:1921
-#: spyder/app/mainwindow.py:2799 spyder/plugins/configdialog.py:1345
-#: spyder/plugins/ipythonconsole.py:131 spyder/plugins/ipythonconsole.py:927
-#: spyder/plugins/ipythonconsole.py:1386 spyder/plugins/maininterpreter.py:149
-#: spyder/plugins/maininterpreter.py:174 spyder/plugins/maininterpreter.py:203
-#: spyder/utils/environ.py:95 spyder/utils/environ.py:108
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:131
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:149
-#: spyder/widgets/variableexplorer/arrayeditor.py:510
-#: spyder/widgets/variableexplorer/collectionseditor.py:416
-#: spyder/widgets/variableexplorer/collectionseditor.py:1095
+#: spyder/app/mainwindow.py:1802 spyder/app/mainwindow.py:1824
+#: spyder/app/mainwindow.py:1890 spyder/app/mainwindow.py:1898
+#: spyder/app/mainwindow.py:2843 spyder/plugins/configdialog.py:1415
+#: spyder/plugins/ipythonconsole.py:134 spyder/plugins/ipythonconsole.py:987
+#: spyder/plugins/ipythonconsole.py:1439 spyder/plugins/maininterpreter.py:162
+#: spyder/plugins/maininterpreter.py:183 spyder/plugins/maininterpreter.py:212
+#: spyder/utils/environ.py:56 spyder/utils/environ.py:107
+#: spyder/utils/environ.py:120
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:140
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:158
+#: spyder/widgets/variableexplorer/arrayeditor.py:508
+#: spyder/widgets/variableexplorer/collectionseditor.py:449
+#: spyder/plugins/pylint/widgets/pylintgui.py:126
+#: spyder/widgets/variableexplorer/collectionseditor.py:1143
+#: spyder/widgets/variableexplorer/namespacebrowser.py:305
msgid "Warning"
msgstr "警告"
-#: spyder/app/mainwindow.py:1826
+#: spyder/app/mainwindow.py:1803
msgid ""
"Window layout will be reset to default settings: this affects window "
"position, size and dockwidgets.\n"
@@ -527,7 +526,7 @@ msgstr ""
"ズ及びドックウィジェットが影響されます。\n"
"続行しますか?"
-#: spyder/app/mainwindow.py:1848
+#: spyder/app/mainwindow.py:1825
msgid ""
"Layout %s will be "
"overwritten. Do you want to "
@@ -536,7 +535,7 @@ msgstr ""
"レイアウト %sは 上書き"
"されます。 続行しますか?"
-#: spyder/app/mainwindow.py:1914
+#: spyder/app/mainwindow.py:1891
msgid ""
"Error opening the custom layout. Please close Spyder and try again. If the "
"issue persists, then you must use 'Reset to Spyder default' from the layout "
@@ -546,57 +545,65 @@ msgstr ""
"て下さい。この問題が解決しない場合、レイアウトメニューから「Spyderのデフォル"
"ト値に戻す」を選択して下さい。"
-#: spyder/app/mainwindow.py:1922
+#: spyder/app/mainwindow.py:1899
msgid "Quick switch layout #%s has not yet been defined."
msgstr "クイックスイッチレイアウト #%s は未定義です。"
-#: spyder/app/mainwindow.py:1940 spyder/app/mainwindow.py:1941
+#: spyder/app/mainwindow.py:1917 spyder/app/mainwindow.py:1918
msgid "Hide toolbars"
msgstr "ツールバーを隠す"
-#: spyder/app/mainwindow.py:2256 spyder/app/mainwindow.py:2257
+#: spyder/app/mainwindow.py:1989
+msgid ""
+"{} is no longer a valid Spyder project! Since it is the current "
+"active project, it will be closed automatically."
+msgstr ""
+"{} はもはやSpyderプロジェクトではありません!現在のアクティブプロジェ"
+"クトであるため自動的に閉じられます。"
+
+#: spyder/app/mainwindow.py:2252 spyder/app/mainwindow.py:2253
msgid "Maximize current pane"
msgstr "現在のペインを最大化"
-#: spyder/app/mainwindow.py:2260
+#: spyder/app/mainwindow.py:2256
msgid "Restore current pane"
msgstr "現在のペインを復元"
-#: spyder/app/mainwindow.py:2261
+#: spyder/app/mainwindow.py:2257
msgid "Restore pane to its original size"
msgstr "ペインをオリジナルサイズに復元"
-#: spyder/app/mainwindow.py:2359
+#: spyder/app/mainwindow.py:2439
msgid "About %s"
msgstr "%s について"
-#: spyder/app/mainwindow.py:2538 spyder/plugins/editor.py:168
+#: spyder/app/mainwindow.py:2579 spyder/plugins/editor.py:168
#: spyder/plugins/runconfig.py:354 spyder/plugins/runconfig.py:476
-#: spyder/utils/programs.py:286 spyder/widgets/explorer.py:344
+#: spyder/utils/programs.py:307 spyder/widgets/explorer.py:347
msgid "Run"
msgstr "実行"
-#: spyder/app/mainwindow.py:2539
+#: spyder/app/mainwindow.py:2580
msgid "Running an external system terminal is not supported on platform %s."
msgstr ""
"プラットフォーム %s では外部システムターミナルの実行はサポートされていませ"
"ん。"
-#: spyder/app/mainwindow.py:2800
+#: spyder/app/mainwindow.py:2844
msgid ""
"Spyder will restart and reset to default settings:
Do you want to "
"continue?"
msgstr "Spyderを再起動して設定をデフォルトに戻します:
続行しますか?"
-#: spyder/app/mainwindow.py:2928 spyder/widgets/helperwidgets.py:254
+#: spyder/app/mainwindow.py:2973 spyder/widgets/helperwidgets.py:254
msgid "Spyder updates"
msgstr "Spyderアップデート"
-#: spyder/app/mainwindow.py:2929 spyder/plugins/configdialog.py:835
+#: spyder/app/mainwindow.py:2974 spyder/plugins/configdialog.py:888
msgid "Check for updates on startup"
msgstr "起動時に更新をチェック"
-#: spyder/app/mainwindow.py:2948
+#: spyder/app/mainwindow.py:2993
msgid ""
"
IMPORTANT NOTE: It seems that you are using Spyder with "
"Anaconda/Miniconda. Please don't use pip
to "
@@ -610,7 +617,7 @@ msgstr ""
"パッケージが利用できるまで待ち、conda
を使ってアップデートして下"
"さい。
"
-#: spyder/app/mainwindow.py:2958
+#: spyder/app/mainwindow.py:3003
msgid ""
"Spyder %s is available!
Please use your package manager to "
"update Spyder or go to our Releases page to download this "
@@ -622,7 +629,7 @@ msgstr ""
"new version.
If you are not sure how to proceed to update Spyder "
"please refer to our Installation instructions."
-#: spyder/app/mainwindow.py:2971
+#: spyder/app/mainwindow.py:3016
msgid "Spyder is up to date."
msgstr "Spyderは最新の状態です。"
@@ -751,8 +758,8 @@ msgstr ""
"ブルクリックすると新しいウィンドウが開き、変数の中身を調査したり変更したりす"
"ることができます。"
-#: spyder/app/tour.py:179 spyder/plugins/help.py:484 spyder/plugins/help.py:937
-#: spyder/widgets/internalshell.py:270
+#: spyder/app/tour.py:179 spyder/plugins/help.py:482 spyder/plugins/help.py:931
+#: spyder/widgets/internalshell.py:271
msgid "Help"
msgstr "ヘルプ"
@@ -820,7 +827,7 @@ msgstr "紹介ツアー"
msgid "New features in version 3.0"
msgstr "バージョン3.0の新機能"
-#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:446
+#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:474
msgid "Run code"
msgstr "コードを実行"
@@ -828,207 +835,205 @@ msgstr "コードを実行"
msgid "Go to step: "
msgstr "ステップへ移動"
-#: spyder/config/base.py:269
-msgid ""
-"Update LANGUAGE_CODES (inside config/base.py) if a new translation has been "
-"added to Spyder"
-msgstr ""
-"新しい翻訳がSpyderに追加された場合LANGUAGE_CODES (config/base.py内)を更新"
-
-#: spyder/config/utils.py:24
+#: spyder/config/utils.py:24 spyder/plugins/pylint/widgets/pylintgui.py:289
msgid "Python files"
msgstr "Pythonファイル"
-#: spyder/config/utils.py:25
+#: spyder/config/utils.py:26
msgid "Cython/Pyrex files"
msgstr "Cython/Pyrexファイル"
-#: spyder/config/utils.py:26
+#: spyder/config/utils.py:27
msgid "C files"
msgstr "Cファイル"
-#: spyder/config/utils.py:27
+#: spyder/config/utils.py:28
msgid "C++ files"
msgstr "C++ファイル"
-#: spyder/config/utils.py:28
+#: spyder/config/utils.py:29
msgid "OpenCL files"
msgstr "OpenCLファイル"
-#: spyder/config/utils.py:29
+#: spyder/config/utils.py:30
msgid "Fortran files"
msgstr "Fortranファイル"
-#: spyder/config/utils.py:30
+#: spyder/config/utils.py:31
msgid "IDL files"
msgstr "IDLファイル"
-#: spyder/config/utils.py:31
+#: spyder/config/utils.py:32
msgid "MATLAB files"
msgstr "MATLABファイル"
-#: spyder/config/utils.py:32
+#: spyder/config/utils.py:33
msgid "Julia files"
msgstr "Juliaファイル"
-#: spyder/config/utils.py:33
+#: spyder/config/utils.py:34
msgid "Yaml files"
msgstr "Yamlファイル"
-#: spyder/config/utils.py:34
+#: spyder/config/utils.py:35
msgid "Patch and diff files"
msgstr "Patch and diffファイル"
-#: spyder/config/utils.py:35
+#: spyder/config/utils.py:36
msgid "Batch files"
msgstr "Batchファイル"
-#: spyder/config/utils.py:36 spyder/utils/iofuncs.py:426
+#: spyder/config/utils.py:37
msgid "Text files"
msgstr "テキストファイル"
-#: spyder/config/utils.py:37
+#: spyder/config/utils.py:38
msgid "reStructuredText files"
msgstr "reStructuredTextファイル"
-#: spyder/config/utils.py:38
+#: spyder/config/utils.py:39
msgid "gettext files"
msgstr "gettextファイル"
-#: spyder/config/utils.py:39
+#: spyder/config/utils.py:40
msgid "NSIS files"
msgstr "NSISファイル"
-#: spyder/config/utils.py:40
+#: spyder/config/utils.py:41
msgid "Web page files"
msgstr "Webページファイル"
-#: spyder/config/utils.py:41
+#: spyder/config/utils.py:42
msgid "XML files"
msgstr "XMLファイル"
-#: spyder/config/utils.py:42
+#: spyder/config/utils.py:43
msgid "Javascript files"
msgstr "Javascriptファイル"
-#: spyder/config/utils.py:43
+#: spyder/config/utils.py:44
msgid "Json files"
msgstr "Jsonファイル"
-#: spyder/config/utils.py:44
+#: spyder/config/utils.py:45
msgid "IPython notebooks"
msgstr "IPython notebooks"
-#: spyder/config/utils.py:45
+#: spyder/config/utils.py:46
msgid "Enaml files"
msgstr "Enamlファイル"
-#: spyder/config/utils.py:46
+#: spyder/config/utils.py:47
msgid "Configuration files"
msgstr "Configurationファイル"
-#: spyder/config/utils.py:48
+#: spyder/config/utils.py:49
msgid "Markdown files"
msgstr "Markdownファイル"
-#: spyder/config/utils.py:52 spyder/widgets/explorer.py:794
+#: spyder/config/utils.py:53 spyder/widgets/explorer.py:796
msgid "All files"
msgstr "すべてのファイル"
-#: spyder/config/utils.py:134
+#: spyder/config/utils.py:138
msgid "Supported text files"
msgstr "サポートされたテキストファイル"
-#: spyder/plugins/__init__.py:511 spyder/plugins/editor.py:105
-#: spyder/plugins/editor.py:568 spyder/plugins/editor.py:1816
-#: spyder/plugins/help.py:117 spyder/plugins/help.py:385
-#: spyder/widgets/editor.py:534 spyder/widgets/sourcecode/codeeditor.py:98
-#: spyder/widgets/sourcecode/codeeditor.py:3222
+#: spyder/plugins/__init__.py:512 spyder/plugins/editor.py:105
+#: spyder/plugins/editor.py:568 spyder/plugins/editor.py:1830
+#: spyder/plugins/help.py:117 spyder/plugins/help.py:383
+#: spyder/widgets/editor.py:544 spyder/widgets/sourcecode/codeeditor.py:98
+#: spyder/widgets/sourcecode/codeeditor.py:3229
msgid "Editor"
msgstr "エディタ"
-#: spyder/plugins/configdialog.py:144
+#: spyder/plugins/configdialog.py:146
msgid "Reset to defaults"
msgstr "デフォルト設定へ戻す"
-#: spyder/plugins/configdialog.py:156
+#: spyder/plugins/configdialog.py:158
msgid "Preferences"
msgstr "設定"
-#: spyder/plugins/configdialog.py:508
+#: spyder/plugins/configdialog.py:514
msgid "Invalid directory path"
msgstr "不正なディレクトリパス"
-#: spyder/plugins/configdialog.py:511 spyder/plugins/configdialog.py:526
+#: spyder/plugins/configdialog.py:517 spyder/plugins/configdialog.py:532
#: spyder/plugins/runconfig.py:220 spyder/plugins/runconfig.py:268
-#: spyder/plugins/workingdirectory.py:240 spyder/widgets/explorer.py:705
-#: spyder/widgets/findinfiles.py:332 spyder/widgets/pathmanager.py:258
+#: spyder/plugins/workingdirectory.py:241 spyder/widgets/explorer.py:707
+#: spyder/widgets/findinfiles.py:347 spyder/widgets/pathmanager.py:259
#: spyder/widgets/projects/projectdialog.py:155
msgid "Select directory"
msgstr "ディレクトリを選択"
-#: spyder/plugins/configdialog.py:538
+#: spyder/plugins/configdialog.py:544 spyder/plugins/configdialog.py:704
msgid "Invalid file path"
msgstr "不正なファイルパス"
-#: spyder/plugins/configdialog.py:541 spyder/plugins/configdialog.py:558
+#: spyder/plugins/configdialog.py:547 spyder/plugins/configdialog.py:564
+#: spyder/plugins/configdialog.py:707
msgid "Select file"
msgstr "ファイル選択"
-#: spyder/plugins/configdialog.py:557
+#: spyder/plugins/configdialog.py:563
msgid "All files (*)"
msgstr "全てのファイル (*)"
-#: spyder/plugins/configdialog.py:630
+#: spyder/plugins/configdialog.py:636
msgid "Bold"
msgstr "ボールド"
-#: spyder/plugins/configdialog.py:633
+#: spyder/plugins/configdialog.py:639
msgid "Italic"
msgstr "イタリック"
-#: spyder/plugins/configdialog.py:687
+#: spyder/plugins/configdialog.py:728
msgid "Font: "
msgstr "フォント:"
-#: spyder/plugins/configdialog.py:693
+#: spyder/plugins/configdialog.py:734
msgid "Size: "
msgstr "サイズ:"
-#: spyder/plugins/configdialog.py:712
+#: spyder/plugins/configdialog.py:753
msgid "Font style"
msgstr "フォントスタイル"
-#: spyder/plugins/configdialog.py:789
+#: spyder/plugins/configdialog.py:830
msgid "Spyder needs to restart to change the following setting:"
-msgstr "Spyderは以下の設定を適用するために再起動が必要となります:"
+msgstr "以下の設定を適用するために再起動が必要となります:"
-#: spyder/plugins/configdialog.py:792
+#: spyder/plugins/configdialog.py:833
msgid "Spyder needs to restart to change the following settings:"
-msgstr "Spyderは以下の設定を適用するために再起動が必要となります:"
+msgstr "以下の設定を適用するために再起動が必要となります:"
-#: spyder/plugins/configdialog.py:794
+#: spyder/plugins/configdialog.py:835
msgid "Do you wish to restart now?"
msgstr "直ちに再起動しますか?"
-#: spyder/plugins/configdialog.py:800
+#: spyder/plugins/configdialog.py:841
msgid "Information"
msgstr "情報"
-#: spyder/plugins/configdialog.py:814 spyder/plugins/configdialog.py:821
+#: spyder/plugins/configdialog.py:855 spyder/plugins/configdialog.py:862
#: spyder/widgets/projects/configdialog.py:74
msgid "General"
msgstr "一般"
-#: spyder/plugins/configdialog.py:824
-msgid "Language"
-msgstr "言語"
+#: spyder/plugins/configdialog.py:866
+msgid "Language:"
+msgstr "言語:"
+
+#: spyder/plugins/configdialog.py:874
+msgid "Rendering engine:"
+msgstr "レンダリングエンジン:"
-#: spyder/plugins/configdialog.py:827
+#: spyder/plugins/configdialog.py:879
msgid "Use a single instance"
msgstr "単一インスタンスを使用"
-#: spyder/plugins/configdialog.py:829
+#: spyder/plugins/configdialog.py:881
msgid ""
"Set this to open external
Python files in an already running instance "
"(Requires a restart)"
@@ -1036,90 +1041,90 @@ msgstr ""
"外部Pythonファイルを実行中の
インスタンスで開くためにこれをセット (再起動"
"が必要)"
-#: spyder/plugins/configdialog.py:832
+#: spyder/plugins/configdialog.py:885
msgid "Prompt when exiting"
msgstr "終了時に確認する"
-#: spyder/plugins/configdialog.py:833
+#: spyder/plugins/configdialog.py:886
msgid "Show internal Spyder errors to report them to Github"
msgstr "GithubにレポートするためにSpyderの内部エラーを表示"
-#: spyder/plugins/configdialog.py:852 spyder/plugins/editor.py:114
-#: spyder/plugins/ipythonconsole.py:290
+#: spyder/plugins/configdialog.py:914 spyder/plugins/editor.py:114
+#: spyder/plugins/ipythonconsole.py:301
#: spyder/widgets/projects/configdialog.py:81
msgid "Interface"
msgstr "インターフェイス"
-#: spyder/plugins/configdialog.py:860
+#: spyder/plugins/configdialog.py:922
msgid "Qt windows style"
msgstr "Qt windowスタイル"
-#: spyder/plugins/configdialog.py:866
+#: spyder/plugins/configdialog.py:928
msgid "Icon theme"
msgstr "アイコンテーマ"
-#: spyder/plugins/configdialog.py:870
+#: spyder/plugins/configdialog.py:932
msgid "Vertical title bars in panes"
msgstr "ペインのタイトルバーを縦にする"
-#: spyder/plugins/configdialog.py:872
+#: spyder/plugins/configdialog.py:934
msgid "Vertical tabs in panes"
msgstr "ペインのタブを縦にする"
-#: spyder/plugins/configdialog.py:874
+#: spyder/plugins/configdialog.py:936
msgid "Animated toolbars and panes"
msgstr "ツールバーとペインをアニメーションさせる"
-#: spyder/plugins/configdialog.py:876
+#: spyder/plugins/configdialog.py:938
msgid "Tear off menus"
msgstr "メニューを切り離す"
-#: spyder/plugins/configdialog.py:877
+#: spyder/plugins/configdialog.py:939
msgid "Set this to detach any
menu from the main window"
msgstr "メインウインドウから
メニューを切り離すために設定する"
-#: spyder/plugins/configdialog.py:879
+#: spyder/plugins/configdialog.py:941
msgid "Custom margin for panes:"
msgstr "ペインのマージン調整"
-#: spyder/plugins/configdialog.py:881
+#: spyder/plugins/configdialog.py:943
msgid "pixels"
msgstr "ピクセル"
-#: spyder/plugins/configdialog.py:888
+#: spyder/plugins/configdialog.py:950
msgid "Cursor blinking:"
msgstr "カーソルの点滅:"
-#: spyder/plugins/configdialog.py:890
+#: spyder/plugins/configdialog.py:952
msgid "ms"
msgstr "ms"
-#: spyder/plugins/configdialog.py:929
+#: spyder/plugins/configdialog.py:991
msgid "Status bar"
msgstr "ステータスバー"
-#: spyder/plugins/configdialog.py:930
+#: spyder/plugins/configdialog.py:992
msgid "Show status bar"
msgstr "ステータスバーを表示"
-#: spyder/plugins/configdialog.py:932
+#: spyder/plugins/configdialog.py:994
msgid "Show memory usage every"
msgstr "メモリ使用状況を以下の間隔で更新"
-#: spyder/plugins/configdialog.py:934 spyder/plugins/configdialog.py:943
+#: spyder/plugins/configdialog.py:996 spyder/plugins/configdialog.py:1005
#: spyder/plugins/editor.py:139 spyder/plugins/editor.py:283
msgid " ms"
msgstr "ms"
-#: spyder/plugins/configdialog.py:941
+#: spyder/plugins/configdialog.py:1003
msgid "Show CPU usage every"
msgstr "CPU使用状況を以下の間隔で更新"
-#: spyder/plugins/configdialog.py:974
+#: spyder/plugins/configdialog.py:1036
msgid "Screen resolution"
msgstr "スクリーン解像度:"
-#: spyder/plugins/configdialog.py:976
+#: spyder/plugins/configdialog.py:1038
msgid ""
"Configuration for high DPI screens
Please see {0}"
"a><> for more information about these options (in English)."
@@ -1127,59 +1132,67 @@ msgstr ""
"高DPIスクリーン設定
これらのオプションのより詳細な情報は以下を参照して"
"下さい {0}<>."
-#: spyder/plugins/configdialog.py:986
+#: spyder/plugins/configdialog.py:1048
msgid "Normal"
msgstr "通常"
-#: spyder/plugins/configdialog.py:990
+#: spyder/plugins/configdialog.py:1052
msgid "Enable auto high DPI scaling"
msgstr "高DPIスケーリング自動設定を有効化"
-#: spyder/plugins/configdialog.py:993
+#: spyder/plugins/configdialog.py:1055
msgid "Set this for high DPI displays"
msgstr "高DPIディスプレイ用にセットする"
-#: spyder/plugins/configdialog.py:997
+#: spyder/plugins/configdialog.py:1059
msgid "Set a custom high DPI scaling"
msgstr "カスタム高DPIスケーリングを設定"
-#: spyder/plugins/configdialog.py:1000
+#: spyder/plugins/configdialog.py:1062
msgid "Set this for high DPI displays when auto scaling does not work"
msgstr ""
"自動スケーリングが動作しない場合、高DPIディスプレイ用にこの設定を適用する。"
-#: spyder/plugins/configdialog.py:1006
+#: spyder/plugins/configdialog.py:1068
msgid ""
"Enter values for different screens separated by semicolons ';', float values "
"are supported"
msgstr ""
"他のスクリーンの値(小数点表記も可)をセミコロン';'で区切って入力して下さい。"
-#: spyder/plugins/configdialog.py:1033
+#: spyder/plugins/configdialog.py:1095
msgid "Plain text font"
msgstr "プレーンテキスト"
-#: spyder/plugins/configdialog.py:1039
+#: spyder/plugins/configdialog.py:1101
msgid "Rich text font"
msgstr "リッチテキスト"
-#: spyder/plugins/configdialog.py:1042
+#: spyder/plugins/configdialog.py:1104
msgid "Fonts"
msgstr "フォント"
-#: spyder/plugins/configdialog.py:1056
+#: spyder/plugins/configdialog.py:1118
msgid "Appearance"
msgstr "外見"
-#: spyder/plugins/configdialog.py:1058 spyder/plugins/ipythonconsole.py:579
+#: spyder/plugins/configdialog.py:1120 spyder/plugins/ipythonconsole.py:633
msgid "Advanced Settings"
msgstr "詳細設定"
-#: spyder/plugins/configdialog.py:1094
+#: spyder/plugins/configdialog.py:1155
+msgid ""
+"We're sorry but the following error occurred while trying to set your "
+"selected language:
{}"
+msgstr ""
+"申し訳ありません。言語を設定中に以下のエラーが発生しました:
{}"
+"tt>"
+
+#: spyder/plugins/configdialog.py:1164
msgid "Syntax coloring"
msgstr "構文強調の配色"
-#: spyder/plugins/configdialog.py:1107
+#: spyder/plugins/configdialog.py:1177
msgid ""
"Here you can select the color scheme used in the Editor and all other Spyder "
"plugins.
You can also edit the color schemes provided by Spyder or "
@@ -1189,52 +1202,52 @@ msgstr ""
"
以下のオプションにより定義済みの色スキームの編集及び独自色スキーム作"
"成が実行できます。
"
-#: spyder/plugins/configdialog.py:1112
+#: spyder/plugins/configdialog.py:1182
msgid "Edit selected"
msgstr "選択を編集"
-#: spyder/plugins/configdialog.py:1113
+#: spyder/plugins/configdialog.py:1183
msgid "Create new scheme"
msgstr "新しいスキームを作成"
-#: spyder/plugins/configdialog.py:1114 spyder/widgets/explorer.py:583
+#: spyder/plugins/configdialog.py:1184 spyder/widgets/explorer.py:582
#: spyder/widgets/projects/explorer.py:243 spyder/widgets/shell.py:136
msgid "Delete"
msgstr "削除"
-#: spyder/plugins/configdialog.py:1117
+#: spyder/plugins/configdialog.py:1187
msgid "Reset"
msgstr "リセット"
-#: spyder/plugins/configdialog.py:1124
+#: spyder/plugins/configdialog.py:1194
msgid "Scheme:"
msgstr "スキーム:"
-#: spyder/plugins/configdialog.py:1155
+#: spyder/plugins/configdialog.py:1225
msgid "Manage color schemes"
msgstr "色スキームのマネージ"
-#: spyder/plugins/configdialog.py:1346
+#: spyder/plugins/configdialog.py:1416
msgid "Are you sure you want to delete this scheme?"
msgstr "本当にこのスキームを削除しますか?"
-#: spyder/plugins/configdialog.py:1463
+#: spyder/plugins/configdialog.py:1533
msgid "Text"
msgstr "テキスト"
-#: spyder/plugins/configdialog.py:1465
+#: spyder/plugins/configdialog.py:1535
msgid "Highlight"
msgstr "強調"
-#: spyder/plugins/configdialog.py:1467
+#: spyder/plugins/configdialog.py:1537
msgid "Background"
msgstr "背景"
-#: spyder/plugins/configdialog.py:1471
+#: spyder/plugins/configdialog.py:1541
msgid "Scheme name:"
msgstr "スキーム名:"
-#: spyder/plugins/configdialog.py:1478
+#: spyder/plugins/configdialog.py:1548
msgid "Color scheme editor"
msgstr "色スキームエディタ"
@@ -1270,7 +1283,7 @@ msgstr "sys.pathを読み取り専用で表示"
msgid "Buffer..."
msgstr "バッファー..."
-#: spyder/plugins/console.py:163 spyder/plugins/history.py:43
+#: spyder/plugins/console.py:163 spyder/plugins/history.py:45
msgid "Set maximum line count"
msgstr "最大行数を設定"
@@ -1283,13 +1296,13 @@ msgid "Set external editor executable path"
msgstr "外部エディタ実行パスを設定"
#: spyder/plugins/console.py:170 spyder/plugins/editor.py:149
-#: spyder/plugins/help.py:152 spyder/plugins/help.py:360
-#: spyder/plugins/history.py:46 spyder/plugins/history.py:157
+#: spyder/plugins/help.py:152 spyder/plugins/help.py:358
+#: spyder/plugins/history.py:48 spyder/plugins/history.py:159
msgid "Wrap lines"
msgstr "行の折り返し"
#: spyder/plugins/console.py:173 spyder/plugins/editor.py:185
-#: spyder/plugins/ipythonconsole.py:300
+#: spyder/plugins/ipythonconsole.py:311
msgid "Display balloon tips"
msgstr "バルーンチップを表示"
@@ -1309,7 +1322,8 @@ msgstr "内部コンソール設定"
msgid "Run Python script"
msgstr "Pythonスクリプトを実行"
-#: spyder/plugins/console.py:266 spyder/widgets/explorer.py:809
+#: spyder/plugins/console.py:266 spyder/widgets/explorer.py:811
+#: spyder/plugins/profiler/widgets/profilergui.py:220
msgid "Python scripts"
msgstr "Pythonスクリプト"
@@ -1342,8 +1356,8 @@ msgid "Show tab bar"
msgstr "タブバーを表示"
#: spyder/plugins/editor.py:122 spyder/plugins/editor.py:199
-#: spyder/plugins/help.py:151 spyder/plugins/history.py:45
-#: spyder/plugins/ipythonconsole.py:332
+#: spyder/plugins/help.py:151 spyder/plugins/history.py:47
+#: spyder/plugins/ipythonconsole.py:349
msgid "Source code"
msgstr "ソースコード"
@@ -1369,11 +1383,11 @@ msgstr "現在行を強調"
#: spyder/plugins/editor.py:135
msgid "Highlight current cell"
-msgstr "現在セルを強調"
+msgstr "現在cellを強調"
#: spyder/plugins/editor.py:137
msgid "Highlight occurrences after"
-msgstr "以下の事象を強調"
+msgstr "変更後に構文を強調するまでの時間"
#: spyder/plugins/editor.py:169
msgid "Save all files before running script"
@@ -1385,7 +1399,7 @@ msgstr "選択を実行"
#: spyder/plugins/editor.py:173
msgid "Maintain focus in the Editor after running cells or selections"
-msgstr "エディタ内で実行後、選択後もセルのフォーカスを維持する"
+msgstr "エディタ内で実行後、選択後もcellのフォーカスを維持する"
#: spyder/plugins/editor.py:176
msgid "Introspection"
@@ -1579,8 +1593,8 @@ msgstr ""
msgid "Fix automatically and show warning message box"
msgstr "自動的に修正し、警告をメッセージボックスで表示する"
-#: spyder/plugins/editor.py:357 spyder/plugins/ipythonconsole.py:573
-#: spyder/plugins/variableexplorer.py:35
+#: spyder/plugins/editor.py:357 spyder/plugins/ipythonconsole.py:627
+#: spyder/plugins/variableexplorer.py:47
msgid "Display"
msgstr "表示"
@@ -1596,8 +1610,8 @@ msgstr "詳細設定"
msgid "&New file..."
msgstr "新規ファイル(&N)..."
-#: spyder/plugins/editor.py:645 spyder/widgets/explorer.py:786
-#: spyder/widgets/explorer.py:793
+#: spyder/plugins/editor.py:645 spyder/widgets/explorer.py:788
+#: spyder/widgets/explorer.py:795
msgid "New file"
msgstr "新規ファイル"
@@ -1613,8 +1627,8 @@ msgstr "最後に閉じたファイルを開く"
msgid "&Open..."
msgstr "開く(&O)..."
-#: spyder/plugins/editor.py:662 spyder/plugins/editor.py:1867
-#: spyder/plugins/editor.py:1873
+#: spyder/plugins/editor.py:662 spyder/plugins/editor.py:1881
+#: spyder/plugins/editor.py:1887
msgid "Open file"
msgstr "ファイルを開く"
@@ -1630,7 +1644,7 @@ msgstr "ディスクからファイルを復帰"
msgid "&Save"
msgstr "保存(&S)"
-#: spyder/plugins/editor.py:673 spyder/widgets/editor.py:1672
+#: spyder/plugins/editor.py:673 spyder/widgets/editor.py:1675
msgid "Save file"
msgstr "ファイルを保存"
@@ -1711,6 +1725,7 @@ msgid "Set/Edit conditional breakpoint"
msgstr "条件付きブレークポイントをセット/編集"
#: spyder/plugins/editor.py:755
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:180
msgid "Clear breakpoints in all files"
msgstr "全てのファイルのブレークポイントをクリア"
@@ -1754,8 +1769,10 @@ msgstr "Step Return"
msgid "Run until current function or method returns"
msgstr "現在行のメソッド/関数までRunする"
-#: spyder/plugins/editor.py:796 spyder/widgets/findinfiles.py:438
-#: spyder/widgets/ipythonconsole/client.py:354
+#: spyder/plugins/editor.py:796 spyder/widgets/findinfiles.py:450
+#: spyder/widgets/ipythonconsole/client.py:393
+#: spyder/plugins/pylint/widgets/pylintgui.py:211
+#: spyder/plugins/profiler/widgets/profilergui.py:87
msgid "Stop"
msgstr "停止"
@@ -1783,7 +1800,7 @@ msgstr "最後のスクリプトを再度実行する(&L)"
msgid "Run again last file"
msgstr "最後のファイルを再度実行する"
-#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2720
+#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2727
msgid "Run &selection or current line"
msgstr "選択範囲あるいは現在のカーソル行を実行(&S)"
@@ -1791,7 +1808,7 @@ msgstr "選択範囲あるいは現在のカーソル行を実行(&S)"
msgid "Run selection or current line"
msgstr "選択範囲あるいは現在行を実行"
-#: spyder/plugins/editor.py:836 spyder/widgets/sourcecode/codeeditor.py:2708
+#: spyder/plugins/editor.py:836 spyder/widgets/sourcecode/codeeditor.py:2715
msgid "Run cell"
msgstr "cellを実行"
@@ -1800,18 +1817,18 @@ msgid ""
"Run current cell (Ctrl+Enter)\n"
"[Use #%% to create cells]"
msgstr ""
-"現在のセルを実行する (Ctrl+Enter)\n"
+"現在のcellを実行する (Ctrl+Enter)\n"
"[Use #%% to create cells]"
-#: spyder/plugins/editor.py:845 spyder/widgets/sourcecode/codeeditor.py:2712
+#: spyder/plugins/editor.py:845 spyder/widgets/sourcecode/codeeditor.py:2719
msgid "Run cell and advance"
-msgstr "cellを実行し進む"
+msgstr "cellを実行して進む"
#: spyder/plugins/editor.py:848
msgid "Run current cell and go to the next one (Shift+Enter)"
-msgstr "現在のセルを実行し次のセルへ(Shift+Enter)"
+msgstr "現在のcellを実行し次のcellへ(Shift+Enter)"
-#: spyder/plugins/editor.py:854 spyder/widgets/sourcecode/codeeditor.py:2716
+#: spyder/plugins/editor.py:854 spyder/widgets/sourcecode/codeeditor.py:2723
msgid "Re-run last cell"
msgstr "最後のcellを再度実行する("
@@ -1877,11 +1894,11 @@ msgstr "次のカーソル位置"
msgid "Go to next cursor position"
msgstr "次のカーソル位置へ移動"
-#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Comment"
msgstr "コメント"
-#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Uncomment"
msgstr "コメント解除"
@@ -1989,8 +2006,8 @@ msgstr "「最近使用したファイル」の最大履歴数..."
msgid "Clear recent files list"
msgstr "最近使用したファイルのリストをクリア"
-#: spyder/plugins/editor.py:1009 spyder/plugins/projects.py:107
-#: spyder/widgets/findinfiles.py:246
+#: spyder/plugins/editor.py:1009 spyder/plugins/projects.py:101
+#: spyder/widgets/findinfiles.py:261
msgid "Clear this list"
msgstr "このリストをクリア"
@@ -1998,39 +2015,39 @@ msgstr "このリストをクリア"
msgid "Open &recent"
msgstr "最近使用したファイル(&R)"
-#: spyder/plugins/editor.py:1675
+#: spyder/plugins/editor.py:1674
msgid "Spyder Editor"
msgstr "Spyderエディタ"
-#: spyder/plugins/editor.py:1676
+#: spyder/plugins/editor.py:1675
msgid "This is a temporary script file."
msgstr "これは一時的なスクリプトファイルです"
-#: spyder/plugins/editor.py:1745
+#: spyder/plugins/editor.py:1758
msgid "untitled"
msgstr "タイトル無し"
-#: spyder/plugins/editor.py:1817
+#: spyder/plugins/editor.py:1831
msgid "Maximum number of recent files"
msgstr "「最近使用したファイル」の最大履歴数"
-#: spyder/plugins/editor.py:1963
+#: spyder/plugins/editor.py:1977
msgid "Printing..."
msgstr "印刷中..."
-#: spyder/plugins/explorer.py:54
+#: spyder/plugins/explorer.py:55
msgid "File explorer"
msgstr "ファイルエクスプローラー"
-#: spyder/plugins/findinfiles.py:120 spyder/widgets/findinfiles.py:913
+#: spyder/plugins/findinfiles.py:117 spyder/widgets/findinfiles.py:949
msgid "Find in files"
msgstr "ファイルの検索"
-#: spyder/plugins/findinfiles.py:145
+#: spyder/plugins/findinfiles.py:141
msgid "&Find in files"
msgstr "ファイル内を検索(&F)"
-#: spyder/plugins/findinfiles.py:150
+#: spyder/plugins/findinfiles.py:146
msgid "Search text in multiple files"
msgstr "複数のファイルからテキストを検索"
@@ -2048,8 +2065,8 @@ msgid ""
"parenthesis is written next to it. Below you can decide to which plugin you "
"want to connect it to turn on this feature."
msgstr ""
-"このペインは括弧の左側が入力されるとそのオブジェクトのヘルプ情報を自動的に表"
-"示します。この機能を有効にするために接続したいプラグインを選べます。"
+"以下のペインでは左側括弧が入力されると、そのオブジェクトのヘルプ情報を自動的"
+"に表示することができます。この機能を有効にする場合選択して下さい。"
#: spyder/plugins/help.py:122
msgid ""
@@ -2083,47 +2100,47 @@ msgstr "Sphinx %s が現在インストールされています。"
msgid "No further documentation available"
msgstr "これ以上のドキュメントはありません"
-#: spyder/plugins/help.py:307 spyder/plugins/help.py:347
+#: spyder/plugins/help.py:307 spyder/plugins/help.py:345
msgid "No documentation available"
msgstr "利用可能なドキュメントはありません"
-#: spyder/plugins/help.py:378
+#: spyder/plugins/help.py:376
msgid "Source"
msgstr "ソース"
-#: spyder/plugins/help.py:385 spyder/plugins/runconfig.py:170
-#: spyder/plugins/runconfig.py:486 spyder/widgets/ipythonconsole/client.py:288
+#: spyder/plugins/help.py:383 spyder/plugins/runconfig.py:170
+#: spyder/plugins/runconfig.py:486 spyder/widgets/ipythonconsole/client.py:327
msgid "Console"
msgstr "コンソール"
-#: spyder/plugins/help.py:393
+#: spyder/plugins/help.py:391
msgid "Object"
msgstr "オブジェクト"
-#: spyder/plugins/help.py:407
+#: spyder/plugins/help.py:405
msgid "Plain Text"
msgstr "プレーンテキスト"
-#: spyder/plugins/help.py:411
+#: spyder/plugins/help.py:409
msgid "Show Source"
msgstr "ソースを表示"
-#: spyder/plugins/help.py:415
+#: spyder/plugins/help.py:413
msgid "Rich Text"
msgstr "リッチテキスト"
-#: spyder/plugins/help.py:425
+#: spyder/plugins/help.py:423
msgid "Automatic import"
msgstr "自動インポート"
-#: spyder/plugins/help.py:437 spyder/plugins/history.py:106
-#: spyder/widgets/editor.py:728 spyder/widgets/explorer.py:1200
-#: spyder/widgets/ipythonconsole/client.py:378
-#: spyder/widgets/variableexplorer/namespacebrowser.py:148
+#: spyder/plugins/help.py:435 spyder/plugins/history.py:108
+#: spyder/widgets/editor.py:738 spyder/widgets/explorer.py:1205
+#: spyder/widgets/ipythonconsole/client.py:417
+#: spyder/widgets/variableexplorer/namespacebrowser.py:151
msgid "Options"
msgstr "オプション"
-#: spyder/plugins/help.py:696
+#: spyder/plugins/help.py:692
msgid ""
"Here you can get help of any object by pressing %s in front of it, either on "
"the Editor or the Console.%sHelp can also be shown automatically after "
@@ -2134,38 +2151,38 @@ msgstr ""
"プが得られます。%s ヘルプはオブジェクトの隣で左括弧を入力することでも自動的に"
"表示されます。%sでこの機能を有効化できます。"
-#: spyder/plugins/help.py:702
+#: spyder/plugins/help.py:698
msgid "Preferences > Help"
msgstr "設定 > ヘルプ"
-#: spyder/plugins/help.py:709
+#: spyder/plugins/help.py:705
msgid "Usage"
msgstr "使用法"
-#: spyder/plugins/help.py:710
+#: spyder/plugins/help.py:706
msgid "New to Spyder? Read our"
-msgstr "Spypderは初めてですか? 読んでください。"
+msgstr "Spyderは初めてですか? 読んでください。"
-#: spyder/plugins/help.py:711
+#: spyder/plugins/help.py:707
msgid "tutorial"
msgstr "チュートリアル"
-#: spyder/plugins/help.py:718
+#: spyder/plugins/help.py:714
msgid ""
"Please consider installing Sphinx to get documentation rendered in rich text."
msgstr ""
"ドキュメントをリッチテキストで表示するためにSphinxをインストールした方が良い"
"でしょう。"
-#: spyder/plugins/help.py:891
+#: spyder/plugins/help.py:885
msgid "Lock"
msgstr "ロック"
-#: spyder/plugins/help.py:891
+#: spyder/plugins/help.py:885
msgid "Unlock"
msgstr "アンロック"
-#: spyder/plugins/help.py:938
+#: spyder/plugins/help.py:932
msgid ""
"The following error occured when calling Sphinx %s.
Incompatible "
"Sphinx version or doc string decoding failed.
Error message:
%s"
@@ -2174,152 +2191,168 @@ msgstr ""
"ジョンが合っていないか文字列のデコードに失敗しました。
エラーメッセー"
"ジ:
%s"
-#: spyder/plugins/help.py:982
+#: spyder/plugins/help.py:976
msgid "No source code available."
msgstr "ソースコードが利用できません"
-#: spyder/plugins/history.py:39
+#: spyder/plugins/history.py:39 spyder/plugins/pylint/plugin.py:35
msgid "Settings"
msgstr "設定"
-#: spyder/plugins/history.py:41
+#: spyder/plugins/history.py:43
msgid " entries"
msgstr " エントリ"
-#: spyder/plugins/history.py:41
+#: spyder/plugins/history.py:43
msgid "History depth: "
-msgstr "ヒストリー階層:"
+msgstr "最大ヒストリー数:"
-#: spyder/plugins/history.py:48
+#: spyder/plugins/history.py:50
msgid "Scroll automatically to last entry"
msgstr "最後のエントリーまで自動的にスクロール"
-#: spyder/plugins/history.py:126
+#: spyder/plugins/history.py:128
msgid "History log"
msgstr "ヒストリログ"
-#: spyder/plugins/history.py:153
+#: spyder/plugins/history.py:153 spyder/plugins/pylint/plugin.py:115
msgid "History..."
msgstr "ヒストリ..."
-#: spyder/plugins/history.py:155
+#: spyder/plugins/history.py:155 spyder/plugins/pylint/plugin.py:117
msgid "Set history maximum entries"
msgstr "ヒストリの最大エントリ数"
-#: spyder/plugins/history.py:260
+#: spyder/plugins/history.py:260 spyder/plugins/pylint/plugin.py:39
+#: spyder/plugins/pylint/plugin.py:160
msgid "History"
msgstr "ヒストリ"
-#: spyder/plugins/history.py:261
+#: spyder/plugins/history.py:261 spyder/plugins/pylint/plugin.py:161
msgid "Maximum entries"
msgstr "最大エントリ数"
-#: spyder/plugins/ipythonconsole.py:65
+#: spyder/plugins/ipythonconsole.py:64
msgid "Symbolic mathematics in the IPython Console"
msgstr "IPythonコンソールでの記号数学"
-#: spyder/plugins/ipythonconsole.py:69
+#: spyder/plugins/ipythonconsole.py:68
msgid "Run Cython files in the IPython Console"
msgstr "CythonファイルをIPythonコンソールで実行"
-#: spyder/plugins/ipythonconsole.py:73
+#: spyder/plugins/ipythonconsole.py:72
msgid "Integrate the IPython console"
msgstr "IPythonコンソールを統合"
-#: spyder/plugins/ipythonconsole.py:77
+#: spyder/plugins/ipythonconsole.py:76
msgid "IPython interactive python environment"
msgstr "IPythonインタラクティブpython環境"
-#: spyder/plugins/ipythonconsole.py:128
+#: spyder/plugins/ipythonconsole.py:80
+msgid "Display 2D graphics in the IPython Console"
+msgstr "IPythonコンソールで2D画像を表示"
+
+#: spyder/plugins/ipythonconsole.py:131
msgid ""
"The authenticity of host %s can't be established. Are you sure you "
"want to continue connecting?"
msgstr "ホスト %s の信頼性が確立できません。本当に接続を続けますか?"
-#: spyder/plugins/ipythonconsole.py:140
+#: spyder/plugins/ipythonconsole.py:143
msgid "The authenticity of the host can't be established"
msgstr "ホストの信頼性が確立できません"
-#: spyder/plugins/ipythonconsole.py:147
+#: spyder/plugins/ipythonconsole.py:150
msgid "Tunnel '%s' failed to start"
msgstr "Tunnel '%s' は開始できませんでした"
-#: spyder/plugins/ipythonconsole.py:152
+#: spyder/plugins/ipythonconsole.py:155
msgid "Could not connect to remote host"
msgstr "リモートホストへ接続できませんでした"
-#: spyder/plugins/ipythonconsole.py:169 spyder/plugins/ipythonconsole.py:799
+#: spyder/plugins/ipythonconsole.py:172 spyder/plugins/ipythonconsole.py:846
msgid "Connect to an existing kernel"
msgstr "既存のカーネルに接続"
-#: spyder/plugins/ipythonconsole.py:171
+#: spyder/plugins/ipythonconsole.py:174
msgid ""
-"Please enter the connection info of the kernel you want to connect to. For "
-"that you can either select its JSON connection file using the Browse"
-"tt> button, or write directly its id, in case it's a local kernel (for "
-"example kernel-3764.json or just 3764)."
+"Please select the JSON connection file (e.g. kernel-3764.json"
+"tt>) or enter the 4-digit ID (e.g. 3764) of the existing "
+"kernel to connect to, and enter the SSH host name and credentials if a "
+"remote kernel."
msgstr ""
-"接続したいカーネルの接続情報を入力してください。 表示 ボタンを押し、"
-"JSON接続ファイルを選ぶか、ローカルカーネルの場合IDを入力してください (例: "
-"kernel-3764.json あるいは 3764)。"
+"既存のカーネルに接続するために、接続設定JSONファイルを選択するか(例 "
+"kernel-3764.json) 4桁のIDを入力(例 3764)してくださ"
+"い。 リモートカーネルを選択する場合はさらにSSHホスト名と認証情報を入力してく"
+"ださい。"
-#: spyder/plugins/ipythonconsole.py:182
-msgid "Connection info:"
-msgstr "接続情報:"
+#: spyder/plugins/ipythonconsole.py:183
+msgid "Kernel ID/Connection file:"
+msgstr "カーネルID/接続設定ファイル:"
-#: spyder/plugins/ipythonconsole.py:184
-msgid "Path to connection file or kernel id"
-msgstr "接続ファイルへのパスあるいはカーネルID"
+#: spyder/plugins/ipythonconsole.py:185
+msgid "ID number or path to connection file"
+msgstr "ID番号あるいは接続設定ファイルへのパス"
-#: spyder/plugins/ipythonconsole.py:186 spyder/plugins/ipythonconsole.py:203
+#: spyder/plugins/ipythonconsole.py:187 spyder/plugins/ipythonconsole.py:216
msgid "Browse"
msgstr "表示"
-#: spyder/plugins/ipythonconsole.py:195
-msgid "This is a remote kernel"
-msgstr "これはリモートカーネルです"
+#: spyder/plugins/ipythonconsole.py:196
+msgid "This is a remote kernel (via SSH)"
+msgstr "これはリモートカーネルです(SSH経由)"
#: spyder/plugins/ipythonconsole.py:199
+msgid ""
+"Note: If connecting to a remote kernel, only the SSH keyfile or"
+"i> the Password field need to be completed, unless the keyfile is protected "
+"with a passphrase."
+msgstr ""
+"注: リモートカーネル接続では、キーファイルがパスフレーズで保護されて"
+"いない場合、SSHキーファイルのみ あるいは パスワード欄への記入が必要と"
+"なります。"
+
+#: spyder/plugins/ipythonconsole.py:207
msgid "username@hostname:port"
msgstr "username@hostname:port"
-#: spyder/plugins/ipythonconsole.py:202
-msgid "Path to ssh key file"
-msgstr "sshキーファイルへのパス"
-
-#: spyder/plugins/ipythonconsole.py:211
-msgid "Password or ssh key passphrase"
-msgstr "パスワードあるいはsshキーのパスフレーズ"
+#: spyder/plugins/ipythonconsole.py:210
+msgid "Remote user password or SSH keyfile passphrase"
+msgstr "パスワードあるいはSSHキーパスフレーズ"
#: spyder/plugins/ipythonconsole.py:215
-msgid "Host name"
-msgstr "ホスト名"
+msgid "Path to SSH keyfile (optional)"
+msgstr "SSHキーファイルへのパス(optional)"
-#: spyder/plugins/ipythonconsole.py:216
-msgid "Ssh key"
-msgstr "sshキー"
+#: spyder/plugins/ipythonconsole.py:224
+msgid "Host name:"
+msgstr "ホスト名:"
-#: spyder/plugins/ipythonconsole.py:217
-msgid "Password"
-msgstr "パスワード"
+#: spyder/plugins/ipythonconsole.py:225
+msgid "Password:"
+msgstr "パスワード:"
-#: spyder/plugins/ipythonconsole.py:246
-msgid "Open connection file"
-msgstr "IPython接続ファイルを開く"
+#: spyder/plugins/ipythonconsole.py:226
+msgid "SSH keyfile:"
+msgstr "SSHキーファイル:"
-#: spyder/plugins/ipythonconsole.py:251
-msgid "Select ssh key"
-msgstr "sshキーを選択"
+#: spyder/plugins/ipythonconsole.py:257
+msgid "Select kernel connection file"
+msgstr "カーネル接続設定ファイルを選択"
-#: spyder/plugins/ipythonconsole.py:284 spyder/plugins/ipythonconsole.py:734
+#: spyder/plugins/ipythonconsole.py:262
+msgid "Select SSH keyfile"
+msgstr "SSHキーファイルを選択"
+
+#: spyder/plugins/ipythonconsole.py:295 spyder/plugins/ipythonconsole.py:780
msgid "IPython console"
msgstr "IPythonコンソール"
-#: spyder/plugins/ipythonconsole.py:291
+#: spyder/plugins/ipythonconsole.py:302
msgid "Display initial banner"
msgstr "初期バナーの表示"
-#: spyder/plugins/ipythonconsole.py:292
+#: spyder/plugins/ipythonconsole.py:303
msgid ""
"This option lets you hide the message shown at\n"
"the top of the console when it's opened."
@@ -2327,11 +2360,11 @@ msgstr ""
"このオプションによりコンソールを開いた時に表示される\n"
"一番上のメッセージを隠すことができます。"
-#: spyder/plugins/ipythonconsole.py:294
+#: spyder/plugins/ipythonconsole.py:305
msgid "Use a pager to display additional text inside the console"
msgstr "コンソール内で追加テキストを表示するためにページャーを使用"
-#: spyder/plugins/ipythonconsole.py:296
+#: spyder/plugins/ipythonconsole.py:307
msgid ""
"Useful if you don't want to fill the console with long help or completion "
"texts.\n"
@@ -2340,15 +2373,15 @@ msgstr ""
"補完テキストや長いヘルプでコンソールを埋めたくない場合有効です。\n"
"注: このページャーから出るには Qキーを押してください。"
-#: spyder/plugins/ipythonconsole.py:301
+#: spyder/plugins/ipythonconsole.py:312
msgid "Ask for confirmation before closing"
-msgstr "閉じる前に確認するようにする"
+msgstr "閉じる前に確認する"
-#: spyder/plugins/ipythonconsole.py:304
+#: spyder/plugins/ipythonconsole.py:315
msgid "Ask for confirmation before removing all user-defined variables"
-msgstr "全ユーザー定義変数を削除する前に確認する"
+msgstr "全てのユーザー定義変数を削除する前に確認する"
-#: spyder/plugins/ipythonconsole.py:307
+#: spyder/plugins/ipythonconsole.py:318
msgid ""
"This option lets you hide the warning message shown\n"
"when resetting the namespace from Spyder."
@@ -2356,44 +2389,56 @@ msgstr ""
"このオプションによりSpyderから名前空間をリセットするときの\n"
"警告メッセージを隠すことができます。"
-#: spyder/plugins/ipythonconsole.py:309
-#: spyder/widgets/ipythonconsole/client.py:317
+#: spyder/plugins/ipythonconsole.py:320
+#: spyder/widgets/ipythonconsole/client.py:356
msgid "Show elapsed time"
msgstr "実行時間を表示"
-#: spyder/plugins/ipythonconsole.py:320
+#: spyder/plugins/ipythonconsole.py:322
+msgid "Ask for confirmation before restarting"
+msgstr "再起動前に確認メッセージを出す"
+
+#: spyder/plugins/ipythonconsole.py:324
+msgid ""
+"This option lets you hide the warning message shown\n"
+"when restarting the kernel."
+msgstr ""
+"このオプションによりカーネル再起動時の\n"
+"警告メッセージを隠すことができます。"
+
+#: spyder/plugins/ipythonconsole.py:337
msgid "Completion Type"
msgstr "補完タイプ"
-#: spyder/plugins/ipythonconsole.py:321
+#: spyder/plugins/ipythonconsole.py:338
msgid "Decide what type of completion to use"
msgstr "どのタイプの補完を使うか選択"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Graphical"
msgstr "グラフィックス"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Plain"
msgstr "プレーンテキスト"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Terminal"
msgstr "ターミナル"
-#: spyder/plugins/ipythonconsole.py:324
+#: spyder/plugins/ipythonconsole.py:341
msgid "Completion:"
msgstr "補完:"
-#: spyder/plugins/ipythonconsole.py:334
+#: spyder/plugins/ipythonconsole.py:351
msgid " lines"
msgstr "行"
-#: spyder/plugins/ipythonconsole.py:334
+#: spyder/plugins/ipythonconsole.py:351
msgid "Buffer: "
msgstr "バッファー:"
-#: spyder/plugins/ipythonconsole.py:336
+#: spyder/plugins/ipythonconsole.py:353
msgid ""
"Set the maximum number of lines of text shown in the\n"
"console before truncation. Specifying -1 disables it\n"
@@ -2403,19 +2448,19 @@ msgstr ""
"-1 を設定すると無効になります\n"
"(非推奨です!)"
-#: spyder/plugins/ipythonconsole.py:345
+#: spyder/plugins/ipythonconsole.py:362
msgid "Support for graphics (Matplotlib)"
msgstr "画像のサポート(Matplotlib)"
-#: spyder/plugins/ipythonconsole.py:346
+#: spyder/plugins/ipythonconsole.py:363
msgid "Activate support"
msgstr "サポートを有効化"
-#: spyder/plugins/ipythonconsole.py:347
+#: spyder/plugins/ipythonconsole.py:364
msgid "Automatically load Pylab and NumPy modules"
msgstr "Pylab, NumPyモジュールを自動的にロード"
-#: spyder/plugins/ipythonconsole.py:350
+#: spyder/plugins/ipythonconsole.py:367
msgid ""
"This lets you load graphics support without importing \n"
"the commands to do plots. Useful to work with other\n"
@@ -2427,19 +2472,19 @@ msgstr ""
"している場合や、SpyderでGUIを開発している場合、\n"
"有用です。"
-#: spyder/plugins/ipythonconsole.py:365
+#: spyder/plugins/ipythonconsole.py:382
msgid "Inline"
msgstr "インライン"
-#: spyder/plugins/ipythonconsole.py:366
+#: spyder/plugins/ipythonconsole.py:383
msgid "Automatic"
msgstr "自動"
-#: spyder/plugins/ipythonconsole.py:367
+#: spyder/plugins/ipythonconsole.py:384
msgid "Graphics backend"
msgstr "グラフィックスのバックエンド"
-#: spyder/plugins/ipythonconsole.py:368
+#: spyder/plugins/ipythonconsole.py:385
msgid ""
"Decide how graphics are going to be displayed in the console. If unsure, "
"please select %s to put graphics inside the console or %s to "
@@ -2449,59 +2494,77 @@ msgstr ""
"コンソール内で画像を表示したい場合 %s を選び、別ウィンドウで(ズーム、"
"パン等)操作したい場合は %s を選んでください。"
-#: spyder/plugins/ipythonconsole.py:388
+#: spyder/plugins/ipythonconsole.py:405
msgid "Backend:"
msgstr "バックエンド:"
-#: spyder/plugins/ipythonconsole.py:390
+#: spyder/plugins/ipythonconsole.py:407
msgid "This option will be applied the next time a console is opened."
msgstr "このオプションは次にコンソールを開いた時に適用されます"
-#: spyder/plugins/ipythonconsole.py:401
+#: spyder/plugins/ipythonconsole.py:418
msgid "Inline backend"
msgstr "インラインのバックエンド"
-#: spyder/plugins/ipythonconsole.py:402
+#: spyder/plugins/ipythonconsole.py:419
msgid "Decide how to render the figures created by this backend"
msgstr "このバックエンドで生成された画像をどのように描画するか選択"
-#: spyder/plugins/ipythonconsole.py:406
+#: spyder/plugins/ipythonconsole.py:423
msgid "Format:"
msgstr "フォーマット:"
-#: spyder/plugins/ipythonconsole.py:409
+#: spyder/plugins/ipythonconsole.py:427
msgid "Resolution:"
msgstr "解像度:"
-#: spyder/plugins/ipythonconsole.py:409
+#: spyder/plugins/ipythonconsole.py:427
msgid "dpi"
msgstr "dpi"
-#: spyder/plugins/ipythonconsole.py:411
+#: spyder/plugins/ipythonconsole.py:429
msgid "Only used when the format is PNG. Default is 72"
msgstr "PNGフォーマットの場合のみ使われます。デフォルトは72"
-#: spyder/plugins/ipythonconsole.py:414
+#: spyder/plugins/ipythonconsole.py:432
msgid "Width:"
msgstr "幅:"
-#: spyder/plugins/ipythonconsole.py:414 spyder/plugins/ipythonconsole.py:418
+#: spyder/plugins/ipythonconsole.py:432 spyder/plugins/ipythonconsole.py:436
msgid "inches"
msgstr "インチ"
-#: spyder/plugins/ipythonconsole.py:416
+#: spyder/plugins/ipythonconsole.py:434
msgid "Default is 6"
msgstr "デフォルトは6です"
-#: spyder/plugins/ipythonconsole.py:418
+#: spyder/plugins/ipythonconsole.py:436
msgid "Height:"
msgstr "高さ:"
-#: spyder/plugins/ipythonconsole.py:420
+#: spyder/plugins/ipythonconsole.py:438
msgid "Default is 4"
msgstr "デフォルトは4です"
-#: spyder/plugins/ipythonconsole.py:447
+#: spyder/plugins/ipythonconsole.py:440
+msgid "Use a tight layout for inline plots"
+msgstr "インラインプロットのためにタイトなレイアウトを使う"
+
+#: spyder/plugins/ipythonconsole.py:442
+msgid ""
+"Sets bbox_inches to \"tight\" when\n"
+"plotting inline with matplotlib.\n"
+"When enabled, can cause discrepancies\n"
+"between the image displayed inline and\n"
+"that created using savefig."
+msgstr ""
+"matplotlibを使ってインラインプロット\n"
+"するためにbbox_inchesに\"tight\"を設定します。\n"
+"これが有効化された場合、インライン表示された画像と\n"
+"savefigによって作成された画像の間に食い違いが\n"
+"出る場合があります。"
+
+#: spyder/plugins/ipythonconsole.py:475
msgid ""
"You can run several lines of code when a console is started. Please "
"introduce each one separated by commas, for example:
import os, import "
@@ -2510,15 +2573,15 @@ msgstr ""
"コンソールを開始した時にコードを実行できます。それぞれをコンマで区切ってくだ"
"さい。例:
import os, import sys"
-#: spyder/plugins/ipythonconsole.py:453
+#: spyder/plugins/ipythonconsole.py:481
msgid "Lines:"
msgstr "行:"
-#: spyder/plugins/ipythonconsole.py:462
+#: spyder/plugins/ipythonconsole.py:490
msgid "Run a file"
msgstr "ファイルを実行"
-#: spyder/plugins/ipythonconsole.py:463
+#: spyder/plugins/ipythonconsole.py:491
msgid ""
"You can also run a whole file at startup instead of just some lines (This is "
"similar to have a PYTHONSTARTUP file)."
@@ -2526,34 +2589,58 @@ msgstr ""
"行の一部だけではなくファイル全体をスタート時に実行できます(PYTHONSTARTUPファ"
"イルと類似)"
-#: spyder/plugins/ipythonconsole.py:467
+#: spyder/plugins/ipythonconsole.py:495
msgid "Use the following file:"
msgstr "以下のファイルを使う:"
-#: spyder/plugins/ipythonconsole.py:481
+#: spyder/plugins/ipythonconsole.py:509
+msgid "Jedi completion"
+msgstr "Jediモジュールによる補完"
+
+#: spyder/plugins/ipythonconsole.py:510
+msgid ""
+"Enable Jedi-based Tab completion in the IPython console; similar to "
+"the greedy completer, but without evaluating the code.
Warning: "
+"Slows down your console when working with large dataframes!"
+msgstr ""
+"IPythonコンソールでjediベースのタブ補完を有効化する;貪欲(greedy)な"
+"補完と類似しているがコードの評価はしない。
警告: サイズの大きい"
+"データフレームを扱っている場合コンソールの処理速度が低下することがあります。"
+
+#: spyder/plugins/ipythonconsole.py:517
+msgid "Use Jedi completion in the IPython console"
+msgstr "IPythonコンソールでJediモジュールによる補完を使う"
+
+#: spyder/plugins/ipythonconsole.py:530
msgid "Greedy completion"
msgstr "Greedy completion"
-#: spyder/plugins/ipythonconsole.py:482
+#: spyder/plugins/ipythonconsole.py:531
msgid ""
"Enable Tab completion on elements of lists, results of function "
-"calls, etc, without assigning them to a variable.
For example, you "
-"can get completions on things like li[0].<Tab> or ins."
-"meth().<Tab>"
+"calls, etc, without assigning them to a variable, like li[0].<"
+"Tab> or ins.meth().<Tab>
Warning: Due to a "
+"bug, IPython's greedy completer requires a leading <Space> "
+"for some completions; e.g. np.sin(<Space>np.<Tab> "
+"works while np.sin(np.<Tab> doesn't."
msgstr ""
-"リスト要素、関数呼び出し結果等を変数に割り当てずににTab 補完"
-"を有効にする。
例えば li[0].<Tab> や ins.meth().<"
-"Tab> のように補完できる"
+"リスト要素や関数呼び出し結果等でTab補完を有効化する。 この場合結果等"
+"を変数に割り当てずににTab 補完を有効にする。
例えば "
+"li[0].<Tab> や ins.meth().<Tab> のように補完で"
+"きる、
警告:バグにより、IPythonのgreedy補完ではいくつかの補完に対"
+"して<Space> が必要となる。例:np.sin(<Space>np.<"
+"Tab> は正しく動作するが、np.sin(np.<Tab> は動作しな"
+"い。"
-#: spyder/plugins/ipythonconsole.py:490
-msgid "Use the greedy completer"
-msgstr "greedy completerを利用する"
+#: spyder/plugins/ipythonconsole.py:543
+msgid "Use greedy completion in the IPython console"
+msgstr "IPythonコンソールで貪欲な補完(greedy completion)を使う"
-#: spyder/plugins/ipythonconsole.py:501
+#: spyder/plugins/ipythonconsole.py:555
msgid "Autocall"
msgstr "Autocall"
-#: spyder/plugins/ipythonconsole.py:502
+#: spyder/plugins/ipythonconsole.py:556
msgid ""
"Autocall makes IPython automatically call any callable object even if you "
"didn't type explicit parentheses.
For example, if you type str 43 "
@@ -2563,23 +2650,23 @@ msgstr ""
"Autocallによって自動的に呼ぶ。
例えば、str 43 と入力すると自動的"
"に str(43) となる。"
-#: spyder/plugins/ipythonconsole.py:509
+#: spyder/plugins/ipythonconsole.py:563
msgid "Smart"
msgstr "Smart"
-#: spyder/plugins/ipythonconsole.py:510
+#: spyder/plugins/ipythonconsole.py:564
msgid "Full"
msgstr "Full"
-#: spyder/plugins/ipythonconsole.py:511
+#: spyder/plugins/ipythonconsole.py:565
msgid "Off"
msgstr "オフ"
-#: spyder/plugins/ipythonconsole.py:513
+#: spyder/plugins/ipythonconsole.py:567
msgid "Autocall: "
msgstr "Autocall:"
-#: spyder/plugins/ipythonconsole.py:514
+#: spyder/plugins/ipythonconsole.py:568
msgid ""
"On %s mode, Autocall is not applied if there are no arguments after "
"the callable. On %s mode, all callable objects are automatically "
@@ -2589,11 +2676,11 @@ msgstr ""
"されません。 %s モードでは、(引数がない場合でも)全ての呼び出し可能オブ"
"ジェクトが自動的に呼ばれます。"
-#: spyder/plugins/ipythonconsole.py:526
+#: spyder/plugins/ipythonconsole.py:580
msgid "Symbolic Mathematics"
msgstr "記号数学"
-#: spyder/plugins/ipythonconsole.py:527
+#: spyder/plugins/ipythonconsole.py:581
msgid ""
"Perfom symbolic operations in the console (e.g. integrals, derivatives, "
"vector calculus, etc) and get the outputs in a beautifully printed style (it "
@@ -2602,11 +2689,11 @@ msgstr ""
"記号演算をコンソール内で実行し(例:積分、微分、ベクトル演算等)、整えられた印刷"
"可能スタイルで出力する(要Sympyモジュール)。"
-#: spyder/plugins/ipythonconsole.py:532
+#: spyder/plugins/ipythonconsole.py:586
msgid "Use symbolic math"
msgstr "記号演算を使う"
-#: spyder/plugins/ipythonconsole.py:533
+#: spyder/plugins/ipythonconsole.py:587
msgid ""
"This option loads the Sympy library to work with.
Please refer to its "
"documentation to learn how to use it."
@@ -2614,43 +2701,43 @@ msgstr ""
"このオプションはSympyライブラリをロードします。
Sympyドキュメントを参照"
"し、使用方法を学んでください。"
-#: spyder/plugins/ipythonconsole.py:543
+#: spyder/plugins/ipythonconsole.py:597
msgid "Prompts"
msgstr "プロンプト"
-#: spyder/plugins/ipythonconsole.py:544
+#: spyder/plugins/ipythonconsole.py:598
msgid "Modify how Input and Output prompts are shown in the console."
msgstr "プロンプトの入力と出力のコンソール内での表示を変更する。"
-#: spyder/plugins/ipythonconsole.py:547
+#: spyder/plugins/ipythonconsole.py:601
msgid "Input prompt:"
msgstr "入力プロンプト:"
-#: spyder/plugins/ipythonconsole.py:549
+#: spyder/plugins/ipythonconsole.py:603
msgid ""
"Default is
In [<span class=\"in-prompt-number\">%i</span>]:"
msgstr ""
"デフォルトは
In [<span class=\"in-prompt-number\">%i</span>]:"
-#: spyder/plugins/ipythonconsole.py:553
+#: spyder/plugins/ipythonconsole.py:607
msgid "Output prompt:"
msgstr "出力プロンプト:"
-#: spyder/plugins/ipythonconsole.py:555
+#: spyder/plugins/ipythonconsole.py:609
msgid ""
"Default is
Out[<span class=\"out-prompt-number\">%i</span>]:"
msgstr ""
"デフォルトは
Out[<span class=\"out-prompt-number\">%i</span>]:"
-#: spyder/plugins/ipythonconsole.py:575
+#: spyder/plugins/ipythonconsole.py:629
msgid "Graphics"
msgstr "グラフィックス"
-#: spyder/plugins/ipythonconsole.py:577
+#: spyder/plugins/ipythonconsole.py:631
msgid "Startup"
msgstr "スタートアップ"
-#: spyder/plugins/ipythonconsole.py:604
+#: spyder/plugins/ipythonconsole.py:658
msgid ""
"The directory {} is not writable and it is required to create IPython "
"consoles. Please make it writable."
@@ -2658,23 +2745,33 @@ msgstr ""
"IPythonコンソール作成に必要なディクショナリ{}が書き込み不可になっています。書"
"き込み可能に変更して下さい"
-#: spyder/plugins/ipythonconsole.py:784
+#: spyder/plugins/ipythonconsole.py:831
msgid "Open an &IPython console"
msgstr "IPythonコンソールを開く(&I)"
-#: spyder/plugins/ipythonconsole.py:791
+#: spyder/plugins/ipythonconsole.py:838
msgid "Restart kernel"
msgstr "カーネルの再起動"
-#: spyder/plugins/ipythonconsole.py:800
+#: spyder/plugins/ipythonconsole.py:847
msgid "Open a new IPython console connected to an existing kernel"
msgstr "既存カーネルに接続された新規IPythonコンソールを開く"
-#: spyder/plugins/ipythonconsole.py:803
+#: spyder/plugins/ipythonconsole.py:850
msgid "Rename tab"
msgstr "タブをリネーム"
-#: spyder/plugins/ipythonconsole.py:928
+#: spyder/plugins/ipythonconsole.py:968
+msgid ""
+"
Please exit from debugging before trying to run a file in this "
+"console.\n"
+"
"
+msgstr ""
+"
コンソールでファイルを実行しようとする前に、デバッグを終了して下さい。"
+"\n"
+"
"
+
+#: spyder/plugins/ipythonconsole.py:988
msgid ""
"No IPython console is currently available to run %s.
Please "
"open a new one and try again."
@@ -2682,62 +2779,56 @@ msgstr ""
"現在%s実行可能なIPythonコンソールがありません。.
新規に開いて再"
"試行してください。"
-#: spyder/plugins/ipythonconsole.py:1023
+#: spyder/plugins/ipythonconsole.py:1096
msgid ""
-"Your Python environment or installation doesn't have the ipykernel "
-"and cloudpickle modules installed on it. Without these modules is "
-"not possible for Spyder to create a console for you.
You can install "
-"them by running in a system terminal:
pip install ipykernel "
-"cloudpickle
or
conda install ipykernel cloudpickle"
-"tt>"
+"Your Python environment or installation doesn't have the spyder-kernels"
+"tt> module or the right version of it installed. Without this module is not "
+"possible for Spyder to create a console for you.
You can install it "
+"by running in a system terminal:
conda install spyder-kernels=0."
+"*
or
pip install spyder-kernels==0.*"
msgstr ""
-"Python環境にipykernelとcloudpickle モジュールがインストール"
-"されていません。これらのモジュールがない場合Spyderでコンソールを開くことがで"
-"きない場合があります。
システムのターミナルで以下のコマンドでインス"
-"トールすることが可能です。:
pip install ipykernel cloudpickle"
-"tt>
あるいは
conda install ipykernel cloudpickle"
+"Python環境にspyder-kernelsモジュールあるいは正しいバージョンのものが"
+"インストールされておりません。このモジュールがない場合Spyderでコンソールを開"
+"くことができない場合があります。
システムのターミナルで以下のコマンド"
+"を入力することによってインストールできます:
conda install spyder-"
+"kernels=0.*
あるいは
pip install spyder-kernels==0.*"
+"tt>"
-#: spyder/plugins/ipythonconsole.py:1316
+#: spyder/plugins/ipythonconsole.py:1362
msgid "Do you want to close this console?"
msgstr "本当にこのコンソールを閉じますか?"
-#: spyder/plugins/ipythonconsole.py:1322
+#: spyder/plugins/ipythonconsole.py:1368
msgid ""
"Do you want to close all other consoles connected to the same kernel as this "
"one?"
msgstr "同じカーネルに接続している他の全てのコンソールを閉じますか?"
-#: spyder/plugins/ipythonconsole.py:1387
+#: spyder/plugins/ipythonconsole.py:1440
msgid ""
"It was not possible to restart the IPython console when switching to this "
-"project. The error was {0}"
+"project. The error was
{0}"
msgstr ""
-"プロジェクト切替時にIPythonコンソールの再起動に失敗しました。エラー {0}"
+"プロジェクト切替時にIPythonコンソールの再起動に失敗しました。エラー "
+"
{0}"
-#: spyder/plugins/ipythonconsole.py:1488
-msgid ""
-"This error was most probably caused by installing Spyder in a directory with "
-"non-ascii characters (i.e. characters with tildes, apostrophes or non-latin "
-"symbols).
To fix it, please reinstall Spyder in a different "
-"location."
-msgstr ""
-"このエラーはおそらくSpyderを非ASCII文字を名前に含むディレクトリにインストール"
-"していることによって発生しています。br>
解決するにはSpyderを他の場所に"
-"再インストール して下さい。"
+#: spyder/plugins/ipythonconsole.py:1546 spyder/plugins/ipythonconsole.py:1556
+msgid "The error is:
{}"
+msgstr "エラー:
{}"
-#: spyder/plugins/ipythonconsole.py:1694
+#: spyder/plugins/ipythonconsole.py:1742
msgid "IPython"
msgstr "IPython"
-#: spyder/plugins/ipythonconsole.py:1695
+#: spyder/plugins/ipythonconsole.py:1743
msgid "Unable to connect to %s"
msgstr "%sに接続できませんでした"
-#: spyder/plugins/ipythonconsole.py:1765
+#: spyder/plugins/ipythonconsole.py:1819
msgid "Connection error"
msgstr "接続エラー"
-#: spyder/plugins/ipythonconsole.py:1766
+#: spyder/plugins/ipythonconsole.py:1820
msgid ""
"Could not open ssh tunnel. The error was:\n"
"\n"
@@ -2761,31 +2852,35 @@ msgstr "レイアウトの削除"
msgid "Layout Display and Order"
msgstr "レイアウトの表示と順序"
-#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:66
+#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:71
msgid "Python interpreter"
msgstr "Pythonインタープリター"
-#: spyder/plugins/maininterpreter.py:68
+#: spyder/plugins/maininterpreter.py:73
msgid "Select the Python interpreter for all Spyder consoles"
msgstr "Spyderコンソールで使用するPythonインタープリターの選択"
-#: spyder/plugins/maininterpreter.py:71
+#: spyder/plugins/maininterpreter.py:76
msgid "Default (i.e. the same as Spyder's)"
msgstr "デフォルト(=Spyderと同じ)"
-#: spyder/plugins/maininterpreter.py:74
+#: spyder/plugins/maininterpreter.py:79
msgid "Use the following Python interpreter:"
msgstr "以下のPythonインタープリターを使う"
-#: spyder/plugins/maininterpreter.py:77
+#: spyder/plugins/maininterpreter.py:82
msgid "Executables"
msgstr "実行可能ファイル"
-#: spyder/plugins/maininterpreter.py:94
+#: spyder/plugins/maininterpreter.py:92
+msgid "Recent custom interpreters"
+msgstr "最近使ったPythonインタープリター"
+
+#: spyder/plugins/maininterpreter.py:107
msgid "User Module Reloader (UMR)"
msgstr "モジュールリローダーを使用(UMR)"
-#: spyder/plugins/maininterpreter.py:95
+#: spyder/plugins/maininterpreter.py:108
msgid ""
"UMR forces Python to reload modules which were imported when executing a "
"file in a Python or IPython console with the runfile function."
@@ -2793,11 +2888,11 @@ msgstr ""
"PythonあるいはIPythonでrunfileを使うスクリプトをインポートする時、UMR"
"はモジュール再読み込みを強制します。"
-#: spyder/plugins/maininterpreter.py:100
+#: spyder/plugins/maininterpreter.py:113
msgid "Enable UMR"
msgstr "UMRを有効化"
-#: spyder/plugins/maininterpreter.py:101
+#: spyder/plugins/maininterpreter.py:114
msgid ""
"This option will enable the User Module Reloader (UMR) in Python/IPython "
"consoles. UMR forces Python to reload deeply modules during import when "
@@ -2819,19 +2914,19 @@ msgstr ""
"setAttributeメソッドを使ってアトリビュートQt.WA_DeleteOnClose "
"をメインウインドウに適用するなど)"
-#: spyder/plugins/maininterpreter.py:117
+#: spyder/plugins/maininterpreter.py:130
msgid "Show reloaded modules list"
msgstr "再読込されたモジュールのリストを表示"
-#: spyder/plugins/maininterpreter.py:118
+#: spyder/plugins/maininterpreter.py:131
msgid "Please note that these changes will be applied only to new consoles"
msgstr "これらの変更は新規コンソールのみに適用されることに注意してください"
-#: spyder/plugins/maininterpreter.py:122
+#: spyder/plugins/maininterpreter.py:135
msgid "Set UMR excluded (not reloaded) modules"
msgstr "UMRから排除される(=再読込されない)モジュールを設定"
-#: spyder/plugins/maininterpreter.py:150
+#: spyder/plugins/maininterpreter.py:163
msgid ""
"You selected an invalid Python interpreter for the console so the previous "
"interpreter will stay. Please make sure to select a valid one."
@@ -2839,7 +2934,7 @@ msgstr ""
"無効なPythonインタープリターが選択されたためインタープリターは変更されませ"
"ん。有効なものを選択して下さい。"
-#: spyder/plugins/maininterpreter.py:175
+#: spyder/plugins/maininterpreter.py:184
msgid ""
"You selected a Python %d interpreter for the console but Spyder is "
"running on Python %d!.
Although this is possible, we recommend "
@@ -2852,17 +2947,17 @@ msgstr ""
"ジョン間での構文非互換性による偽の警告/エラーを避けるため、Spyder上でも選択し"
"たバージョンのインタープリターをインストール・実行することが推奨されます。"
-#: spyder/plugins/maininterpreter.py:186 spyder/plugins/maininterpreter.py:213
-#: spyder/plugins/maininterpreter.py:217
+#: spyder/plugins/maininterpreter.py:195 spyder/plugins/maininterpreter.py:222
+#: spyder/plugins/maininterpreter.py:226
msgid "UMR"
msgstr "UMR"
-#: spyder/plugins/maininterpreter.py:187
+#: spyder/plugins/maininterpreter.py:196
msgid "Set the list of excluded modules as this: numpy, scipy"
msgstr ""
"除外モジュールのリストを以下の例のように入力して下さい: numpy, scipy"
-#: spyder/plugins/maininterpreter.py:204
+#: spyder/plugins/maininterpreter.py:213
msgid ""
"You are working with Python 2, this means that you can not import a module "
"that contains non-ascii characters."
@@ -2870,7 +2965,7 @@ msgstr ""
"Python2で動作しています。この環境では非アスキー文字を含むモジュールをインポー"
"トできません。"
-#: spyder/plugins/maininterpreter.py:214
+#: spyder/plugins/maininterpreter.py:223
msgid ""
"The following modules are not installed on your machine:\n"
"%s"
@@ -2878,7 +2973,7 @@ msgstr ""
"以下のモジュールがコンピュータにインストールされていません:\n"
"%s"
-#: spyder/plugins/maininterpreter.py:218
+#: spyder/plugins/maininterpreter.py:227
msgid ""
"Please note that these changes will be applied only to new Python/IPython "
"consoles"
@@ -2894,40 +2989,40 @@ msgstr "オンラインヘルプ"
msgid "Outline"
msgstr "アウトライン"
-#: spyder/plugins/projects.py:83 spyder/widgets/projects/explorer.py:112
+#: spyder/plugins/projects.py:77 spyder/widgets/projects/explorer.py:112
#: spyder/widgets/projects/explorer.py:126
msgid "Project explorer"
msgstr "プロジェクトエクスプローラー"
-#: spyder/plugins/projects.py:95
+#: spyder/plugins/projects.py:89
msgid "New Project..."
msgstr "新規プロジェクト..."
-#: spyder/plugins/projects.py:98
+#: spyder/plugins/projects.py:92
msgid "Open Project..."
msgstr "プロジェクトを開く..."
-#: spyder/plugins/projects.py:101
+#: spyder/plugins/projects.py:95
msgid "Close Project"
msgstr "プロジェクトを閉じる..."
-#: spyder/plugins/projects.py:104
+#: spyder/plugins/projects.py:98
msgid "Delete Project"
msgstr "プロジェクトを削除する"
-#: spyder/plugins/projects.py:110
+#: spyder/plugins/projects.py:104
msgid "Project Preferences"
msgstr "プロジェクト設定"
-#: spyder/plugins/projects.py:112
+#: spyder/plugins/projects.py:106
msgid "Recent Projects"
msgstr "最近開いたプロジェクト"
-#: spyder/plugins/projects.py:249
+#: spyder/plugins/projects.py:264
msgid "Open project"
msgstr "プロジェクトを開く"
-#: spyder/plugins/projects.py:255
+#: spyder/plugins/projects.py:270
msgid "%s is not a Spyder project!"
msgstr "%s はSpyderプロジェクトではありません!"
@@ -2957,7 +3052,7 @@ msgstr "エラーが発生した場合直接デバッグモードに入る"
#: spyder/plugins/runconfig.py:47
msgid "Interact with the Python console after execution"
-msgstr "実行後Pythonコンソールと相互作用する"
+msgstr "実行後Pythonコンソールと対話する"
#: spyder/plugins/runconfig.py:49
msgid "The directory of the file being executed"
@@ -2965,7 +3060,7 @@ msgstr "現在実行しているファイルのディレクトリ\t"
#: spyder/plugins/runconfig.py:50 spyder/plugins/workingdirectory.py:56
msgid "The current working directory"
-msgstr "現在の作業ディレクトリ設定"
+msgstr "現在の作業ディレクトリ"
#: spyder/plugins/runconfig.py:51
msgid "The following directory:"
@@ -3096,7 +3191,7 @@ msgid "Context"
msgstr "コンテキスト"
#: spyder/plugins/shortcuts.py:587
-#: spyder/widgets/variableexplorer/collectionseditor.py:128
+#: spyder/widgets/variableexplorer/collectionseditor.py:153
msgid "Name"
msgstr "名前"
@@ -3136,36 +3231,44 @@ msgstr "ショートカットのリセット"
msgid "Do you want to reset to default values?"
msgstr "デフォルト値に戻しますか?"
-#: spyder/plugins/variableexplorer.py:25
+#: spyder/plugins/variableexplorer.py:24
+msgid "View and edit DataFrames and Series in the Variable Explorer"
+msgstr "変数エクスプローラーでのDataFrameとSeriesの表示・編集"
+
+#: spyder/plugins/variableexplorer.py:29
+msgid "View and edit two and three dimensional arrays in the Variable Explorer"
+msgstr "変数エクスプローラーでの2, 3次元配列の表示・編集"
+
+#: spyder/plugins/variableexplorer.py:37
msgid "Filter"
msgstr "フィルター"
-#: spyder/plugins/variableexplorer.py:27
-#: spyder/widgets/variableexplorer/namespacebrowser.py:200
+#: spyder/plugins/variableexplorer.py:39
+#: spyder/widgets/variableexplorer/namespacebrowser.py:203
msgid "Exclude private references"
msgstr "privateな参照を除外"
-#: spyder/plugins/variableexplorer.py:28
-#: spyder/widgets/variableexplorer/namespacebrowser.py:215
+#: spyder/plugins/variableexplorer.py:40
+#: spyder/widgets/variableexplorer/namespacebrowser.py:218
msgid "Exclude capitalized references"
msgstr "大文字で始まる参照を除外"
-#: spyder/plugins/variableexplorer.py:29
-#: spyder/widgets/variableexplorer/namespacebrowser.py:208
+#: spyder/plugins/variableexplorer.py:41
+#: spyder/widgets/variableexplorer/namespacebrowser.py:211
msgid "Exclude all-uppercase references"
msgstr "名前が全て大文字の参照を除外"
-#: spyder/plugins/variableexplorer.py:30
-#: spyder/widgets/variableexplorer/namespacebrowser.py:223
+#: spyder/plugins/variableexplorer.py:42
+#: spyder/widgets/variableexplorer/namespacebrowser.py:226
msgid "Exclude unsupported data types"
msgstr "非サポートのデータ型を除外"
-#: spyder/plugins/variableexplorer.py:36
-#: spyder/widgets/variableexplorer/collectionseditor.py:702
+#: spyder/plugins/variableexplorer.py:48
+#: spyder/widgets/variableexplorer/collectionseditor.py:738
msgid "Show arrays min/max"
msgstr "配列の最小/最大を表示"
-#: spyder/plugins/variableexplorer.py:178
+#: spyder/plugins/variableexplorer.py:202
msgid "Variable explorer"
msgstr "変数エクスプローラー"
@@ -3207,12 +3310,12 @@ msgstr ""
msgid "Back"
msgstr "戻る"
-#: spyder/plugins/workingdirectory.py:132 spyder/widgets/explorer.py:1194
+#: spyder/plugins/workingdirectory.py:130 spyder/widgets/explorer.py:1199
#: spyder/widgets/variableexplorer/importwizard.py:539
msgid "Next"
msgstr "次"
-#: spyder/plugins/workingdirectory.py:143
+#: spyder/plugins/workingdirectory.py:141
msgid ""
"This is the working directory for newly\n"
"opened consoles (Python/IPython consoles and\n"
@@ -3226,31 +3329,37 @@ msgstr ""
"及びエディタで作成した新規ファイルの\n"
"作業ディレクトリです。"
-#: spyder/plugins/workingdirectory.py:168
+#: spyder/plugins/workingdirectory.py:166
msgid "Browse a working directory"
msgstr "作業ディレクトリを表示"
-#: spyder/plugins/workingdirectory.py:175
+#: spyder/plugins/workingdirectory.py:173
msgid "Change to parent directory"
msgstr "親ディレクトリへ移動"
-#: spyder/plugins/workingdirectory.py:182 spyder/widgets/findinfiles.py:225
+#: spyder/plugins/workingdirectory.py:180 spyder/widgets/findinfiles.py:240
msgid "Current working directory"
msgstr "現在の作業ディレクトリ"
-#: spyder/utils/codeanalysis.py:92
+#: spyder/utils/codeanalysis.py:94
msgid "Real-time code analysis on the Editor"
msgstr "エディタ上でのリアルタイムコード分析"
-#: spyder/utils/codeanalysis.py:96
+#: spyder/utils/codeanalysis.py:98
msgid "Real-time code style analysis on the Editor"
msgstr "エディタ上でのリアルタイムコードスタイル分析"
-#: spyder/utils/environ.py:46
+#: spyder/utils/environ.py:48
msgid "Environment variables"
msgstr "環境変数"
-#: spyder/utils/environ.py:96
+#: spyder/utils/environ.py:57
+msgid ""
+"An error occurred while trying to show your environment variables. The error "
+"was
{0}"
+msgstr "環境変数の表示中にエラーが発生しました。エラーは
{0}"
+
+#: spyder/utils/environ.py:108
msgid ""
"Module pywin32 was not found.
Please restart this Windows "
"session (not the computer) for changes to take effect."
@@ -3258,7 +3367,7 @@ msgstr ""
"モジュール pywin32 は見つかりませんでした。
変更を反映させるには(コ"
"ンピュータではなく)このWindowsセッション を再起動して。"
-#: spyder/utils/environ.py:109
+#: spyder/utils/environ.py:121
msgid ""
"If you accept changes, this will modify the current user environment "
"variables directly in Windows registry. Use it with precautions, at "
@@ -3275,7 +3384,7 @@ msgstr ""
"Python(x,y) HomeのようにSpyderを実行しているアプリケーションを全て再起"
"動する)"
-#: spyder/utils/help/sphinxify.py:217 spyder/utils/help/sphinxify.py:227
+#: spyder/utils/help/sphinxify.py:216 spyder/utils/help/sphinxify.py:226
msgid ""
"It was not possible to generate rich text help for this object.Please "
"see it in plain text."
@@ -3288,133 +3397,76 @@ msgstr ""
msgid "Editor's code completion, go-to-definition and help"
msgstr "エディタのコード補完、go-to-definition及びヘルプ"
-#: spyder/utils/iofuncs.py:408
-msgid "Supported files"
-msgstr "サポートされているファイル"
-
-#: spyder/utils/iofuncs.py:410
-msgid "All files (*.*)"
-msgstr "すべてのファイル (*.*)"
-
-#: spyder/utils/iofuncs.py:420
-msgid "Spyder data files"
-msgstr "Spyderデータファイル"
-
-#: spyder/utils/iofuncs.py:422
-#: spyder/widgets/variableexplorer/collectionseditor.py:1061
-msgid "NumPy arrays"
-msgstr "NumPy配列"
-
-#: spyder/utils/iofuncs.py:423
-msgid "NumPy zip arrays"
-msgstr "NumPy zip配列"
-
-#: spyder/utils/iofuncs.py:424
-msgid "Matlab files"
-msgstr "Matlabファイル"
-
-#: spyder/utils/iofuncs.py:425
-msgid "CSV text files"
-msgstr "CSVテキストファイル"
-
-#: spyder/utils/iofuncs.py:427
-msgid "JPEG images"
-msgstr "JPEG画像"
-
-#: spyder/utils/iofuncs.py:428
-msgid "PNG images"
-msgstr "PNG画像"
-
-#: spyder/utils/iofuncs.py:429
-msgid "GIF images"
-msgstr "GIF画像"
-
-#: spyder/utils/iofuncs.py:430
-msgid "TIFF images"
-msgstr "TIFF画像"
-
-#: spyder/utils/iofuncs.py:431 spyder/utils/iofuncs.py:432
-msgid "Pickle files"
-msgstr "Pickleファイル"
-
-#: spyder/utils/iofuncs.py:433
-msgid "JSON files"
-msgstr "JSONファイル"
-
-#: spyder/utils/iofuncs.py:452 spyder/utils/iofuncs.py:459
-msgid "Unsupported file type '%s'"
-msgstr "非サポートファイルタイプ '%s'"
-
-#: spyder/utils/programs.py:287
+#: spyder/utils/programs.py:308
msgid "It was not possible to run this file in an external terminal"
msgstr "このファイルを外部ターミナルで実行できませんでした"
-#: spyder/utils/syntaxhighlighters.py:34
+#: spyder/utils/syntaxhighlighters.py:35
msgid "Syntax highlighting for Matlab, Julia and other file types"
msgstr "Matbal、Julia及びたのファイルタイプの構文強調"
-#: spyder/utils/syntaxhighlighters.py:43
+#: spyder/utils/syntaxhighlighters.py:44
msgid "Background:"
msgstr "バックグラウンド:"
-#: spyder/utils/syntaxhighlighters.py:44
+#: spyder/utils/syntaxhighlighters.py:45
#: spyder/widgets/sourcecode/codeeditor.py:107
msgid "Current line:"
msgstr "現在行:"
-#: spyder/utils/syntaxhighlighters.py:45
+#: spyder/utils/syntaxhighlighters.py:46
msgid "Current cell:"
-msgstr "現在セル:"
+msgstr "現在cell:"
-#: spyder/utils/syntaxhighlighters.py:46
+#: spyder/utils/syntaxhighlighters.py:47
msgid "Occurrence:"
msgstr "事象:"
-#: spyder/utils/syntaxhighlighters.py:47
+#: spyder/utils/syntaxhighlighters.py:48
msgid "Link:"
msgstr "リンク:"
-#: spyder/utils/syntaxhighlighters.py:48
+#: spyder/utils/syntaxhighlighters.py:49
msgid "Side areas:"
msgstr "サイドエリア:"
-#: spyder/utils/syntaxhighlighters.py:49
+#: spyder/utils/syntaxhighlighters.py:50
msgid "Matched
parens:"
msgstr "閉じた
括弧:"
-#: spyder/utils/syntaxhighlighters.py:50
+#: spyder/utils/syntaxhighlighters.py:51
msgid "Unmatched
parens:"
msgstr "閉じていない
括弧:"
-#: spyder/utils/syntaxhighlighters.py:51
+#: spyder/utils/syntaxhighlighters.py:52
msgid "Normal text:"
msgstr "通常テキスト:"
-#: spyder/utils/syntaxhighlighters.py:52
+#: spyder/utils/syntaxhighlighters.py:53
msgid "Keyword:"
msgstr "キーワード:"
-#: spyder/utils/syntaxhighlighters.py:53
+#: spyder/utils/syntaxhighlighters.py:54
msgid "Builtin:"
msgstr "組み込み:"
-#: spyder/utils/syntaxhighlighters.py:54
+#: spyder/utils/syntaxhighlighters.py:55
msgid "Definition:"
msgstr "定義:"
-#: spyder/utils/syntaxhighlighters.py:55
+#: spyder/utils/syntaxhighlighters.py:56
msgid "Comment:"
msgstr "コメント:"
-#: spyder/utils/syntaxhighlighters.py:56
+#: spyder/utils/syntaxhighlighters.py:57
msgid "String:"
msgstr "文字列:"
-#: spyder/utils/syntaxhighlighters.py:57
+#: spyder/utils/syntaxhighlighters.py:58
msgid "Number:"
msgstr "数字:"
-#: spyder/utils/syntaxhighlighters.py:58
+#: spyder/utils/syntaxhighlighters.py:59
msgid "Instance:"
msgstr "インスタンス:"
@@ -3458,7 +3510,7 @@ msgstr ""
"\n"
" Numpy 配列/行列 ヘルパー
\n"
" テーブルに配列を入力してください。
\n"
-" セル間の移動にはタブを使います。\n"
+" cell間の移動にはタブを使います。\n"
"
\n"
" 配列入力には'Enter'を、行列入力には 'Ctrl+Enter'を。\n"
"
\n"
@@ -3470,39 +3522,39 @@ msgstr ""
msgid "Array dimensions not valid"
msgstr "配列の次元が不正"
-#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2731
+#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2738
msgid "Zoom out"
msgstr "ズームアウト"
-#: spyder/widgets/browser.py:61 spyder/widgets/sourcecode/codeeditor.py:2727
+#: spyder/widgets/browser.py:61 spyder/widgets/sourcecode/codeeditor.py:2734
msgid "Zoom in"
msgstr "ズームイン"
-#: spyder/widgets/browser.py:213
+#: spyder/widgets/browser.py:216
msgid "Home"
msgstr "ホーム"
-#: spyder/widgets/browser.py:249
+#: spyder/widgets/browser.py:252
msgid "Find text"
msgstr "テキスト検索"
-#: spyder/widgets/browser.py:266
+#: spyder/widgets/browser.py:269
msgid "Address:"
msgstr "アドレス:"
-#: spyder/widgets/browser.py:302
+#: spyder/widgets/browser.py:305
msgid "Unable to load page"
msgstr "ページをロードできません"
-#: spyder/widgets/comboboxes.py:164
+#: spyder/widgets/comboboxes.py:165
msgid "Press enter to validate this entry"
msgstr "入力を検証するにはエンターキーを押してください"
-#: spyder/widgets/comboboxes.py:165
+#: spyder/widgets/comboboxes.py:166
msgid "This entry is incorrect"
msgstr "この入力は不正です"
-#: spyder/widgets/comboboxes.py:208
+#: spyder/widgets/comboboxes.py:209
msgid "Press enter to validate this path"
msgstr "パスを検証するにはエンターキーを押してください"
@@ -3520,7 +3572,7 @@ msgstr "インストール済み"
#: spyder/widgets/dependencies.py:64
msgid "Provided features"
-msgstr "利用できる機能"
+msgstr "提供される機能"
#: spyder/widgets/dependencies.py:134
msgid "Dependencies"
@@ -3537,99 +3589,100 @@ msgid ""
msgstr ""
"全てのペインが正しく機能するために、Spyderは複数のPythonモジュールに依存して"
"います。 下記のテーブルには必要なモジュールとインストール済みモジュールのバー"
-"ジョンを示します。
注: 以下のモジュールはインストールしなくても"
-"Spyderを安全に使用できます。:%s 、%s.
新たに発生した依存"
-"関係及び解決された依存関係はSpyderを再起動するまで正しく認識されません"
+"ジョンを表示しています。
注: 以下のモジュールはインストールしな"
+"くてもSpyderを安全に使用できます。:%s ,%s.
新たに発生し"
+"た依存関係及び解決された依存関係はSpyderを再起動するまで正しく認識されません"
#: spyder/widgets/dependencies.py:157
msgid "Copy to clipboard"
msgstr "クリップボードにコピー"
-#: spyder/widgets/editor.py:501
+#: spyder/widgets/editor.py:511
msgid "Find symbols in file..."
msgstr "ファイル中のシンボル検索..."
-#: spyder/widgets/editor.py:504
+#: spyder/widgets/editor.py:514
msgid "Copy path to clipboard"
msgstr "パスをクリップボードにコピー"
-#: spyder/widgets/editor.py:508
+#: spyder/widgets/editor.py:518
msgid "Close all to the right"
msgstr "全体を右側へ閉じる"
-#: spyder/widgets/editor.py:510
+#: spyder/widgets/editor.py:520
msgid "Close all but this"
msgstr "他を閉じる"
-#: spyder/widgets/editor.py:514 spyder/widgets/explorer.py:370
+#: spyder/widgets/editor.py:524 spyder/widgets/explorer.py:373
msgid "Show in Finder"
msgstr "Finderで表示"
-#: spyder/widgets/editor.py:516 spyder/widgets/explorer.py:372
+#: spyder/widgets/editor.py:526 spyder/widgets/explorer.py:375
msgid "Show in external file explorer"
msgstr "外部ファイルエクスプローラーで表示"
-#: spyder/widgets/editor.py:1193
+#: spyder/widgets/editor.py:1201
msgid "Temporary file"
msgstr "一時ファイル"
-#: spyder/widgets/editor.py:1279
+#: spyder/widgets/editor.py:1287
msgid "New window"
msgstr "新しいウインドウ"
-#: spyder/widgets/editor.py:1280
+#: spyder/widgets/editor.py:1288
msgid "Create a new editor window"
msgstr "新しいエディタウインドウを作成する"
-#: spyder/widgets/editor.py:1283
+#: spyder/widgets/editor.py:1291
msgid "Split vertically"
msgstr "縦に分割する"
-#: spyder/widgets/editor.py:1285
+#: spyder/widgets/editor.py:1293
msgid "Split vertically this editor window"
msgstr "このエディタウインドウを縦に分割する"
-#: spyder/widgets/editor.py:1287
+#: spyder/widgets/editor.py:1295
msgid "Split horizontally"
msgstr "横に分割"
-#: spyder/widgets/editor.py:1289
+#: spyder/widgets/editor.py:1297
msgid "Split horizontally this editor window"
msgstr "このエディタウインドウを横に分割"
-#: spyder/widgets/editor.py:1291
+#: spyder/widgets/editor.py:1299
msgid "Close this panel"
msgstr "このパネルを閉じる"
-#: spyder/widgets/editor.py:1531
+#: spyder/widgets/editor.py:1534
msgid "%s has been modified.
Do you want to save changes?"
msgstr "%s は変更されています。
保存しますか?"
-#: spyder/widgets/editor.py:1617 spyder/widgets/editor.py:1780
-msgid "Save"
-msgstr "保存"
+#: spyder/widgets/editor.py:1620 spyder/widgets/editor.py:1783
+#: spyder/widgets/explorer.py:82
+msgid "Save Error"
+msgstr "エラーを保存"
-#: spyder/widgets/editor.py:1618 spyder/widgets/editor.py:1781
-#: spyder/widgets/shell.py:267
+#: spyder/widgets/editor.py:1621 spyder/widgets/editor.py:1784
+#: spyder/widgets/explorer.py:83
msgid "Unable to save file '%s'
Error message:
%s"
msgstr "ファイル '%s' を保存できません
エラーメッセージ:
%s"
-#: spyder/widgets/editor.py:1968
+#: spyder/widgets/editor.py:1971
msgid ""
"%s is unavailable (this file may have been removed, moved or renamed "
"outside Spyder).
Do you want to close it?"
msgstr ""
-"%s は利用できません (このファイルはSpypder外で削除、移動あるいは名前変"
+"%s は利用できません (このファイルはSpyder外で削除、移動あるいは名前変"
"更されています)。
閉じますか?"
-#: spyder/widgets/editor.py:1991
+#: spyder/widgets/editor.py:1994
msgid ""
"%s has been modified outside Spyder.
Do you want to reload it and "
"lose all your changes?"
msgstr ""
"%s はSpyderの外で変更されています。
変更を破棄して再読込しますか?"
-#: spyder/widgets/editor.py:2101
+#: spyder/widgets/editor.py:2104
msgid ""
"All changes to %s will be lost.
Do you want to revert file from "
"disk?"
@@ -3637,11 +3690,11 @@ msgstr ""
"%s へのすべての変更は失われます。
ファイルをディスクから復帰させま"
"すか?"
-#: spyder/widgets/editor.py:2245
+#: spyder/widgets/editor.py:2250
msgid "Loading %s..."
msgstr "%s をロードしています..."
-#: spyder/widgets/editor.py:2257
+#: spyder/widgets/editor.py:2262
msgid ""
"%s contains mixed end-of-line characters.
Spyder will fix this "
"automatically."
@@ -3649,11 +3702,11 @@ msgstr ""
"%s は複数種の改行コードを含んでいます。
Spyderは自動的に修正しま"
"す。"
-#: spyder/widgets/editor.py:2664
+#: spyder/widgets/editor.py:2672
msgid "Close window"
msgstr "ウインドウを閉じる"
-#: spyder/widgets/editor.py:2666
+#: spyder/widgets/editor.py:2674
msgid "Close this window"
msgstr "このウインドウを閉じる"
@@ -3675,7 +3728,7 @@ msgstr "%s 行で定義されている関数"
#: spyder/widgets/editortools.py:149
msgid "Cell starts at line %s"
-msgstr "%s 行から始まるセル"
+msgstr "%s 行から始まるcell"
#: spyder/widgets/editortools.py:201 spyder/widgets/editortools.py:527
msgid "Go to cursor position"
@@ -3685,7 +3738,7 @@ msgstr "カーソル位置へ移動"
msgid "Show absolute path"
msgstr "絶対パスを表示"
-#: spyder/widgets/editortools.py:207 spyder/widgets/explorer.py:283
+#: spyder/widgets/editortools.py:207 spyder/widgets/explorer.py:286
msgid "Show all files"
msgstr "全てのファイルを表示"
@@ -3697,111 +3750,111 @@ msgstr "特別なコメントを表示"
msgid "Show/hide outline explorer"
msgstr "アウトラインエクスプローラーの表示/隠す"
-#: spyder/widgets/explorer.py:279
+#: spyder/widgets/explorer.py:282
msgid "Edit filename filters..."
msgstr "ファイル名フィルターを編集..."
-#: spyder/widgets/explorer.py:293
+#: spyder/widgets/explorer.py:296
msgid "Edit filename filters"
msgstr "ファイル名フィルターを編集"
-#: spyder/widgets/explorer.py:294
+#: spyder/widgets/explorer.py:297
msgid "Name filters:"
msgstr "フィルター:"
-#: spyder/widgets/explorer.py:313
+#: spyder/widgets/explorer.py:316
msgid "File..."
msgstr "ファイル..."
-#: spyder/widgets/explorer.py:317
+#: spyder/widgets/explorer.py:320
msgid "Module..."
msgstr "モジュール..."
-#: spyder/widgets/explorer.py:321
+#: spyder/widgets/explorer.py:324
msgid "Folder..."
msgstr "フォルダー..."
-#: spyder/widgets/explorer.py:325
+#: spyder/widgets/explorer.py:328
msgid "Package..."
msgstr "パッケージ..."
-#: spyder/widgets/explorer.py:346
-#: spyder/widgets/variableexplorer/collectionseditor.py:677
+#: spyder/widgets/explorer.py:349
+#: spyder/widgets/variableexplorer/collectionseditor.py:713
msgid "Edit"
msgstr "編集"
-#: spyder/widgets/explorer.py:348
+#: spyder/widgets/explorer.py:351
msgid "Move..."
msgstr "移動..."
-#: spyder/widgets/explorer.py:351
+#: spyder/widgets/explorer.py:354
msgid "Delete..."
msgstr "削除..."
-#: spyder/widgets/explorer.py:354
+#: spyder/widgets/explorer.py:357
msgid "Rename..."
msgstr "リネーム..."
-#: spyder/widgets/explorer.py:357
+#: spyder/widgets/explorer.py:360
msgid "Open"
msgstr "開く"
-#: spyder/widgets/explorer.py:358 spyder/widgets/sourcecode/codeeditor.py:2699
+#: spyder/widgets/explorer.py:361 spyder/widgets/sourcecode/codeeditor.py:2706
msgid "Convert to Python script"
msgstr "Pythonスクリプトへ変換"
-#: spyder/widgets/explorer.py:399
+#: spyder/widgets/explorer.py:393
msgid "Commit"
msgstr "コミット"
-#: spyder/widgets/explorer.py:402
+#: spyder/widgets/explorer.py:396
msgid "Browse repository"
msgstr "レポジトリを表示"
-#: spyder/widgets/explorer.py:413
+#: spyder/widgets/explorer.py:407
msgid "Open command prompt here"
msgstr "コマンドプロンプトをここで開く"
-#: spyder/widgets/explorer.py:415
+#: spyder/widgets/explorer.py:409
msgid "Open terminal here"
msgstr "ターミナルをここで開く"
-#: spyder/widgets/explorer.py:416
+#: spyder/widgets/explorer.py:410
msgid "Open IPython console here"
msgstr "IPythonコンソールをここで開く"
-#: spyder/widgets/explorer.py:430
+#: spyder/widgets/explorer.py:424
msgid "New"
msgstr "新規"
-#: spyder/widgets/explorer.py:438
+#: spyder/widgets/explorer.py:432
msgid "Import"
msgstr "インポート"
-#: spyder/widgets/explorer.py:584
+#: spyder/widgets/explorer.py:583
msgid "Do you really want to delete %s?"
msgstr "本当に %s を削除しますか?"
-#: spyder/widgets/explorer.py:602
+#: spyder/widgets/explorer.py:601
msgid "delete"
msgstr "削除"
-#: spyder/widgets/explorer.py:603 spyder/widgets/projects/explorer.py:148
+#: spyder/widgets/explorer.py:602 spyder/widgets/projects/explorer.py:148
#: spyder/widgets/projects/explorer.py:256
msgid "Project Explorer"
msgstr "プロジェクトエクスプローラー"
-#: spyder/widgets/explorer.py:604 spyder/widgets/projects/explorer.py:149
+#: spyder/widgets/explorer.py:603 spyder/widgets/projects/explorer.py:149
msgid "Unable to %s %s
Error message:
%s"
msgstr ""
"%s が %s に実行できませんでした。
エラーメッセージ:
"
"%s"
-#: spyder/widgets/explorer.py:619
+#: spyder/widgets/explorer.py:618
msgid "File Explorer"
msgstr "ファイルエクスプローラー"
-#: spyder/widgets/explorer.py:620
+#: spyder/widgets/explorer.py:619
msgid ""
"The current directory contains a project.
If you want to delete the "
"project, please go to Projects » Delete Project"
@@ -3810,11 +3863,11 @@ msgstr ""
"したい場合はプロジェクト » プロジェクトの削除を選択して下"
"さい"
-#: spyder/widgets/explorer.py:637 spyder/widgets/sourcecode/codeeditor.py:2160
+#: spyder/widgets/explorer.py:636 spyder/widgets/sourcecode/codeeditor.py:2167
msgid "Conversion error"
msgstr "変換エラー"
-#: spyder/widgets/explorer.py:638 spyder/widgets/sourcecode/codeeditor.py:2161
+#: spyder/widgets/explorer.py:637 spyder/widgets/sourcecode/codeeditor.py:2168
msgid ""
"It was not possible to convert this notebook. The error is:\n"
"\n"
@@ -3822,96 +3875,98 @@ msgstr ""
"notebookが変換できませんでした。エラー:\n"
"\n"
-#: spyder/widgets/explorer.py:655 spyder/widgets/explorer.py:663
-#: spyder/widgets/explorer.py:674
-#: spyder/widgets/variableexplorer/collectionseditor.py:706
-#: spyder/widgets/variableexplorer/collectionseditor.py:952
+#: spyder/widgets/explorer.py:654 spyder/widgets/explorer.py:662
+#: spyder/widgets/explorer.py:676
+#: spyder/widgets/variableexplorer/collectionseditor.py:742
+#: spyder/widgets/variableexplorer/collectionseditor.py:988
msgid "Rename"
msgstr "リネーム"
-#: spyder/widgets/explorer.py:656
+#: spyder/widgets/explorer.py:655
msgid "New name:"
msgstr "新しい名前:"
-#: spyder/widgets/explorer.py:664
+#: spyder/widgets/explorer.py:663
msgid ""
"Do you really want to rename %s and overwrite the existing file "
"%s?"
msgstr ""
"本当に %s をリネームし、既存ファイル %s を上書きしますか?"
-#: spyder/widgets/explorer.py:675
+#: spyder/widgets/explorer.py:677
msgid "Unable to rename file %s
Error message:
%s"
msgstr ""
"ファイル %s をリネームできません
エラーメッセージ:
%s"
-#: spyder/widgets/explorer.py:722
+#: spyder/widgets/explorer.py:724
msgid "Unable to move %s
Error message:
%s"
msgstr " %s を移動できません
エラーメッセージ:
%s"
-#: spyder/widgets/explorer.py:740
+#: spyder/widgets/explorer.py:742
msgid "Unable to create folder %s
Error message:
%s"
msgstr ""
"フォルダ %s を作成できません
エラーメッセージ:
%s"
-#: spyder/widgets/explorer.py:753 spyder/widgets/explorer.py:787
+#: spyder/widgets/explorer.py:755 spyder/widgets/explorer.py:789
msgid "Unable to create file %s
Error message:
%s"
msgstr ""
"ファイル %s を作成できません
エラーメッセージ:
%s"
-#: spyder/widgets/explorer.py:761
+#: spyder/widgets/explorer.py:763
msgid "New folder"
msgstr "新規フォルダー"
-#: spyder/widgets/explorer.py:762
+#: spyder/widgets/explorer.py:764
msgid "Folder name:"
msgstr "フォルダ名:"
-#: spyder/widgets/explorer.py:767
+#: spyder/widgets/explorer.py:769
msgid "New package"
msgstr "新規パッケージ"
-#: spyder/widgets/explorer.py:768
+#: spyder/widgets/explorer.py:770
msgid "Package name:"
msgstr "パッケージ名:"
-#: spyder/widgets/explorer.py:808
+#: spyder/widgets/explorer.py:810
msgid "New module"
msgstr "新規モジュール"
-#: spyder/widgets/explorer.py:823
+#: spyder/widgets/explorer.py:825
msgid ""
"For %s support, please install one of the
following tools:
%s"
msgstr ""
" %s をサポートするためには以下のツールをインストールしてください。
ツー"
"ル:
%s"
-#: spyder/widgets/explorer.py:827
+#: spyder/widgets/explorer.py:829
msgid "Unable to find external program.
%s"
msgstr "外部プログラムが見つかりません。
%s"
-#: spyder/widgets/explorer.py:1048
+#: spyder/widgets/explorer.py:1049
msgid "Show current directory only"
msgstr "現在のディレクトリのみを表示"
-#: spyder/widgets/explorer.py:1158
+#: spyder/widgets/explorer.py:1163
msgid "You don't have the right permissions to open this directory"
msgstr "このディレクトリを開く権限がありません"
-#: spyder/widgets/explorer.py:1189
+#: spyder/widgets/explorer.py:1194
msgid "Show icons and text"
msgstr "アイコンとテキストを表示"
-#: spyder/widgets/explorer.py:1191
+#: spyder/widgets/explorer.py:1196
#: spyder/widgets/variableexplorer/importwizard.py:535
msgid "Previous"
msgstr "前"
-#: spyder/widgets/explorer.py:1197
+#: spyder/widgets/explorer.py:1202
msgid "Parent"
msgstr "親"
#: spyder/widgets/fileswitcher.py:110
+#: spyder/plugins/pylint/widgets/pylintgui.py:364
+#: spyder/plugins/profiler/widgets/profilergui.py:296
msgid "unsaved file"
msgstr "保存されていないファイル"
@@ -3933,27 +3988,27 @@ msgstr ""
msgid "lines"
msgstr "行"
-#: spyder/widgets/findinfiles.py:124
+#: spyder/widgets/findinfiles.py:121
msgid "Unexpected error: see internal console"
msgstr "予期しないエラー: 内部コンソールを参照してください"
-#: spyder/widgets/findinfiles.py:152
+#: spyder/widgets/findinfiles.py:158
msgid "invalid regular expression"
msgstr "無効な正規表現"
-#: spyder/widgets/findinfiles.py:202
+#: spyder/widgets/findinfiles.py:217
msgid "permission denied errors were encountered"
msgstr "エラーが発生しました(権限がありません)"
-#: spyder/widgets/findinfiles.py:217
+#: spyder/widgets/findinfiles.py:232
msgid "Search directory"
msgstr "ディレクトリを検索"
-#: spyder/widgets/findinfiles.py:230
+#: spyder/widgets/findinfiles.py:245
msgid "Project"
msgstr "プロジェクト"
-#: spyder/widgets/findinfiles.py:231
+#: spyder/widgets/findinfiles.py:246
msgid ""
"Search in all files and directories present on the current project path (if "
"opened)"
@@ -3961,247 +4016,381 @@ msgstr ""
"現在のプロジェクトパス内に存在している(open可能な)全てのファイルとディレクト"
"リを検索"
-#: spyder/widgets/findinfiles.py:236
+#: spyder/widgets/findinfiles.py:251
msgid "File"
msgstr "ファイル"
-#: spyder/widgets/findinfiles.py:237
+#: spyder/widgets/findinfiles.py:252
msgid "Search in current opened file"
msgstr "現在開いているファイルを検索"
-#: spyder/widgets/findinfiles.py:242
+#: spyder/widgets/findinfiles.py:257
msgid "Select other directory"
msgstr "他のディレクトリを選択"
-#: spyder/widgets/findinfiles.py:243
+#: spyder/widgets/findinfiles.py:258
msgid "Search in other folder present on the file system"
msgstr "ファイルシステム上の他フォルダを検索"
-#: spyder/widgets/findinfiles.py:247
+#: spyder/widgets/findinfiles.py:262
msgid "Clear the list of other directories"
msgstr "ディレクトリリストをクリア"
-#: spyder/widgets/findinfiles.py:318
+#: spyder/widgets/findinfiles.py:333
msgid "Clear other directories"
msgstr "他のディレクトリをクリア"
-#: spyder/widgets/findinfiles.py:319
+#: spyder/widgets/findinfiles.py:334
msgid "Do you want to clear the list of other directories?"
msgstr "本当にディレクトリリストをクリアしますか?"
-#: spyder/widgets/findinfiles.py:415
+#: spyder/widgets/findinfiles.py:404 spyder/widgets/findreplace.py:52
+msgid "Regular expression error"
+msgstr "正規表現エラー"
+
+#: spyder/widgets/findinfiles.py:427
msgid "Search pattern"
msgstr "パターンを検索"
-#: spyder/widgets/findinfiles.py:418 spyder/widgets/findinfiles.py:458
-#: spyder/widgets/findreplace.py:99
+#: spyder/widgets/findinfiles.py:430 spyder/widgets/findinfiles.py:470
+#: spyder/widgets/findreplace.py:100
msgid "Regular expression"
msgstr "正規表現"
-#: spyder/widgets/findinfiles.py:421 spyder/widgets/findreplace.py:105
+#: spyder/widgets/findinfiles.py:433 spyder/widgets/findreplace.py:106
msgid "Case Sensitive"
msgstr "大文字/小文字を区別"
-#: spyder/widgets/findinfiles.py:432
+#: spyder/widgets/findinfiles.py:444
msgid "Search"
msgstr "検索"
-#: spyder/widgets/findinfiles.py:435
+#: spyder/widgets/findinfiles.py:447
msgid "Start search"
msgstr "検索開始"
-#: spyder/widgets/findinfiles.py:442
+#: spyder/widgets/findinfiles.py:454
msgid "Stop search"
msgstr "検索終了"
-#: spyder/widgets/findinfiles.py:452
-msgid "Excluded filenames pattern"
-msgstr "除外されるファイル名パターン"
+#: spyder/widgets/findinfiles.py:464
+msgid "Exclude pattern"
+msgstr "除外パターン"
-#: spyder/widgets/findinfiles.py:461
+#: spyder/widgets/findinfiles.py:473
msgid "Exclude:"
msgstr "除外:"
-#: spyder/widgets/findinfiles.py:470
+#: spyder/widgets/findinfiles.py:482
msgid "Search in:"
msgstr "検索:"
-#: spyder/widgets/findinfiles.py:499
+#: spyder/widgets/findinfiles.py:511
msgid "Hide advanced options"
msgstr "詳細オプションを隠す"
-#: spyder/widgets/findinfiles.py:502
+#: spyder/widgets/findinfiles.py:514
msgid "Show advanced options"
msgstr "詳細オプションを表示"
-#: spyder/widgets/findinfiles.py:759 spyder/widgets/findinfiles.py:843
+#: spyder/widgets/findinfiles.py:790 spyder/widgets/findinfiles.py:877
msgid "String not found"
msgstr "文字列が見つかりませんでした"
-#: spyder/widgets/findinfiles.py:845
+#: spyder/widgets/findinfiles.py:879
msgid "matches in"
msgstr "一致"
-#: spyder/widgets/findinfiles.py:846
+#: spyder/widgets/findinfiles.py:880
msgid "file"
msgstr "ファイル"
-#: spyder/widgets/findinfiles.py:878
+#: spyder/widgets/findinfiles.py:912
msgid " Scanning: {0}"
msgstr "スキャン中: {0}"
-#: spyder/widgets/findinfiles.py:880
+#: spyder/widgets/findinfiles.py:914
msgid " Searching for files in folder: {0}"
msgstr " フォルダ内のファイルを検索中: {0}"
-#: spyder/widgets/findinfiles.py:884
+#: spyder/widgets/findinfiles.py:918
msgid " Searching for files..."
msgstr " ファイルを検索しています..."
-#: spyder/widgets/findreplace.py:48
+#: spyder/widgets/findreplace.py:49
msgid "No matches"
msgstr "一致なし"
-#: spyder/widgets/findreplace.py:49 spyder/widgets/findreplace.py:50
-#: spyder/widgets/findreplace.py:72
+#: spyder/widgets/findreplace.py:50 spyder/widgets/findreplace.py:51
+#: spyder/widgets/findreplace.py:73
msgid "Search string"
msgstr "検索文字列"
-#: spyder/widgets/findreplace.py:51
-msgid "Regular expression error"
-msgstr "正規表現エラー"
-
-#: spyder/widgets/findreplace.py:111
+#: spyder/widgets/findreplace.py:112
msgid "Whole words"
msgstr "単語全体"
-#: spyder/widgets/findreplace.py:117
+#: spyder/widgets/findreplace.py:118
msgid "Highlight matches"
msgstr "一致箇所を強調"
-#: spyder/widgets/findreplace.py:131
+#: spyder/widgets/findreplace.py:132
msgid "Replace with:"
msgstr "以下で置換:"
-#: spyder/widgets/findreplace.py:133
+#: spyder/widgets/findreplace.py:134
msgid "Replace string"
msgstr "置換文字列"
-#: spyder/widgets/findreplace.py:137
+#: spyder/widgets/findreplace.py:138
msgid "Replace/find next"
msgstr "次へ置換/検索"
-#: spyder/widgets/findreplace.py:142
+#: spyder/widgets/findreplace.py:143
msgid "Replace selection"
msgstr "選択部分を置換"
-#: spyder/widgets/findreplace.py:150
+#: spyder/widgets/findreplace.py:151
msgid "Replace all"
msgstr "全て置換"
-#: spyder/widgets/findreplace.py:577
+#: spyder/widgets/findreplace.py:583
msgid "of"
msgstr "of"
-#: spyder/widgets/findreplace.py:581
+#: spyder/widgets/findreplace.py:587
msgid "matches"
msgstr "一致"
-#: spyder/widgets/findreplace.py:584
+#: spyder/widgets/findreplace.py:590
msgid "no matches"
msgstr "一致なし"
-#: spyder/widgets/internalshell.py:262
+#: spyder/widgets/github/backend.py:151
+msgid "Invalid credentials"
+msgstr "不正な認証情報"
+
+#: spyder/widgets/github/backend.py:152
+msgid "Failed to create Github issue, invalid credentials..."
+msgstr ""
+"Github issueの作成に失敗しました。認証情報が有効ではない可能性があります..."
+
+#: spyder/widgets/github/backend.py:159
+msgid "Failed to create issue"
+msgstr "issueの作成に失敗しました"
+
+#: spyder/widgets/github/backend.py:160
+msgid "Failed to create Github issue. Error %d"
+msgstr "Githubでのissueの作成に失敗しました。エラー %d"
+
+#: spyder/widgets/github/backend.py:167
+msgid "Issue created on Github"
+msgstr "IssueがGithub上に作成されました"
+
+#: spyder/widgets/github/backend.py:168
+msgid ""
+"Issue successfully created. Would you like to open the issue in your web "
+"browser?"
+msgstr "Issueの作成に成功しました。ブラウザでissueのページを開きますか?"
+
+#: spyder/widgets/github/backend.py:195
+msgid "Failed to store password"
+msgstr "パスワードの保存に失敗しました"
+
+#: spyder/widgets/github/backend.py:196
+msgid ""
+"It was not possible to securely save your password. You will be prompted for "
+"your Github credentials next time you want to report an issue."
+msgstr ""
+"安全な状態でパスワードを保存することができなかったか可能性があります。次回"
+"issueを報告する時に認証情報が確認されます。"
+
+#: spyder/widgets/github/backend.py:212
+msgid "Failed to store token"
+msgstr "トークンの保存に失敗しました"
+
+#: spyder/widgets/github/backend.py:213
+msgid ""
+"It was not possible to securely save your token. You will be prompted for "
+"your Github token next time you want to report an issue."
+msgstr ""
+"トークンが安全な状態で保存されなかった可能性があります。次回issue報告時に確認"
+"されます。"
+
+#: spyder/widgets/github/backend.py:237
+msgid "Failed to retrieve password"
+msgstr "パスワードの取得に失敗しました"
+
+#: spyder/widgets/github/backend.py:238
+msgid ""
+"It was not possible to retrieve your password. Please introduce it again."
+msgstr "パスワードを取得できませんでした。再度導入して下さい。"
+
+#: spyder/widgets/github/backend.py:249
+msgid "Failed to retrieve token"
+msgstr "トークンの取得に失敗しました"
+
+#: spyder/widgets/github/backend.py:250
+msgid "It was not possible to retrieve your token. Please introduce it again."
+msgstr "トークンの入手に失敗しました。再度導入して下さい。"
+
+#: spyder/widgets/github/gh_login.py:38
+msgid "Sign in to Github"
+msgstr "Githubへサインインする"
+
+#: spyder/widgets/github/gh_login.py:57
+msgid ""
+"For regular users, i.e. users without two-factor authentication "
+"enabled"
+msgstr "通常ユーザー、即ち2要素認証の無いユーザーが有効化"
+
+#: spyder/widgets/github/gh_login.py:62
+msgid "Username:"
+msgstr "ユーザー名:"
+
+#: spyder/widgets/github/gh_login.py:69
+msgid "Password: "
+msgstr "パスワード:"
+
+#: spyder/widgets/github/gh_login.py:81
+msgid "Remember me"
+msgstr "私の情報を記憶する"
+
+#: spyder/widgets/github/gh_login.py:82
+msgid "Spyder will save your credentials safely"
+msgstr "Spyderは認証情報を安全な状態で保存します"
+
+#: spyder/widgets/github/gh_login.py:99
+msgid "Password Only"
+msgstr "パスワードのみ"
+
+#: spyder/widgets/github/gh_login.py:105
+msgid ""
+"For users with two-factor authentication enabled, or who prefer a per-"
+"app token authentication.
You can go here "
+"and click \"Generate token\" at the bottom to create a new token to use for "
+"this, with the appropriate permissions."
+msgstr ""
+"2要素認証を有効化しているユーザー、あるいはアプリケーション単位での"
+"トークン認証を行いたいユーザーは、
以下のサイト(こち"
+"ら)へ行ってページ下部の\"Generate token\"をクリックし、適切な認証の下"
+"で新しいトークンを作成することができます。"
+
+#: spyder/widgets/github/gh_login.py:127
+msgid "Remember token"
+msgstr "トークンを記憶する"
+
+#: spyder/widgets/github/gh_login.py:128
+msgid "Spyder will save your token safely"
+msgstr "Spyderはトークンを安全な状態で保存しました"
+
+#: spyder/widgets/github/gh_login.py:145
+msgid "Access Token"
+msgstr "トークンへアクセス"
+
+#: spyder/widgets/github/gh_login.py:148
+msgid "Sign in"
+msgstr "サインイン"
+
+#: spyder/widgets/internalshell.py:263
msgid "Help..."
msgstr "ヘルプ..."
-#: spyder/widgets/internalshell.py:279
+#: spyder/widgets/internalshell.py:280
msgid "Shell special commands:"
msgstr "特別なシェルコマンド:"
-#: spyder/widgets/internalshell.py:280
+#: spyder/widgets/internalshell.py:281
msgid "Internal editor:"
msgstr "内部エディタ"
-#: spyder/widgets/internalshell.py:281
+#: spyder/widgets/internalshell.py:282
msgid "External editor:"
msgstr "外部エディタ"
-#: spyder/widgets/internalshell.py:282
+#: spyder/widgets/internalshell.py:283
msgid "Run script:"
msgstr "スクリプトを実行:"
-#: spyder/widgets/internalshell.py:283
+#: spyder/widgets/internalshell.py:284
msgid "Remove references:"
msgstr "参照を削除"
-#: spyder/widgets/internalshell.py:284
+#: spyder/widgets/internalshell.py:285
msgid "System commands:"
msgstr "システムコマンド:"
-#: spyder/widgets/internalshell.py:285
+#: spyder/widgets/internalshell.py:286
msgid "Python help:"
msgstr "Pythonヘルプ:"
-#: spyder/widgets/internalshell.py:286
+#: spyder/widgets/internalshell.py:287
msgid "GUI-based editor:"
msgstr "GUIエディタ:"
-#: spyder/widgets/ipythonconsole/client.py:272
+#: spyder/widgets/internalshell.py:418
+msgid ""
+"In order to use commands like \"raw_input\" or \"input\" run Spyder with the "
+"multithread option (--multithread) from a system terminal"
+msgstr ""
+"\"raw_input\"や\"input\"コマンドを使うには、Spyder実行時に端末でマルチスレッ"
+"ドオプション(--multithread)を付与して下さい。"
+
+#: spyder/widgets/ipythonconsole/client.py:308
msgid "An error ocurred while starting the kernel"
msgstr "カーネルを開始中にエラーが発生しました"
-#: spyder/widgets/ipythonconsole/client.py:313
-#: spyder/widgets/ipythonconsole/client.py:369
-#: spyder/widgets/ipythonconsole/client.py:402
-#: spyder/widgets/ipythonconsole/shell.py:233
-#: spyder/widgets/variableexplorer/namespacebrowser.py:193
+#: spyder/widgets/ipythonconsole/client.py:352
+#: spyder/widgets/ipythonconsole/client.py:408
+#: spyder/widgets/ipythonconsole/client.py:441
+#: spyder/widgets/ipythonconsole/shell.py:234
+#: spyder/widgets/variableexplorer/namespacebrowser.py:196
msgid "Remove all variables"
msgstr "全ての変数を削除"
-#: spyder/widgets/ipythonconsole/client.py:322
+#: spyder/widgets/ipythonconsole/client.py:361
msgid "Show environment variables"
msgstr "環境変数を表示"
-#: spyder/widgets/ipythonconsole/client.py:329
+#: spyder/widgets/ipythonconsole/client.py:368
msgid "Show sys.path contents"
msgstr "sys.pathの中身を表示"
-#: spyder/widgets/ipythonconsole/client.py:356
+#: spyder/widgets/ipythonconsole/client.py:395
msgid "Stop the current command"
msgstr "現在のコマンドを停止する"
-#: spyder/widgets/ipythonconsole/client.py:367
-#: spyder/widgets/variableexplorer/collectionseditor.py:699
-#: spyder/widgets/variableexplorer/collectionseditor.py:934
+#: spyder/widgets/ipythonconsole/client.py:406
+#: spyder/widgets/variableexplorer/collectionseditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:970
msgid "Remove"
msgstr "除去"
-#: spyder/widgets/ipythonconsole/client.py:390
+#: spyder/widgets/ipythonconsole/client.py:429
msgid "Inspect current object"
msgstr "現在のオブジェクトを調査する"
-#: spyder/widgets/ipythonconsole/client.py:396
+#: spyder/widgets/ipythonconsole/client.py:435
msgid "Clear line or block"
msgstr "ラインやブロックをクリアする"
-#: spyder/widgets/ipythonconsole/client.py:409
+#: spyder/widgets/ipythonconsole/client.py:448
msgid "Clear console"
msgstr "コンソールをクリアする"
-#: spyder/widgets/ipythonconsole/client.py:462
+#: spyder/widgets/ipythonconsole/client.py:507
msgid "Are you sure you want to restart the kernel?"
msgstr "本当にカーネルを再起動しますか?"
-#: spyder/widgets/ipythonconsole/client.py:464
+#: spyder/widgets/ipythonconsole/client.py:509
msgid "Restart kernel?"
msgstr "カーネルを再起動しますか?"
-#: spyder/widgets/ipythonconsole/client.py:476
+#: spyder/widgets/ipythonconsole/client.py:526
msgid "Error restarting kernel: %s\n"
msgstr "カーネルを開始中にエラーが発生しました:%s\n"
-#: spyder/widgets/ipythonconsole/client.py:484
+#: spyder/widgets/ipythonconsole/client.py:534
msgid ""
"
Restarting kernel...\n"
"
"
@@ -4209,36 +4398,36 @@ msgstr ""
"
カーネルを再起動しています...\n"
"
"
-#: spyder/widgets/ipythonconsole/client.py:488
+#: spyder/widgets/ipythonconsole/client.py:538
msgid "Cannot restart a kernel not started by Spyder\n"
msgstr "Spyder以外によって起動されたカーネルは再起動できません\n"
-#: spyder/widgets/ipythonconsole/client.py:597
+#: spyder/widgets/ipythonconsole/client.py:649
msgid "Connecting to kernel..."
msgstr "カーネルへ接続中..."
-#: spyder/widgets/ipythonconsole/help.py:128 spyder/widgets/mixins.py:712
+#: spyder/widgets/ipythonconsole/help.py:128 spyder/widgets/mixins.py:726
msgid "Arguments"
msgstr "引数"
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:129
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:138
msgid "Loading this kind of data while debugging is not supported."
msgstr "この種のデータのデバッグ中の読み込みはサポートされていません。"
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:148
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:157
msgid "Saving data while debugging is not supported."
msgstr "デバッグ中のデータ保存はサポートされていません。"
-#: spyder/widgets/ipythonconsole/shell.py:234
+#: spyder/widgets/ipythonconsole/shell.py:235
msgid ""
"All user-defined variables will be removed. Are you sure you want to proceed?"
msgstr "全てのユーザー定義変数は削除されます。本当に実行しますか?"
-#: spyder/widgets/ipythonconsole/shell.py:240
+#: spyder/widgets/ipythonconsole/shell.py:241
msgid "Don't show again."
msgstr "次回以降表示しない。"
-#: spyder/widgets/ipythonconsole/shell.py:264
+#: spyder/widgets/ipythonconsole/shell.py:266
msgid ""
"
Removing all variables...\n"
"
"
@@ -4246,15 +4435,15 @@ msgstr ""
"
全ての変数を削除しています…\n"
"
"
-#: spyder/widgets/ipythonconsole/shell.py:430
-msgid "Changing backend to Qt for Mayavi"
-msgstr "MayaviのバックエンドをQtに変更中"
+#: spyder/widgets/ipythonconsole/shell.py:432
+msgid "Changing backend to Qt4 for Mayavi"
+msgstr "MayaviのバックエンドをQt4に変更しています"
-#: spyder/widgets/ipythonconsole/shell.py:475
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel died, restarting"
msgstr "カーネル停止しました。再起動中"
-#: spyder/widgets/ipythonconsole/shell.py:475
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel restarting"
msgstr "カーネル再起動中"
@@ -4282,58 +4471,67 @@ msgstr "現在の選択を折りたたむ"
msgid "Expand selection"
msgstr "現在の選択を展開する"
-#: spyder/widgets/pathmanager.py:97
+#: spyder/widgets/pathmanager.py:98
msgid "Move to top"
msgstr "一番上へ移動"
-#: spyder/widgets/pathmanager.py:103
+#: spyder/widgets/pathmanager.py:104
msgid "Move up"
msgstr "上へ移動"
-#: spyder/widgets/pathmanager.py:109
+#: spyder/widgets/pathmanager.py:110
msgid "Move down"
msgstr "下へ移動"
-#: spyder/widgets/pathmanager.py:115
+#: spyder/widgets/pathmanager.py:116
msgid "Move to bottom"
msgstr "一番下へ移動"
-#: spyder/widgets/pathmanager.py:126 spyder/widgets/pathmanager.py:267
+#: spyder/widgets/pathmanager.py:127 spyder/widgets/pathmanager.py:270
+#: spyder/widgets/pathmanager.py:282
msgid "Add path"
msgstr "パスを追加"
-#: spyder/widgets/pathmanager.py:131 spyder/widgets/pathmanager.py:246
+#: spyder/widgets/pathmanager.py:132 spyder/widgets/pathmanager.py:247
msgid "Remove path"
msgstr "パスを削除"
-#: spyder/widgets/pathmanager.py:141
+#: spyder/widgets/pathmanager.py:142
msgid "Synchronize..."
msgstr "同期..."
-#: spyder/widgets/pathmanager.py:143
+#: spyder/widgets/pathmanager.py:144
msgid "Synchronize Spyder's path list with PYTHONPATH environment variable"
msgstr "SpyderのパスリストをPYTHONPATH環境変数に同期させる"
-#: spyder/widgets/pathmanager.py:155
+#: spyder/widgets/pathmanager.py:156
msgid "Synchronize"
msgstr "同期"
-#: spyder/widgets/pathmanager.py:156
+#: spyder/widgets/pathmanager.py:157
msgid ""
"This will synchronize Spyder's path list with PYTHONPATH environment "
"variable for current user, allowing you to run your Python modules outside "
"Spyder without having to configure sys.path.
Do you want to clear "
"contents of PYTHONPATH before adding Spyder's path list?"
msgstr ""
-"sys.pathを変更することなくSpypder外でPythonモジュールを実行できるように、"
+"sys.pathを変更することなくSpyder外でPythonモジュールを実行できるように、"
"Spyderのパスはユーザーの PYTHONPATH 環境変数に同期されます。 "
"
Spyderのパスリストを追加する前にPYTHONPATHの値をクリアしますか?"
-#: spyder/widgets/pathmanager.py:247
+#: spyder/widgets/pathmanager.py:248
msgid "Do you really want to remove selected path?"
msgstr "本当に選択したパスを削除しますか?"
-#: spyder/widgets/pathmanager.py:268
+#: spyder/widgets/pathmanager.py:271
+msgid ""
+"You are using Python 2 and the path selected has Unicode characters. The new "
+"path will not be added."
+msgstr ""
+"Python2が使われており、選択されたパスにユニコード文字が含まれています。新しい"
+"パスは追加されません。"
+
+#: spyder/widgets/pathmanager.py:283
msgid ""
"This directory is already included in Spyder path list.
Do you want to "
"move it to the top of the list?"
@@ -4459,7 +4657,7 @@ msgstr "作成"
msgid "Create new project"
msgstr "新規プロジェクト作成"
-#: spyder/widgets/projects/type/__init__.py:216
+#: spyder/widgets/projects/type/__init__.py:223
msgid "Empty project"
msgstr "空のプロジェクト"
@@ -4471,73 +4669,104 @@ msgstr "Pythonプロジェクト"
msgid "Python package"
msgstr "Pythonパッケージ"
-#: spyder/widgets/pydocgui.py:110
+#: spyder/widgets/pydocgui.py:117
msgid "Module or package:"
msgstr "モジュールあるいはパッケージ:"
-#: spyder/widgets/reporterror.py:121
-msgid "Spyder internal error"
-msgstr "Spyder内部エラー"
-
-#: spyder/widgets/reporterror.py:129
-msgid ""
-"Spyder has encountered an internal problem
\n"
-" Before reporting it, please consult our comprehensive \n"
-" Troubleshooting Guide \n"
-" which should help solve most issues, and search for \n"
-" known bugs matching your error \n"
-" message or problem description for a quicker solution.\n"
-"
\n"
-" If you don't find anything, please enter a detailed step-by-"
-"step \n"
-" description (in English) of what led up to the problem "
-"below. \n"
-" Issue reports without a clear way to reproduce them will be \n"
-" closed.
\n"
-" Thanks for helping us making Spyder better for everyone!\n"
-" "
-msgstr ""
-"Spyderで内部エラーが生じています
\n"
-" これをレポートする前に なるべく \n"
-" トラブルシュートガイドを参照し \n"
-" 既知のバグに該当していないか \n"
-" あるいは解決方法の記載がないか確認して下さい。\n"
-"
\n"
-" 見つからない場合には、どのような原因で生じたかを以下の一問一答"
-"式の\n"
-" 記述(英語)に詳細に入力して下さい。\n"
-" 再現するための情報が不足しているレポートは回答前にcloseされる\n"
-" 場合があります。
\n"
-" Spyderの品質向上にご協力頂きありがとうございます!\n"
-" "
-
-#: spyder/widgets/reporterror.py:163
-msgid "Hide all future errors this session"
-msgstr "このセッションでの以後のエラー全てを隠す"
-
-#: spyder/widgets/reporterror.py:171
+#: spyder/widgets/reporterror.py:128
+msgid "Issue reporter"
+msgstr "Issueレポーター"
+
+#: spyder/widgets/reporterror.py:136
+msgid "Please fill the following information"
+msgstr "以下の情報を入力して下さい"
+
+#: spyder/widgets/reporterror.py:138
+msgid "Spyder has encountered an internal problem!"
+msgstr "Spyderで内部エラーが発生しました!"
+
+#: spyder/widgets/reporterror.py:140
+msgid ""
+"{title}
Before reporting this problem, please consult our "
+"comprehensive Troubleshooting Guide "
+"which should help solve most issues, and search for known bugs matching your error message or problem "
+"description for a quicker solution."
+msgstr ""
+"{title}
この問題を報告する前に、 どうか トラブルシュートガイド を参照して下さい。これは大半"
+"の問題解決の助けになります。またより迅速に解決するために既知のバグリスト でエラーメッセージあるいは問題の概"
+"要を検索して下さい。"
+
+#: spyder/widgets/reporterror.py:158 spyder/widgets/reporterror.py:190
+msgid "{} more characters to go..."
+msgstr "{}文字入力可能です..."
+
+#: spyder/widgets/reporterror.py:162
+msgid "Title: {}"
+msgstr "タイトル: {}"
+
+#: spyder/widgets/reporterror.py:168
+msgid "Steps to reproduce: {}"
+msgstr "問題を再現するステップ {}"
+
+#: spyder/widgets/reporterror.py:169
+msgid ""
+"Please enter a detailed step-by-step description (in English) of what led up "
+"to the problem below. Issue reports without a clear way to reproduce them "
+"will be closed."
+msgstr ""
+"どのようにして問題が発生したか、以下の一問一答式の記述に詳細に入力して下さ"
+"い。状況を再現するための情報が不足しているレポートは回答前にcloseされる場合が"
+"あります。"
+
+#: spyder/widgets/reporterror.py:194
+msgid "Hide all future errors during this session"
+msgstr "このセッションでの以後のエラーを隠す"
+
+#: spyder/widgets/reporterror.py:201
msgid "Submit to Github"
msgstr "Githubへ送信する"
-#: spyder/widgets/reporterror.py:175 spyder/widgets/reporterror.py:227
+#: spyder/widgets/reporterror.py:205 spyder/widgets/reporterror.py:312
msgid "Show details"
msgstr "詳細の表示"
-#: spyder/widgets/reporterror.py:178
+#: spyder/widgets/reporterror.py:210
+#: spyder/widgets/variableexplorer/arrayeditor.py:740
+#: spyder/widgets/variableexplorer/collectionseditor.py:1397
+#: spyder/widgets/variableexplorer/dataframeeditor.py:756
+#: spyder/widgets/variableexplorer/texteditor.py:72
msgid "Close"
msgstr "閉じる"
-#: spyder/widgets/reporterror.py:235
+#: spyder/widgets/reporterror.py:286
+msgid ""
+"An error occurred while trying to send the issue to Github automatically. "
+"Would you like to open it manually?
If so, please make sure to paste "
+"your clipboard into the issue report box that will appear in a new browser "
+"tab before clicking Submit on that page."
+msgstr ""
+"Githubへissueを自動送信中にエラーが発生しました。手動で送信しますか?
"
+"その場合、ブラウザで開いたページのSubmitボタンを押す前に、レポートボッ"
+"クスにクリップボードの中身を貼り付けてているか確認して下さい。"
+
+#: spyder/widgets/reporterror.py:320
msgid "Hide details"
msgstr "詳細を非表示"
-#: spyder/widgets/reporterror.py:243
+#: spyder/widgets/reporterror.py:329 spyder/widgets/reporterror.py:337
msgid "more characters to go..."
msgstr "まだ入力可能です…"
-#: spyder/widgets/reporterror.py:245
-msgid "Submission enabled; thanks!"
-msgstr "レポートの送信が完了しました。ありがとう!"
+#: spyder/widgets/reporterror.py:331
+msgid "Description complete; thanks!"
+msgstr "入力が完了しました;感謝!"
+
+#: spyder/widgets/reporterror.py:339
+msgid "Title complete; thanks!"
+msgstr "タイトルが完了しました;感謝!"
#: spyder/widgets/shell.py:131
msgid "Save history log..."
@@ -4583,27 +4812,27 @@ msgstr "行へ移動:"
msgid "Line count:"
msgstr "行数:"
-#: spyder/widgets/sourcecode/codeeditor.py:1327
+#: spyder/widgets/sourcecode/codeeditor.py:1334
msgid "Breakpoint"
msgstr "ブレークポイント"
-#: spyder/widgets/sourcecode/codeeditor.py:1328
+#: spyder/widgets/sourcecode/codeeditor.py:1335
msgid "Condition:"
msgstr "条件:"
-#: spyder/widgets/sourcecode/codeeditor.py:1733
+#: spyder/widgets/sourcecode/codeeditor.py:1740
msgid "Code analysis"
msgstr "コード分析"
-#: spyder/widgets/sourcecode/codeeditor.py:1787
+#: spyder/widgets/sourcecode/codeeditor.py:1794
msgid "To do"
msgstr "To do"
-#: spyder/widgets/sourcecode/codeeditor.py:2147
+#: spyder/widgets/sourcecode/codeeditor.py:2154
msgid "Removal error"
msgstr "削除エラー"
-#: spyder/widgets/sourcecode/codeeditor.py:2148
+#: spyder/widgets/sourcecode/codeeditor.py:2155
msgid ""
"It was not possible to remove outputs from this notebook. The error is:\n"
"\n"
@@ -4611,15 +4840,15 @@ msgstr ""
"notebookからoutputを削除できませんでした。エラー:\n"
"\n"
-#: spyder/widgets/sourcecode/codeeditor.py:2696
+#: spyder/widgets/sourcecode/codeeditor.py:2703
msgid "Clear all ouput"
msgstr "全ての出力をクリア"
-#: spyder/widgets/sourcecode/codeeditor.py:2702
+#: spyder/widgets/sourcecode/codeeditor.py:2709
msgid "Go to definition"
msgstr "定義へ移動"
-#: spyder/widgets/sourcecode/codeeditor.py:2735
+#: spyder/widgets/sourcecode/codeeditor.py:2742
msgid "Zoom reset"
msgstr "ズームリセット"
@@ -4675,98 +4904,98 @@ msgstr "tabを表示"
msgid "Close current tab"
msgstr "現在のタブを閉じる"
-#: spyder/widgets/variableexplorer/arrayeditor.py:511
+#: spyder/widgets/variableexplorer/arrayeditor.py:509
msgid "It was not possible to copy values for this array"
msgstr "配列の値をコピーできませんでした"
-#: spyder/widgets/variableexplorer/arrayeditor.py:546
-#: spyder/widgets/variableexplorer/arrayeditor.py:579
-#: spyder/widgets/variableexplorer/dataframeeditor.py:703
-#: spyder/widgets/variableexplorer/dataframeeditor.py:748
+#: spyder/widgets/variableexplorer/arrayeditor.py:545
+#: spyder/widgets/variableexplorer/arrayeditor.py:578
+#: spyder/widgets/variableexplorer/dataframeeditor.py:728
+#: spyder/widgets/variableexplorer/dataframeeditor.py:787
msgid "Format"
msgstr "フォーマット"
-#: spyder/widgets/variableexplorer/arrayeditor.py:551
-#: spyder/widgets/variableexplorer/dataframeeditor.py:707
+#: spyder/widgets/variableexplorer/arrayeditor.py:550
+#: spyder/widgets/variableexplorer/dataframeeditor.py:732
msgid "Resize"
msgstr "リサイズ"
-#: spyder/widgets/variableexplorer/arrayeditor.py:554
-#: spyder/widgets/variableexplorer/dataframeeditor.py:711
+#: spyder/widgets/variableexplorer/arrayeditor.py:553
+#: spyder/widgets/variableexplorer/dataframeeditor.py:736
msgid "Background color"
msgstr "背景色"
-#: spyder/widgets/variableexplorer/arrayeditor.py:580
-#: spyder/widgets/variableexplorer/dataframeeditor.py:749
+#: spyder/widgets/variableexplorer/arrayeditor.py:579
+#: spyder/widgets/variableexplorer/dataframeeditor.py:788
msgid "Float formatting"
msgstr "浮動小数点フォーマット"
-#: spyder/widgets/variableexplorer/arrayeditor.py:588
+#: spyder/widgets/variableexplorer/arrayeditor.py:587
msgid "Format (%s) is incorrect"
msgstr "フォーマット (%s) が不正です"
-#: spyder/widgets/variableexplorer/arrayeditor.py:624
+#: spyder/widgets/variableexplorer/arrayeditor.py:625
msgid "Arrays with more than 3 dimensions are not supported"
msgstr "3次元以上の配列はサポートされていません"
-#: spyder/widgets/variableexplorer/arrayeditor.py:628
+#: spyder/widgets/variableexplorer/arrayeditor.py:629
msgid "The 'xlabels' argument length do no match array column number"
msgstr "'xlabels'引数の長さが配列の列数に一致していません"
-#: spyder/widgets/variableexplorer/arrayeditor.py:632
+#: spyder/widgets/variableexplorer/arrayeditor.py:633
msgid "The 'ylabels' argument length do no match array row number"
msgstr "'ylabels'引数の長さが配列の行数に一致していません"
-#: spyder/widgets/variableexplorer/arrayeditor.py:639
+#: spyder/widgets/variableexplorer/arrayeditor.py:640
msgid "%s arrays"
msgstr "%s 配列"
-#: spyder/widgets/variableexplorer/arrayeditor.py:640
+#: spyder/widgets/variableexplorer/arrayeditor.py:641
msgid "%s are currently not supported"
msgstr "%s は現在サポートされていません"
-#: spyder/widgets/variableexplorer/arrayeditor.py:647
+#: spyder/widgets/variableexplorer/arrayeditor.py:648
msgid "NumPy array"
msgstr "NumPy配列"
-#: spyder/widgets/variableexplorer/arrayeditor.py:649
-#: spyder/widgets/variableexplorer/arrayeditor.py:806
+#: spyder/widgets/variableexplorer/arrayeditor.py:650
+#: spyder/widgets/variableexplorer/arrayeditor.py:828
msgid "Array editor"
msgstr "配列エディタ"
-#: spyder/widgets/variableexplorer/arrayeditor.py:651
+#: spyder/widgets/variableexplorer/arrayeditor.py:652
msgid "read only"
msgstr "読み取り専用"
-#: spyder/widgets/variableexplorer/arrayeditor.py:681
+#: spyder/widgets/variableexplorer/arrayeditor.py:685
msgid "Record array fields:"
msgstr "配列のフィールドを記録:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Data"
msgstr "データ"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Mask"
msgstr "マスク"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Masked data"
msgstr "Maskedデータ"
-#: spyder/widgets/variableexplorer/arrayeditor.py:704
+#: spyder/widgets/variableexplorer/arrayeditor.py:708
msgid "Axis:"
msgstr "軸:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:709
+#: spyder/widgets/variableexplorer/arrayeditor.py:713
msgid "Index:"
msgstr "インデックス:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:722
+#: spyder/widgets/variableexplorer/arrayeditor.py:726
msgid "Warning: changes are applied separately"
msgstr "警告: 変更は別々に適用されます"
-#: spyder/widgets/variableexplorer/arrayeditor.py:723
+#: spyder/widgets/variableexplorer/arrayeditor.py:727
msgid ""
"For performance reasons, changes applied to masked array won't be reflected "
"in array's data (and vice-versa)."
@@ -4774,47 +5003,54 @@ msgstr ""
"実行性能に関する理由により、masked配列に適用された変更は配列内のデータには反"
"映されません(逆もまた同様)。"
-#: spyder/widgets/variableexplorer/collectionseditor.py:126
+#: spyder/widgets/variableexplorer/arrayeditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:1392
+#: spyder/widgets/variableexplorer/dataframeeditor.py:751
+#: spyder/widgets/variableexplorer/texteditor.py:67
+msgid "Save and Close"
+msgstr "保存して閉じる"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:151
msgid "Index"
msgstr "インデックス"
-#: spyder/widgets/variableexplorer/collectionseditor.py:131
+#: spyder/widgets/variableexplorer/collectionseditor.py:156
msgid "Tuple"
msgstr "タプル"
-#: spyder/widgets/variableexplorer/collectionseditor.py:134
+#: spyder/widgets/variableexplorer/collectionseditor.py:159
msgid "List"
msgstr "リスト"
-#: spyder/widgets/variableexplorer/collectionseditor.py:137
+#: spyder/widgets/variableexplorer/collectionseditor.py:162
msgid "Dictionary"
msgstr "ディクショナリ"
-#: spyder/widgets/variableexplorer/collectionseditor.py:139
+#: spyder/widgets/variableexplorer/collectionseditor.py:164
msgid "Key"
msgstr "キー"
-#: spyder/widgets/variableexplorer/collectionseditor.py:144
+#: spyder/widgets/variableexplorer/collectionseditor.py:169
msgid "Attribute"
msgstr "属性"
-#: spyder/widgets/variableexplorer/collectionseditor.py:148
+#: spyder/widgets/variableexplorer/collectionseditor.py:173
msgid "elements"
msgstr "要素"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Size"
msgstr "サイズ"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Type"
msgstr "型"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Value"
msgstr "値"
-#: spyder/widgets/variableexplorer/collectionseditor.py:417
+#: spyder/widgets/variableexplorer/collectionseditor.py:450
msgid ""
"Opening this variable can be slow\n"
"\n"
@@ -4824,7 +5060,7 @@ msgstr ""
"\n"
"続行しますか?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:428
+#: spyder/widgets/variableexplorer/collectionseditor.py:461
msgid ""
"Spyder was unable to retrieve the value of this variable from the console."
"
The error mesage was:
%s"
@@ -4832,146 +5068,162 @@ msgstr ""
"Spyderはコンソールから変数の値を読み取ることができませんでした。
エ"
"ラーメッセージ:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:608
+#: spyder/widgets/variableexplorer/collectionseditor.py:643
msgid "Edit item"
msgstr "アイテムを編集"
-#: spyder/widgets/variableexplorer/collectionseditor.py:609
+#: spyder/widgets/variableexplorer/collectionseditor.py:644
msgid "Unable to assign data to item.
Error message:
%s"
msgstr ""
"アイテムにデータを割り当てられません。
エラーメッセージ:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:669
+#: spyder/widgets/variableexplorer/collectionseditor.py:705
msgid "Resize rows to contents"
msgstr "行数を中身に応じて変更"
-#: spyder/widgets/variableexplorer/collectionseditor.py:680
-#: spyder/widgets/variableexplorer/collectionseditor.py:1030
-#: spyder/widgets/variableexplorer/collectionseditor.py:1047
+#: spyder/widgets/variableexplorer/collectionseditor.py:716
+#: spyder/widgets/variableexplorer/collectionseditor.py:1066
+#: spyder/widgets/variableexplorer/collectionseditor.py:1083
msgid "Plot"
msgstr "プロット"
-#: spyder/widgets/variableexplorer/collectionseditor.py:684
+#: spyder/widgets/variableexplorer/collectionseditor.py:720
msgid "Histogram"
msgstr "ヒストグラム"
-#: spyder/widgets/variableexplorer/collectionseditor.py:688
+#: spyder/widgets/variableexplorer/collectionseditor.py:724
msgid "Show image"
msgstr "画像を表示"
-#: spyder/widgets/variableexplorer/collectionseditor.py:692
-#: spyder/widgets/variableexplorer/collectionseditor.py:1055
+#: spyder/widgets/variableexplorer/collectionseditor.py:728
+#: spyder/widgets/variableexplorer/collectionseditor.py:1091
msgid "Save array"
msgstr "配列を保存"
-#: spyder/widgets/variableexplorer/collectionseditor.py:696
-#: spyder/widgets/variableexplorer/collectionseditor.py:994
-#: spyder/widgets/variableexplorer/collectionseditor.py:1002
+#: spyder/widgets/variableexplorer/collectionseditor.py:732
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Insert"
msgstr "挿入"
-#: spyder/widgets/variableexplorer/collectionseditor.py:709
-#: spyder/widgets/variableexplorer/collectionseditor.py:955
+#: spyder/widgets/variableexplorer/collectionseditor.py:745
+#: spyder/widgets/variableexplorer/collectionseditor.py:991
msgid "Duplicate"
msgstr "複製"
-#: spyder/widgets/variableexplorer/collectionseditor.py:932
+#: spyder/widgets/variableexplorer/collectionseditor.py:968
msgid "Do you want to remove the selected item?"
msgstr "選択されたアイテムを除去しますか?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:933
+#: spyder/widgets/variableexplorer/collectionseditor.py:969
msgid "Do you want to remove all selected items?"
msgstr "選択された全てのアイテムを除去しますか?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:953
+#: spyder/widgets/variableexplorer/collectionseditor.py:989
msgid "New variable name:"
msgstr "新しい変数名:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:956
+#: spyder/widgets/variableexplorer/collectionseditor.py:992
msgid "Variable name:"
msgstr "変数名:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:994
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
msgid "Key:"
msgstr "キー:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1002
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Value:"
msgstr "値:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1018
+#: spyder/widgets/variableexplorer/collectionseditor.py:1054
msgid "Import error"
msgstr "インポートエラー"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1019
+#: spyder/widgets/variableexplorer/collectionseditor.py:1055
msgid "Please install matplotlib or guiqwt."
msgstr "matplotlib か guiqwt をインストールしてください。"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1031
+#: spyder/widgets/variableexplorer/collectionseditor.py:1067
msgid "Unable to plot data.
Error message:
%s"
msgstr "データをプロットできません。
エラーメッセージ:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1048
+#: spyder/widgets/variableexplorer/collectionseditor.py:1084
msgid "Unable to show image.
Error message:
%s"
msgstr "画像を表示できません。
エラーメッセージ:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1071
+#: spyder/widgets/variableexplorer/collectionseditor.py:1097
+msgid "NumPy arrays"
+msgstr "NumPy配列"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1107
msgid "Unable to save array
Error message:
%s"
msgstr "配列を保存できません
エラーメッセージ:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1096
+#: spyder/widgets/variableexplorer/collectionseditor.py:1132
msgid "It was not possible to copy this array"
msgstr "配列をコピーできませんでした"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1121
+#: spyder/widgets/variableexplorer/collectionseditor.py:1144
+msgid "It was not possible to copy this dataframe"
+msgstr "このデータフレムはコピーできませんでした"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1166
msgid "Clipboard contents"
msgstr "クリップボードの内容"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1136
+#: spyder/widgets/variableexplorer/collectionseditor.py:1181
msgid "Import from clipboard"
msgstr "クリップボードからインポート"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1138
+#: spyder/widgets/variableexplorer/collectionseditor.py:1183
msgid "Empty clipboard"
msgstr "クリップボードを空にする"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1139
+#: spyder/widgets/variableexplorer/collectionseditor.py:1184
msgid "Nothing to be imported from clipboard."
msgstr "クリップボードからインポートするものはありません。"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:597
+#: spyder/widgets/variableexplorer/dataframeeditor.py:321
+msgid ""
+"It is not possible to display this value because\n"
+"an error ocurred while trying to do it"
+msgstr ""
+"実行中にエラーが発生したため\n"
+"値を表示することが出来ません"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To bool"
msgstr "真偽値へ"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:597
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To complex"
msgstr "複素数へ"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:598
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To float"
msgstr "浮動小数点数へ"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:598
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To int"
msgstr "整数へ"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:599
+#: spyder/widgets/variableexplorer/dataframeeditor.py:623
msgid "To str"
msgstr "文字列へ"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:683
+#: spyder/widgets/variableexplorer/dataframeeditor.py:707
msgid "%s editor"
msgstr "%s エディタ"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:717
+#: spyder/widgets/variableexplorer/dataframeeditor.py:742
msgid "Column min/max"
msgstr "列の 最小/最大"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:757
+#: spyder/widgets/variableexplorer/dataframeeditor.py:796
msgid "Format ({}) is incorrect"
msgstr "フォーマット ({}) が不正です"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:761
+#: spyder/widgets/variableexplorer/dataframeeditor.py:800
msgid "Format ({}) should start with '%'"
msgstr "フォーマット({}) は'%'で開始する必要があります"
@@ -5083,40 +5335,49 @@ msgstr ""
"次のステップを実行できません
入力をチェックしてください。"
"
エラーメッセージ:
%s"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:181
-#: spyder/widgets/variableexplorer/namespacebrowser.py:385
+#: spyder/widgets/variableexplorer/namespacebrowser.py:184
+#: spyder/widgets/variableexplorer/namespacebrowser.py:397
msgid "Import data"
msgstr "データをインポート"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:184
-#: spyder/widgets/variableexplorer/namespacebrowser.py:465
-#: spyder/widgets/variableexplorer/namespacebrowser.py:479
+#: spyder/widgets/variableexplorer/namespacebrowser.py:187
+#: spyder/widgets/variableexplorer/namespacebrowser.py:477
+#: spyder/widgets/variableexplorer/namespacebrowser.py:491
+#: spyder/plugins/profiler/widgets/profilergui.py:121
msgid "Save data"
msgstr "データを保存"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:189
+#: spyder/widgets/variableexplorer/namespacebrowser.py:192
msgid "Save data as..."
msgstr "形式を指定してデータ保存"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:201
+#: spyder/widgets/variableexplorer/namespacebrowser.py:204
msgid "Exclude references which name starts with an underscore"
msgstr "アンダースコアで始まる参照を除外"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:209
+#: spyder/widgets/variableexplorer/namespacebrowser.py:212
msgid "Exclude references which name is uppercase"
msgstr "名前が大文字の参照を除外"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:216
+#: spyder/widgets/variableexplorer/namespacebrowser.py:219
msgid "Exclude references which name starts with an uppercase character"
msgstr "大文字で始まる参照を除外"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:224
+#: spyder/widgets/variableexplorer/namespacebrowser.py:227
msgid ""
"Exclude references to unsupported data types (i.e. which won't be handled/"
"saved correctly)"
msgstr "非サポートデータ型(例:正しくhandle/saveがができない型)への参照を除外 "
-#: spyder/widgets/variableexplorer/namespacebrowser.py:405
+#: spyder/widgets/variableexplorer/namespacebrowser.py:306
+msgid ""
+"The object you are trying to modify is too big to be sent back to the "
+"kernel. Therefore, your modifications won't take place."
+msgstr ""
+"変更中のオブジェクトはカーネルへ送るには大きすぎます。このため変更は適用され"
+"ませんでした。"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:417
msgid ""
"Unsupported file extension '%s'
Would you like to import it "
"anyway (by selecting a known file format)?"
@@ -5124,36 +5385,28 @@ msgstr ""
"サポートされていないファイル拡張 '%s'
(既知のファイルフォーマッ"
"トを選択して)とにかくインポートしますか ?"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:413
+#: spyder/widgets/variableexplorer/namespacebrowser.py:425
msgid "Open file as:"
msgstr "形式を指定して開く:"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:447
+#: spyder/widgets/variableexplorer/namespacebrowser.py:459
msgid "Unable to load '%s'
Error message:
%s"
msgstr " '%s' をロードできません
エラーメッセージ:
%s"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:480
+#: spyder/widgets/variableexplorer/namespacebrowser.py:492
msgid "Unable to save current workspace
Error message:
%s"
msgstr ""
"現在のワークスペースを保存できません
エラーメッセージ:
%s"
-#: spyder/widgets/variableexplorer/texteditor.py:74
+#: spyder/widgets/variableexplorer/texteditor.py:84
msgid "Text editor"
msgstr "テキストエディタ"
-#: spyder/widgets/variableexplorer/utils.py:31
-msgid "View and edit DataFrames and Series in the Variable Explorer"
-msgstr "変数エクスプローラーでのDataFrameとSeriesの表示・編集"
-
-#: spyder/widgets/variableexplorer/utils.py:36
-msgid "View and edit two and three dimensional arrays in the Variable Explorer"
-msgstr "変数エクスプローラーでの2, 3次元配列の表示・編集"
-
-#: spyder/workers/updates.py:90 spyder/workers/updates.py:92
+#: spyder/workers/updates.py:128 spyder/workers/updates.py:130
msgid "Unable to retrieve information."
msgstr "情報が取得できません"
-#: spyder/workers/updates.py:94
+#: spyder/workers/updates.py:132
msgid ""
"Unable to connect to the internet.
Make sure the connection is "
"working properly."
@@ -5161,10 +5414,147 @@ msgstr ""
"インターネットに接続できません。
接続が正しく動作しているか確認してく"
"ださい。"
-#: spyder/workers/updates.py:97
+#: spyder/workers/updates.py:135
msgid "Unable to check for updates."
msgstr "更新をチェックできません"
+#~ msgid "ViTables"
+#~ msgstr "Viテーブル"
+
+#~ msgid ""
+#~ "Update LANGUAGE_CODES (inside config/base.py) if a new translation has "
+#~ "been added to Spyder"
+#~ msgstr ""
+#~ "新しい翻訳がSpyderに追加された場合LANGUAGE_CODES (config/base.py内)を更新"
+
+#~ msgid ""
+#~ "Please enter the connection info of the kernel you want to connect to. "
+#~ "For that you can either select its JSON connection file using the "
+#~ "Browse button, or write directly its id, in case it's a local "
+#~ "kernel (for example kernel-3764.json or just 3764)."
+#~ msgstr ""
+#~ "接続したいカーネルの接続情報を入力してください。 表示 ボタンを押"
+#~ "し、JSON接続ファイルを選ぶか、ローカルカーネルの場合IDを入力してください "
+#~ "(例: kernel-3764.json あるいは 3764)。"
+
+#~ msgid "Connection info:"
+#~ msgstr "接続情報:"
+
+#~ msgid "Ssh key"
+#~ msgstr "sshキー"
+
+#~ msgid "Password"
+#~ msgstr "パスワード"
+
+#~ msgid "Select ssh key"
+#~ msgstr "sshキーを選択"
+
+#~ msgid "PyQt4 Reference Guide"
+#~ msgstr "PyQt4リファレンスガイド"
+
+#~ msgid "PyQt4 API Reference"
+#~ msgstr "PyQt4 APIリファレンス"
+
+#~ msgid "Qt examples"
+#~ msgstr "Qt examples"
+
+#~ msgid "Use the greedy completer"
+#~ msgstr "greedy completerを利用する"
+
+#~ msgid ""
+#~ "This error was most probably caused by installing Spyder in a directory "
+#~ "with non-ascii characters (i.e. characters with tildes, apostrophes or "
+#~ "non-latin symbols).
To fix it, please reinstall Spyder in a "
+#~ "different location."
+#~ msgstr ""
+#~ "このエラーはおそらくSpyderを非ASCII文字を名前に含むディレクトリにインス"
+#~ "トールしていることによって発生しています。br>
解決するにはSpyderを他の"
+#~ "場所に再インストール して下さい。"
+
+#~ msgid "Supported files"
+#~ msgstr "サポートされているファイル"
+
+#~ msgid "All files (*.*)"
+#~ msgstr "すべてのファイル (*.*)"
+
+#~ msgid "Spyder data files"
+#~ msgstr "Spyderデータファイル"
+
+#~ msgid "NumPy zip arrays"
+#~ msgstr "NumPy zip配列"
+
+#~ msgid "Matlab files"
+#~ msgstr "Matlabファイル"
+
+#~ msgid "CSV text files"
+#~ msgstr "CSVテキストファイル"
+
+#~ msgid "JPEG images"
+#~ msgstr "JPEG画像"
+
+#~ msgid "PNG images"
+#~ msgstr "PNG画像"
+
+#~ msgid "GIF images"
+#~ msgstr "GIF画像"
+
+#~ msgid "TIFF images"
+#~ msgstr "TIFF画像"
+
+#~ msgid "Pickle files"
+#~ msgstr "Pickleファイル"
+
+#~ msgid "JSON files"
+#~ msgstr "JSONファイル"
+
+#~ msgid "Unsupported file type '%s'"
+#~ msgstr "非サポートファイルタイプ '%s'"
+
+#~ msgid "Save"
+#~ msgstr "保存"
+
+#~ msgid "Spyder internal error"
+#~ msgstr "Spyder内部エラー"
+
+#~ msgid ""
+#~ "Spyder has encountered an internal problem
\n"
+#~ " Before reporting it, please consult our "
+#~ "comprehensive \n"
+#~ " Troubleshooting Guide \n"
+#~ " which should help solve most issues, and search for \n"
+#~ " known bugs matching your "
+#~ "error \n"
+#~ " message or problem description for a quicker solution.\n"
+#~ "
\n"
+#~ " If you don't find anything, please enter a detailed step-by-"
+#~ "step \n"
+#~ " description (in English) of what led up to the problem "
+#~ "below. \n"
+#~ " Issue reports without a clear way to reproduce them will "
+#~ "be \n"
+#~ " closed.
\n"
+#~ " Thanks for helping us making Spyder better for everyone!\n"
+#~ " "
+#~ msgstr ""
+#~ "Spyderで内部エラーが生じています
\n"
+#~ " これをレポートする前に なるべく \n"
+#~ " トラブルシュートガイドを参照"
+#~ "し \n"
+#~ " 既知のバグに該当していないか \n"
+#~ " あるいは解決方法の記載がないか確認して下さい。\n"
+#~ "
\n"
+#~ " 見つからない場合には、どのような原因で生じたかを以下の一問一"
+#~ "答式の\n"
+#~ " 記述(英語)に詳細に入力して下さい。\n"
+#~ " 再現するための情報が不足しているレポートは回答前にcloseされ"
+#~ "る\n"
+#~ " 場合があります。
\n"
+#~ " Spyderの品質向上にご協力頂きありがとうございます!\n"
+#~ " "
+
+#~ msgid "Submission enabled; thanks!"
+#~ msgstr "レポートの送信が完了しました。ありがとう!"
+
#~ msgid "Pop up internal console when internal errors appear"
#~ msgstr "内部エラー発生時に内部コンソールをポップアップさせる"
@@ -5444,9 +5834,6 @@ msgstr "更新をチェックできません"
#~ msgid "the global working directory"
#~ msgstr "グローバル作業ディレクトリ"
-#~ msgid "Files are created in:"
-#~ msgstr "新規ファイルは以下のディレクトリに作成されます:"
-
#~ msgid "Change to file base directory"
#~ msgstr "ファイルディレクトリを変更するタイミング"
@@ -5592,6 +5979,275 @@ msgstr "更新をチェックできません"
#~ msgid "Refresh periodically"
#~ msgstr "定期的にリフレッシュ"
+#: spyder/plugins/breakpoints/plugin.py:45
+msgid "Breakpoints"
+msgstr "ブレークポイント"
+
+#: spyder/plugins/breakpoints/plugin.py:80
+msgid "List breakpoints"
+msgstr "ブレークポイントをリストアップ"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "Condition"
+msgstr "条件"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "File"
+msgstr "ファイル"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "Line"
+msgstr "行"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:201
+msgid "Clear this breakpoint"
+msgstr "ブレークポイントをクリア"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:206
+msgid "Edit this breakpoint"
+msgstr "ブレークポイントを編集"
+
+#: spyder/plugins/pylint/plugin.py:36
+msgid "Save file before analyzing it"
+msgstr "分析前にファイルを保存"
+
+#: spyder/plugins/pylint/plugin.py:40
+msgid "The following option will be applied at next startup."
+msgstr "以下のオプションは次回起動時に適用されます。"
+
+#: spyder/plugins/pylint/plugin.py:43
+msgid "History: "
+msgstr "ヒストリ:"
+
+#: spyder/plugins/pylint/plugin.py:44
+msgid " results"
+msgstr "結果"
+
+#: spyder/plugins/pylint/plugin.py:47 spyder/plugins/profiler/plugin.py:33
+msgid "Results"
+msgstr "結果"
+
+#: spyder/plugins/pylint/plugin.py:48
+msgid "Results are stored here:"
+msgstr "結果は以下に保存されます:"
+
+#: spyder/plugins/pylint/plugin.py:98
+#: spyder/plugins/pylint/widgets/pylintgui.py:83
+msgid "Static code analysis"
+msgstr "静的コード分析"
+
+#: spyder/plugins/pylint/plugin.py:133
+msgid "Run static code analysis"
+msgstr "静的コード分析を実行"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:117
+msgid "Results for "
+msgstr "結果"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:122
+msgid "Convention"
+msgstr "規約"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:124
+msgid "Refactor"
+msgstr "リファクター"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:206
+msgid "Analyze"
+msgstr "分析"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:207
+msgid "Run analysis"
+msgstr "分析を実行"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:212
+msgid "Stop current analysis"
+msgstr "現在の分析を停止"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:218
+#: spyder/plugins/pylint/widgets/pylintgui.py:288
+msgid "Select Python file"
+msgstr "Pythonファイルを選択"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:224
+#: spyder/plugins/profiler/widgets/profilergui.py:102
+msgid "Output"
+msgstr "出力"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:226
+msgid "Complete output"
+msgstr "出力を完了"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:260
+msgid "Pylint script was not found. Please add \"%s\" to PATH."
+msgstr ""
+"Pylintスクリプトが見つかりいませんでした。\"%s\" をPATHに追加してください。"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:263
+msgid "Please install pylint:"
+msgstr "pylintを再インストールしてください:"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:326
+msgid "Pylint output"
+msgstr "Pylint出力"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:465
+msgid "Source code has not been rated yet."
+msgstr "ソースコードはまだ評価されていません。"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:471
+msgid "Analysis did not succeed (see output for more details)."
+msgstr "分析に失敗しました(詳細は出力を見てください)"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:484
+msgid "Global evaluation:"
+msgstr "全体評価:"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:488
+msgid "previous run:"
+msgstr "前回の実行:"
+
+#: spyder/plugins/profiler/plugin.py:34
+msgid ""
+"Profiler plugin results (the output of python's profile/cProfile)\n"
+"are stored here:"
+msgstr ""
+"プロファイラプラグインの結果(Python profile/cProfile出力)\n"
+"はこちらに保存されます:"
+
+#: spyder/plugins/profiler/plugin.py:75
+msgid "Profiler"
+msgstr "プロファイラ"
+
+#: spyder/plugins/profiler/plugin.py:104
+#: spyder/plugins/profiler/widgets/profilergui.py:81
+msgid "Profile"
+msgstr "プロファイル"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:82
+msgid "Run profiler"
+msgstr "プロファイラの実行"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:88
+msgid "Stop current profiling"
+msgstr "現在のプロファイリングを停止"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:96
+#: spyder/plugins/profiler/widgets/profilergui.py:219
+msgid "Select Python script"
+msgstr "Pythonスクリプトを選択"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:104
+msgid "Show program's output"
+msgstr "プログラムの出力を表示"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:113
+msgid "Collapse one level up"
+msgstr "1つ上のレベルに折りたたむ"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:118
+msgid "Expand one level down"
+msgstr "1つ下のレベルに展開"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:124
+msgid "Save profiling data"
+msgstr "プロファイリングデータを保存"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:126
+msgid "Load data"
+msgstr "データをロード"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:129
+msgid "Load profiling data for comparison"
+msgstr "比較のためのプロファイリングデータをロード"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:131
+msgid "Clear comparison"
+msgstr "比較をクリア"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:171
+msgid "Please install"
+msgstr "インストールしてください"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:172
+msgid "the Python profiler modules"
+msgstr "Pythonプロファイラモジュール"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:179
+msgid "Save profiler result"
+msgstr "プロファイラの結果を保存"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:182
+#: spyder/plugins/profiler/widgets/profilergui.py:188
+msgid "Profiler result"
+msgstr "プロファイラ結果"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:187
+msgid "Select script to compare"
+msgstr "比較するスクリプトを選択"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:227
+#: spyder/plugins/profiler/widgets/profilergui.py:232
+msgid "Profiler output"
+msgstr "プロファイラ出力"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:251
+msgid "Profiling, please wait..."
+msgstr "プロファイリング中、暫くお待ち下さい..."
+
+#: spyder/plugins/profiler/widgets/profilergui.py:343
+msgid "Sorting data, please wait..."
+msgstr "データをソートしています、お待ち下さい..."
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Function/Module"
+msgstr "関数/モジュール"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Total Time"
+msgstr "合計時間"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Diff"
+msgstr "Diff"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Calls"
+msgstr "コール"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Local Time"
+msgstr "ローカル時間"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:391
+msgid "File:line"
+msgstr "ファイル:行"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:565
+msgid "Function or module name"
+msgstr "関数あるいはモジュール名"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:569
+msgid "Time in function (including sub-functions)"
+msgstr "関数内での時間(サブ関数を含む)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:578
+msgid "Local time in function (not in sub-functions)"
+msgstr "関数内でのローカル時間(サブ関数を含まない)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:588
+msgid "Total number of calls (including recursion)"
+msgstr "合計コール回数(再帰呼出しを含む)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:598
+msgid "File:line where function is defined"
+msgstr "関数の定義されている ファイル:行"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:603
+msgid "recursion"
+msgstr "再帰"
+
#~ msgid "Python(x,y)"
#~ msgstr "Python(x,y)"
@@ -5921,9 +6577,6 @@ msgstr "更新をチェックできません"
#~ msgid "Save session and quit..."
#~ msgstr "セッションを保存して終了"
-#~ msgid "Breakpoints"
-#~ msgstr "ブレークポイント"
-
#~ msgid "Exit"
#~ msgstr "Exit"
diff --git a/spyder/locale/pt_BR/LC_MESSAGES/spyder.mo b/spyder/locale/pt_BR/LC_MESSAGES/spyder.mo
index 0e709187946..bba776c59f0 100644
Binary files a/spyder/locale/pt_BR/LC_MESSAGES/spyder.mo and b/spyder/locale/pt_BR/LC_MESSAGES/spyder.mo differ
diff --git a/spyder/locale/pt_BR/LC_MESSAGES/spyder.po b/spyder/locale/pt_BR/LC_MESSAGES/spyder.po
index 0d6e9816932..d4f8d283489 100644
--- a/spyder/locale/pt_BR/LC_MESSAGES/spyder.po
+++ b/spyder/locale/pt_BR/LC_MESSAGES/spyder.po
@@ -5,8 +5,8 @@
msgid ""
msgstr ""
"Project-Id-Version: 3.8POT-Creation-Date: 2017-01-17 12:57-0300\n"
-"POT-Creation-Date: 2018-02-19 11:56+-05\n"
-"PO-Revision-Date: 2018-02-21 05:05-0300\n"
+"POT-Creation-Date: 2018-11-13 11:49+-05\n"
+"PO-Revision-Date: 2018-07-02 14:10-0300\n"
"Last-Translator: Valter Nazianzeno \n"
"Language-Team: pt_BR\n"
"Language: pt_BR\n"
@@ -14,50 +14,42 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
-"X-Generator: Poedit 2.0.6\n"
+"X-Generator: Poedit 2.0.8\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
-#: spyder/app/mainwindow.py:134
+#: spyder/app/mainwindow.py:139
msgid "Initializing..."
msgstr "Iniciando..."
-#: spyder/app/mainwindow.py:238
+#: spyder/app/mainwindow.py:252
msgid "Python2 documentation"
msgstr "Documentação do Python2"
-#: spyder/app/mainwindow.py:240
+#: spyder/app/mainwindow.py:254
msgid "Python3 documentation"
msgstr "Documentação do Python3"
-#: spyder/app/mainwindow.py:242
+#: spyder/app/mainwindow.py:256
msgid "Numpy and Scipy documentation"
msgstr "Documentação do Numpy e Scipy"
-#: spyder/app/mainwindow.py:244
+#: spyder/app/mainwindow.py:258
msgid "Matplotlib documentation"
msgstr "Documentação do Matplotlib"
-#: spyder/app/mainwindow.py:247
-msgid "PyQt4 Reference Guide"
-msgstr "Guia de referência do PyQt4"
-
-#: spyder/app/mainwindow.py:250
-msgid "PyQt4 API Reference"
-msgstr "Referência da API do PyQt4"
-
-#: spyder/app/mainwindow.py:253
+#: spyder/app/mainwindow.py:261
msgid "PyQt5 Reference Guide"
msgstr "Guia de referência do PyQt5"
-#: spyder/app/mainwindow.py:256
+#: spyder/app/mainwindow.py:264
msgid "PyQt5 API Reference"
msgstr "Referência da API do PyQt5"
-#: spyder/app/mainwindow.py:258
+#: spyder/app/mainwindow.py:266
msgid "WinPython"
msgstr "WinPython"
-#: spyder/app/mainwindow.py:518
+#: spyder/app/mainwindow.py:525
msgid ""
"An error occurred while creating a socket needed by Spyder. Please, try to "
"run as an Administrator from cmd.exe the following command and then restart "
@@ -69,172 +61,172 @@ msgstr ""
"então reiniciar seu computador:
netsh winsock reset
"
-#: spyder/app/mainwindow.py:550
+#: spyder/app/mainwindow.py:557
msgid "Close current pane"
msgstr "Fechar painel atual"
-#: spyder/app/mainwindow.py:555
+#: spyder/app/mainwindow.py:562
msgid "Lock panes"
msgstr "Travar painéis"
-#: spyder/app/mainwindow.py:562
+#: spyder/app/mainwindow.py:569
msgid "Use next layout"
msgstr "Usar próximo layout"
-#: spyder/app/mainwindow.py:566
+#: spyder/app/mainwindow.py:573
msgid "Use previous layout"
msgstr "Usar layout anterior"
-#: spyder/app/mainwindow.py:576 spyder/widgets/editor.py:497
+#: spyder/app/mainwindow.py:583 spyder/widgets/editor.py:507
msgid "File switcher..."
msgstr "Seletor de arquivo..."
-#: spyder/app/mainwindow.py:578
+#: spyder/app/mainwindow.py:585
msgid "Fast switch between files"
msgstr "Troca rápida de seleção entre arquivos"
-#: spyder/app/mainwindow.py:584
+#: spyder/app/mainwindow.py:591
msgid "Symbol finder..."
msgstr "Pesquisador de símbolos...."
-#: spyder/app/mainwindow.py:586
+#: spyder/app/mainwindow.py:593
msgid "Fast symbol search in file"
msgstr "Pesquisa rápida de símbolos no arquivo"
-#: spyder/app/mainwindow.py:605 spyder/widgets/sourcecode/codeeditor.py:2673
+#: spyder/app/mainwindow.py:612 spyder/widgets/sourcecode/codeeditor.py:2680
msgid "Undo"
msgstr "Desfazer"
-#: spyder/app/mainwindow.py:607 spyder/widgets/sourcecode/codeeditor.py:2676
+#: spyder/app/mainwindow.py:614 spyder/widgets/sourcecode/codeeditor.py:2683
msgid "Redo"
msgstr "Refazer"
-#: spyder/app/mainwindow.py:609 spyder/widgets/shell.py:123
-#: spyder/widgets/sourcecode/codeeditor.py:2682
-#: spyder/widgets/variableexplorer/arrayeditor.py:467
-#: spyder/widgets/variableexplorer/collectionseditor.py:674
-#: spyder/widgets/variableexplorer/dataframeeditor.py:592
+#: spyder/app/mainwindow.py:616 spyder/widgets/shell.py:123
+#: spyder/widgets/sourcecode/codeeditor.py:2689
+#: spyder/widgets/variableexplorer/arrayeditor.py:465
+#: spyder/widgets/variableexplorer/collectionseditor.py:710
+#: spyder/widgets/variableexplorer/dataframeeditor.py:616
msgid "Copy"
msgstr "Copiar"
-#: spyder/app/mainwindow.py:611 spyder/widgets/shell.py:119
-#: spyder/widgets/sourcecode/codeeditor.py:2679
+#: spyder/app/mainwindow.py:618 spyder/widgets/shell.py:119
+#: spyder/widgets/sourcecode/codeeditor.py:2686
msgid "Cut"
msgstr "Recortar"
-#: spyder/app/mainwindow.py:613 spyder/widgets/shell.py:127
-#: spyder/widgets/sourcecode/codeeditor.py:2685
-#: spyder/widgets/variableexplorer/collectionseditor.py:671
+#: spyder/app/mainwindow.py:620 spyder/widgets/shell.py:127
+#: spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/widgets/variableexplorer/collectionseditor.py:707
msgid "Paste"
msgstr "Colar"
-#: spyder/app/mainwindow.py:616 spyder/widgets/shell.py:140
-#: spyder/widgets/sourcecode/codeeditor.py:2688
+#: spyder/app/mainwindow.py:623 spyder/widgets/shell.py:140
+#: spyder/widgets/sourcecode/codeeditor.py:2695
msgid "Select All"
msgstr "Selecionar tudo"
-#: spyder/app/mainwindow.py:626 spyder/plugins/editor.py:1422
+#: spyder/app/mainwindow.py:633 spyder/plugins/editor.py:1421
msgid "&File"
msgstr "&Arquivo"
-#: spyder/app/mainwindow.py:627 spyder/plugins/editor.py:1410
+#: spyder/app/mainwindow.py:634 spyder/plugins/editor.py:1409
msgid "File toolbar"
msgstr "Barra de arquivo"
-#: spyder/app/mainwindow.py:631 spyder/plugins/editor.py:1423
+#: spyder/app/mainwindow.py:638 spyder/plugins/editor.py:1422
msgid "&Edit"
msgstr "&Editar"
-#: spyder/app/mainwindow.py:632 spyder/plugins/editor.py:1420
+#: spyder/app/mainwindow.py:639 spyder/plugins/editor.py:1419
msgid "Edit toolbar"
msgstr "Barra de edição"
-#: spyder/app/mainwindow.py:636 spyder/plugins/editor.py:1424
+#: spyder/app/mainwindow.py:643 spyder/plugins/editor.py:1423
msgid "&Search"
msgstr "&Pesquisar"
-#: spyder/app/mainwindow.py:637 spyder/plugins/editor.py:1412
+#: spyder/app/mainwindow.py:644 spyder/plugins/editor.py:1411
msgid "Search toolbar"
msgstr "Barra de pesquisa"
-#: spyder/app/mainwindow.py:641 spyder/plugins/editor.py:1425
+#: spyder/app/mainwindow.py:648 spyder/plugins/editor.py:1424
msgid "Sour&ce"
msgstr "Códi&go"
-#: spyder/app/mainwindow.py:642 spyder/plugins/editor.py:1414
+#: spyder/app/mainwindow.py:649 spyder/plugins/editor.py:1413
msgid "Source toolbar"
msgstr "Barra de código"
-#: spyder/app/mainwindow.py:646 spyder/plugins/editor.py:803
-#: spyder/plugins/editor.py:1426
+#: spyder/app/mainwindow.py:653 spyder/plugins/editor.py:803
+#: spyder/plugins/editor.py:1425
msgid "&Run"
msgstr "&Executar"
-#: spyder/app/mainwindow.py:647 spyder/plugins/editor.py:1416
+#: spyder/app/mainwindow.py:654 spyder/plugins/editor.py:1415
msgid "Run toolbar"
-msgstr "Barra de execução "
+msgstr "Barra de execução"
-#: spyder/app/mainwindow.py:651 spyder/plugins/editor.py:762
+#: spyder/app/mainwindow.py:658 spyder/plugins/editor.py:762
msgid "&Debug"
msgstr "&Depurar"
-#: spyder/app/mainwindow.py:652 spyder/plugins/editor.py:1418
+#: spyder/app/mainwindow.py:659 spyder/plugins/editor.py:1417
msgid "Debug toolbar"
msgstr "Barra de depuração"
-#: spyder/app/mainwindow.py:656
+#: spyder/app/mainwindow.py:663
msgid "C&onsoles"
msgstr "C&onsoles"
-#: spyder/app/mainwindow.py:659
+#: spyder/app/mainwindow.py:666
msgid "&Projects"
msgstr "&Projetos"
-#: spyder/app/mainwindow.py:662 spyder/plugins/editor.py:1427
+#: spyder/app/mainwindow.py:669 spyder/plugins/editor.py:1426
msgid "&Tools"
msgstr "&Ferramentas"
-#: spyder/app/mainwindow.py:665 spyder/plugins/editor.py:1428
+#: spyder/app/mainwindow.py:672 spyder/plugins/editor.py:1427
msgid "&View"
msgstr "&Ver"
-#: spyder/app/mainwindow.py:668 spyder/plugins/editor.py:1429
+#: spyder/app/mainwindow.py:675 spyder/plugins/editor.py:1428
msgid "&Help"
msgstr "A&juda"
-#: spyder/app/mainwindow.py:673
+#: spyder/app/mainwindow.py:680
msgid "Welcome to Spyder!"
msgstr "Bem-vindo ao Spyder!"
-#: spyder/app/mainwindow.py:678
+#: spyder/app/mainwindow.py:685
msgid "Pre&ferences"
msgstr "Pre&ferências"
-#: spyder/app/mainwindow.py:685 spyder/widgets/pathmanager.py:53
+#: spyder/app/mainwindow.py:692 spyder/widgets/pathmanager.py:54
msgid "PYTHONPATH manager"
msgstr "Gerenciar PYTHONPATH"
-#: spyder/app/mainwindow.py:688
+#: spyder/app/mainwindow.py:695
msgid "Python Path Manager"
msgstr "Gerenciador de caminhos do Python"
-#: spyder/app/mainwindow.py:691
+#: spyder/app/mainwindow.py:698
msgid "Update module names list"
msgstr "Atualizar a lista de nomes dos módulos"
-#: spyder/app/mainwindow.py:694
+#: spyder/app/mainwindow.py:701
msgid "Refresh list of module names available in PYTHONPATH"
msgstr "Atualizar a lista de nomes dos módulos disponíveis no PYTHONPATH"
-#: spyder/app/mainwindow.py:697
+#: spyder/app/mainwindow.py:704
msgid "Reset Spyder to factory defaults"
msgstr "Resetar configuração padrão do Spyder"
-#: spyder/app/mainwindow.py:702
+#: spyder/app/mainwindow.py:709
msgid "Current user environment variables..."
msgstr "Variáveis de ambiente do usuário atual..."
-#: spyder/app/mainwindow.py:704
+#: spyder/app/mainwindow.py:711
msgid ""
"Show and edit current user environment variables in Windows registry (i.e. "
"for all sessions)"
@@ -244,51 +236,43 @@ msgstr ""
"registro do Windows (para todas\n"
"as sessões)"
-#: spyder/app/mainwindow.py:713 spyder/app/mainwindow.py:1137
+#: spyder/app/mainwindow.py:720 spyder/app/mainwindow.py:1115
msgid "External Tools"
msgstr "Ferramentas externas"
-#: spyder/app/mainwindow.py:716
+#: spyder/app/mainwindow.py:723
msgid "WinPython control panel"
msgstr "Painel de controle WinPython"
-#: spyder/app/mainwindow.py:725
+#: spyder/app/mainwindow.py:733
msgid "Qt Designer"
msgstr "Qt Designer"
-#: spyder/app/mainwindow.py:730
+#: spyder/app/mainwindow.py:737
msgid "Qt Linguist"
msgstr "Qt Linguist"
-#: spyder/app/mainwindow.py:736
-msgid "Qt examples"
-msgstr "Exemplos do Qt"
-
-#: spyder/app/mainwindow.py:756
+#: spyder/app/mainwindow.py:758
msgid "guidata examples"
-msgstr "Exemplos do guidata"
+msgstr "exemplos do guidata"
-#: spyder/app/mainwindow.py:767
+#: spyder/app/mainwindow.py:769
msgid "guiqwt examples"
-msgstr "Exemplos do guiqwt"
+msgstr "exemplos do guiqwt"
-#: spyder/app/mainwindow.py:772
+#: spyder/app/mainwindow.py:774
msgid "Sift"
msgstr "Sift"
-#: spyder/app/mainwindow.py:782
-msgid "ViTables"
-msgstr "ViTables"
-
-#: spyder/app/mainwindow.py:796
+#: spyder/app/mainwindow.py:792
msgid "Fullscreen mode"
msgstr "Modo tela cheia"
-#: spyder/app/mainwindow.py:808
+#: spyder/app/mainwindow.py:804
msgid "Main toolbar"
msgstr "Barra principal"
-#: spyder/app/mainwindow.py:817
+#: spyder/app/mainwindow.py:813
msgid ""
"Spyder Internal Console\n"
"\n"
@@ -310,167 +294,172 @@ msgstr ""
"\n"
"Por favor não execute seu código neste console\n"
-#: spyder/app/mainwindow.py:834
+#: spyder/app/mainwindow.py:830
msgid "Loading help..."
msgstr "Carregando ajuda..."
-#: spyder/app/mainwindow.py:841
+#: spyder/app/mainwindow.py:837
msgid "Loading outline explorer..."
msgstr "Carregando o explorador de código..."
-#: spyder/app/mainwindow.py:847
+#: spyder/app/mainwindow.py:843
msgid "Loading editor..."
msgstr "Carregando editor..."
-#: spyder/app/mainwindow.py:853 spyder/plugins/console.py:141
-#: spyder/widgets/ipythonconsole/client.py:414
+#: spyder/app/mainwindow.py:849 spyder/plugins/console.py:141
+#: spyder/widgets/ipythonconsole/client.py:453
msgid "&Quit"
msgstr "&Sair"
-#: spyder/app/mainwindow.py:855 spyder/plugins/console.py:143
+#: spyder/app/mainwindow.py:851 spyder/plugins/console.py:143
msgid "Quit"
msgstr "Sair"
-#: spyder/app/mainwindow.py:859
+#: spyder/app/mainwindow.py:855
msgid "&Restart"
msgstr "&Reiniciar"
-#: spyder/app/mainwindow.py:861
+#: spyder/app/mainwindow.py:857
msgid "Restart"
msgstr "Reiniciar"
-#: spyder/app/mainwindow.py:875
+#: spyder/app/mainwindow.py:871
msgid "Loading file explorer..."
msgstr "Carregando explorador de arquivos..."
-#: spyder/app/mainwindow.py:882
+#: spyder/app/mainwindow.py:878
msgid "Loading history plugin..."
msgstr "Carregando histórico..."
-#: spyder/app/mainwindow.py:893
+#: spyder/app/mainwindow.py:889
msgid "Loading online help..."
msgstr "Carregando ajuda online..."
-#: spyder/app/mainwindow.py:898
+#: spyder/app/mainwindow.py:894
msgid "Loading project explorer..."
msgstr "Carregando explorador de projetos..."
-#: spyder/app/mainwindow.py:911
+#: spyder/app/mainwindow.py:907
msgid "Loading namespace browser..."
msgstr "Carregando explorador de variáveis..."
-#: spyder/app/mainwindow.py:917
+#: spyder/app/mainwindow.py:913
msgid "Loading IPython console..."
msgstr "Carregando console IPython..."
-#: spyder/app/mainwindow.py:922
+#: spyder/app/mainwindow.py:918
msgid "Setting up main window..."
msgstr "Configurando tela principal..."
-#: spyder/app/mainwindow.py:926
+#: spyder/app/mainwindow.py:922
msgid "Troubleshooting..."
msgstr "Solução de problemas..."
-#: spyder/app/mainwindow.py:928
+#: spyder/app/mainwindow.py:924
msgid "Dependencies..."
msgstr "Dependências..."
-#: spyder/app/mainwindow.py:932
+#: spyder/app/mainwindow.py:928
msgid "Report issue..."
msgstr "Reportar problema..."
-#: spyder/app/mainwindow.py:936
+#: spyder/app/mainwindow.py:932
msgid "Spyder support..."
msgstr "Suporte do Spyder..."
-#: spyder/app/mainwindow.py:939
+#: spyder/app/mainwindow.py:935
msgid "Check for updates..."
msgstr "Verificar por atualizações..."
-#: spyder/app/mainwindow.py:962
+#: spyder/app/mainwindow.py:940
msgid "Spyder documentation"
msgstr "Documentação do Spyder"
-#: spyder/app/mainwindow.py:970
+#: spyder/app/mainwindow.py:948
msgid "Spyder tutorial"
msgstr "Tutorial do Spyder"
-#: spyder/app/mainwindow.py:975
+#: spyder/app/mainwindow.py:953
msgid "Shortcuts Summary"
msgstr "Resumo de Atalhos"
-#: spyder/app/mainwindow.py:981
+#: spyder/app/mainwindow.py:959
msgid "Interactive tours"
msgstr "Tours interativas"
-#: spyder/app/mainwindow.py:1008
+#: spyder/app/mainwindow.py:986
msgid "Python documentation"
msgstr "Documentação do Python"
-#: spyder/app/mainwindow.py:1014
+#: spyder/app/mainwindow.py:992
msgid "IPython documentation"
msgstr "Documentação do IPython"
-#: spyder/app/mainwindow.py:1015
+#: spyder/app/mainwindow.py:993
msgid "Intro to IPython"
msgstr "Introdução ao IPython"
-#: spyder/app/mainwindow.py:1017
+#: spyder/app/mainwindow.py:995
msgid "Quick reference"
msgstr "Referência rápida"
-#: spyder/app/mainwindow.py:1019
+#: spyder/app/mainwindow.py:997
msgid "Console help"
msgstr "Ajuda do console"
-#: spyder/app/mainwindow.py:1049
+#: spyder/app/mainwindow.py:1027
msgid "Installed Python modules"
msgstr "Módulos instalados do Python"
-#: spyder/app/mainwindow.py:1053
+#: spyder/app/mainwindow.py:1031
msgid "Online documentation"
msgstr "Documentação online"
-#: spyder/app/mainwindow.py:1066
+#: spyder/app/mainwindow.py:1044
msgid "Qt documentation"
msgstr "Documentação do Qt"
-#: spyder/app/mainwindow.py:1072
+#: spyder/app/mainwindow.py:1050
msgid "About %s..."
msgstr "Sobre o %s..."
-#: spyder/app/mainwindow.py:1103
+#: spyder/app/mainwindow.py:1081
msgid "Panes"
msgstr "Painéis"
-#: spyder/app/mainwindow.py:1105
+#: spyder/app/mainwindow.py:1083
msgid "Toolbars"
msgstr "Barra de ferramentas"
-#: spyder/app/mainwindow.py:1106
+#: spyder/app/mainwindow.py:1084
msgid "Window layouts"
msgstr "Layouts da janela"
-#: spyder/app/mainwindow.py:1115 spyder/app/mainwindow.py:1943
-#: spyder/app/mainwindow.py:1944
+#: spyder/app/mainwindow.py:1093 spyder/app/mainwindow.py:1920
+#: spyder/app/mainwindow.py:1921
msgid "Show toolbars"
msgstr "Mostrar barra de ferramentas"
-#: spyder/app/mainwindow.py:1130
+#: spyder/app/mainwindow.py:1108
msgid "Attached console window (debugging)"
msgstr "Janela do console anexada (depuração)"
-#: spyder/app/mainwindow.py:1322 spyder/plugins/projects.py:254
-#: spyder/widgets/explorer.py:721 spyder/widgets/explorer.py:826
-#: spyder/widgets/variableexplorer/arrayeditor.py:587
-#: spyder/widgets/variableexplorer/collectionseditor.py:427
-#: spyder/widgets/variableexplorer/dataframeeditor.py:758
-#: spyder/widgets/variableexplorer/dataframeeditor.py:762
-#: spyder/widgets/variableexplorer/namespacebrowser.py:299
+#: spyder/app/mainwindow.py:1298 spyder/app/mainwindow.py:1988
+#: spyder/plugins/configdialog.py:1154 spyder/plugins/projects.py:269
+#: spyder/widgets/explorer.py:723 spyder/widgets/explorer.py:828
+#: spyder/widgets/reporterror.py:285
+#: spyder/widgets/variableexplorer/arrayeditor.py:586
+#: spyder/widgets/variableexplorer/collectionseditor.py:460
+#: spyder/widgets/variableexplorer/dataframeeditor.py:797
+#: spyder/plugins/pylint/widgets/pylintgui.py:128
+#: spyder/widgets/variableexplorer/namespacebrowser.py:311
+#: spyder/plugins/pylint/widgets/pylintgui.py:363
+#: spyder/plugins/pylint/widgets/pylintgui.py:391
+#: spyder/plugins/profiler/widgets/profilergui.py:295
msgid "Error"
msgstr "Erro"
-#: spyder/app/mainwindow.py:1323
+#: spyder/app/mainwindow.py:1299
msgid ""
"You have missing dependencies!
%s
Please "
"install them to avoid this message.
Note: Spyder could "
@@ -489,38 +478,41 @@ msgstr ""
"problema certifique-se de que quaisquer bugs encontrados não são o resultado "
"das dependências que estão faltando."
-#: spyder/app/mainwindow.py:1779
+#: spyder/app/mainwindow.py:1756
msgid "Spyder Default Layout"
msgstr "Layout padrão do Spyder"
-#: spyder/app/mainwindow.py:1797
+#: spyder/app/mainwindow.py:1774
msgid "Save current layout"
msgstr "Salvar layout atual"
-#: spyder/app/mainwindow.py:1801
+#: spyder/app/mainwindow.py:1778
msgid "Layout preferences"
msgstr "Preferências do Layout"
-#: spyder/app/mainwindow.py:1805
+#: spyder/app/mainwindow.py:1782
msgid "Reset to spyder default"
msgstr "Resetar para o layout padrão do Spyder"
-#: spyder/app/mainwindow.py:1825 spyder/app/mainwindow.py:1847
-#: spyder/app/mainwindow.py:1913 spyder/app/mainwindow.py:1921
-#: spyder/app/mainwindow.py:2799 spyder/plugins/configdialog.py:1345
-#: spyder/plugins/ipythonconsole.py:131 spyder/plugins/ipythonconsole.py:927
-#: spyder/plugins/ipythonconsole.py:1386 spyder/plugins/maininterpreter.py:149
-#: spyder/plugins/maininterpreter.py:174 spyder/plugins/maininterpreter.py:203
-#: spyder/utils/environ.py:95 spyder/utils/environ.py:108
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:131
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:149
-#: spyder/widgets/variableexplorer/arrayeditor.py:510
-#: spyder/widgets/variableexplorer/collectionseditor.py:416
-#: spyder/widgets/variableexplorer/collectionseditor.py:1095
+#: spyder/app/mainwindow.py:1802 spyder/app/mainwindow.py:1824
+#: spyder/app/mainwindow.py:1890 spyder/app/mainwindow.py:1898
+#: spyder/app/mainwindow.py:2843 spyder/plugins/configdialog.py:1415
+#: spyder/plugins/ipythonconsole.py:134 spyder/plugins/ipythonconsole.py:987
+#: spyder/plugins/ipythonconsole.py:1439 spyder/plugins/maininterpreter.py:162
+#: spyder/plugins/maininterpreter.py:183 spyder/plugins/maininterpreter.py:212
+#: spyder/utils/environ.py:56 spyder/utils/environ.py:107
+#: spyder/utils/environ.py:120
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:140
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:158
+#: spyder/widgets/variableexplorer/arrayeditor.py:508
+#: spyder/widgets/variableexplorer/collectionseditor.py:449
+#: spyder/plugins/pylint/widgets/pylintgui.py:126
+#: spyder/widgets/variableexplorer/collectionseditor.py:1143
+#: spyder/widgets/variableexplorer/namespacebrowser.py:305
msgid "Warning"
msgstr "Aviso"
-#: spyder/app/mainwindow.py:1826
+#: spyder/app/mainwindow.py:1803
msgid ""
"Window layout will be reset to default settings: this affects window "
"position, size and dockwidgets.\n"
@@ -530,7 +522,7 @@ msgstr ""
"afeta a posição, tamanho e componentes da janela.\n"
"Deseja continuar?"
-#: spyder/app/mainwindow.py:1848
+#: spyder/app/mainwindow.py:1825
msgid ""
"Layout %s will be "
"overwritten. Do you want to "
@@ -540,7 +532,7 @@ msgstr ""
"sobrescrito. Você deseja "
"Continuar?"
-#: spyder/app/mainwindow.py:1914
+#: spyder/app/mainwindow.py:1891
msgid ""
"Error opening the custom layout. Please close Spyder and try again. If the "
"issue persists, then you must use 'Reset to Spyder default' from the layout "
@@ -550,41 +542,49 @@ msgstr ""
"novamente. Se o problema persistir então você deve usar \"Resetar para o "
"layout padrão do Spyder\" no menu."
-#: spyder/app/mainwindow.py:1922
+#: spyder/app/mainwindow.py:1899
msgid "Quick switch layout #%s has not yet been defined."
msgstr "Troca rápida do layout #%s ainda não foi definida."
-#: spyder/app/mainwindow.py:1940 spyder/app/mainwindow.py:1941
+#: spyder/app/mainwindow.py:1917 spyder/app/mainwindow.py:1918
msgid "Hide toolbars"
msgstr "Esconder barra de ferramentas"
-#: spyder/app/mainwindow.py:2256 spyder/app/mainwindow.py:2257
+#: spyder/app/mainwindow.py:1989
+msgid ""
+"{} is no longer a valid Spyder project! Since it is the current "
+"active project, it will be closed automatically."
+msgstr ""
+"{} não é mais um projeto válido do Spyder! Já que ele é o atual "
+"projeto ativo, será fechado automaticamente."
+
+#: spyder/app/mainwindow.py:2252 spyder/app/mainwindow.py:2253
msgid "Maximize current pane"
msgstr "Maximizar painel atual"
-#: spyder/app/mainwindow.py:2260
+#: spyder/app/mainwindow.py:2256
msgid "Restore current pane"
msgstr "Restaurar painel atual"
-#: spyder/app/mainwindow.py:2261
+#: spyder/app/mainwindow.py:2257
msgid "Restore pane to its original size"
msgstr "Restaurar painel ao seu tamanho original"
-#: spyder/app/mainwindow.py:2359
+#: spyder/app/mainwindow.py:2439
msgid "About %s"
msgstr "Sobre o %s"
-#: spyder/app/mainwindow.py:2538 spyder/plugins/editor.py:168
+#: spyder/app/mainwindow.py:2579 spyder/plugins/editor.py:168
#: spyder/plugins/runconfig.py:354 spyder/plugins/runconfig.py:476
-#: spyder/utils/programs.py:286 spyder/widgets/explorer.py:344
+#: spyder/utils/programs.py:307 spyder/widgets/explorer.py:347
msgid "Run"
msgstr "Executar"
-#: spyder/app/mainwindow.py:2539
+#: spyder/app/mainwindow.py:2580
msgid "Running an external system terminal is not supported on platform %s."
msgstr "Executar um terminal externo não é suportado na plataforma %s."
-#: spyder/app/mainwindow.py:2800
+#: spyder/app/mainwindow.py:2844
msgid ""
"Spyder will restart and reset to default settings:
Do you want to "
"continue?"
@@ -592,15 +592,15 @@ msgstr ""
"O Spyder será reiniciado e resetado para suas definições padrões: "
"
Deseja continuar?"
-#: spyder/app/mainwindow.py:2928 spyder/widgets/helperwidgets.py:254
+#: spyder/app/mainwindow.py:2973 spyder/widgets/helperwidgets.py:254
msgid "Spyder updates"
msgstr "Atualizações do Spyder"
-#: spyder/app/mainwindow.py:2929 spyder/plugins/configdialog.py:835
+#: spyder/app/mainwindow.py:2974 spyder/plugins/configdialog.py:888
msgid "Check for updates on startup"
msgstr "Verificar por atualizações na inicialização"
-#: spyder/app/mainwindow.py:2948
+#: spyder/app/mainwindow.py:2993
msgid ""
"
IMPORTANT NOTE: It seems that you are using Spyder with "
"Anaconda/Miniconda. Please don't use pip
to "
@@ -614,7 +614,7 @@ msgstr ""
"até que novos pacotes conda estejam disponíveis e use o conda
"
"para realizar a atualização.
"
-#: spyder/app/mainwindow.py:2958
+#: spyder/app/mainwindow.py:3003
msgid ""
"Spyder %s is available!
Please use your package manager to "
"update Spyder or go to our Releases page to download this "
@@ -626,7 +626,7 @@ msgstr ""
"baixar a nova versão.
Se você não sabe como atualizar o Spyder "
"visite a página de instruções Installation."
-#: spyder/app/mainwindow.py:2971
+#: spyder/app/mainwindow.py:3016
msgid "Spyder is up to date."
msgstr "O Spyder está atualizado."
@@ -759,8 +759,8 @@ msgstr ""
"em qualquer uma delas uma nova janela será aberta, aonde você poderá "
"inspecionar e modificar seus valores."
-#: spyder/app/tour.py:179 spyder/plugins/help.py:484 spyder/plugins/help.py:937
-#: spyder/widgets/internalshell.py:270
+#: spyder/app/tour.py:179 spyder/plugins/help.py:482 spyder/plugins/help.py:931
+#: spyder/widgets/internalshell.py:271
msgid "Help"
msgstr "Ajuda"
@@ -827,7 +827,7 @@ msgstr "Tour de introdução"
msgid "New features in version 3.0"
msgstr "Novidades na versão 3.0"
-#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:446
+#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:474
msgid "Run code"
msgstr "Executar código"
@@ -835,208 +835,206 @@ msgstr "Executar código"
msgid "Go to step: "
msgstr "Vá para a etapa: "
-#: spyder/config/base.py:269
-msgid ""
-"Update LANGUAGE_CODES (inside config/base.py) if a new translation has been "
-"added to Spyder"
-msgstr ""
-"Atualize LANGUAGE_CODES (config/base.py) se um novo idioma for adicionado ao "
-"Spyder"
-
-#: spyder/config/utils.py:24
+#: spyder/config/utils.py:24 spyder/plugins/pylint/widgets/pylintgui.py:289
msgid "Python files"
msgstr "Arquivos Python"
-#: spyder/config/utils.py:25
+#: spyder/config/utils.py:26
msgid "Cython/Pyrex files"
msgstr "Arquivos Cython/Pyrex"
-#: spyder/config/utils.py:26
+#: spyder/config/utils.py:27
msgid "C files"
msgstr "Arquivos C"
-#: spyder/config/utils.py:27
+#: spyder/config/utils.py:28
msgid "C++ files"
msgstr "Arquivos C++"
-#: spyder/config/utils.py:28
+#: spyder/config/utils.py:29
msgid "OpenCL files"
msgstr "Arquivos OpenCL"
-#: spyder/config/utils.py:29
+#: spyder/config/utils.py:30
msgid "Fortran files"
msgstr "Arquivos Fortran"
-#: spyder/config/utils.py:30
+#: spyder/config/utils.py:31
msgid "IDL files"
msgstr "Arquivos IDL"
-#: spyder/config/utils.py:31
+#: spyder/config/utils.py:32
msgid "MATLAB files"
msgstr "Arquivos MATLAB"
-#: spyder/config/utils.py:32
+#: spyder/config/utils.py:33
msgid "Julia files"
msgstr "Arquivos Julia"
-#: spyder/config/utils.py:33
+#: spyder/config/utils.py:34
msgid "Yaml files"
msgstr "Arquivos Yaml"
-#: spyder/config/utils.py:34
+#: spyder/config/utils.py:35
msgid "Patch and diff files"
msgstr "Arquivos Patch e diff"
-#: spyder/config/utils.py:35
+#: spyder/config/utils.py:36
msgid "Batch files"
msgstr "Arquivos Batch"
-#: spyder/config/utils.py:36 spyder/utils/iofuncs.py:426
+#: spyder/config/utils.py:37
msgid "Text files"
msgstr "Arquivos de texto"
-#: spyder/config/utils.py:37
+#: spyder/config/utils.py:38
msgid "reStructuredText files"
msgstr "Arquivos de texto reeStruturado"
-#: spyder/config/utils.py:38
+#: spyder/config/utils.py:39
msgid "gettext files"
-msgstr "Arquivos gettext "
+msgstr "Arquivos gettext"
-#: spyder/config/utils.py:39
+#: spyder/config/utils.py:40
msgid "NSIS files"
-msgstr "Arquivos NSIS "
+msgstr "Arquivos NSIS"
-#: spyder/config/utils.py:40
+#: spyder/config/utils.py:41
msgid "Web page files"
msgstr "Arquivos de Páginas web"
-#: spyder/config/utils.py:41
+#: spyder/config/utils.py:42
msgid "XML files"
msgstr "Arquivos XML"
-#: spyder/config/utils.py:42
+#: spyder/config/utils.py:43
msgid "Javascript files"
msgstr "Arquivos Javascript"
-#: spyder/config/utils.py:43
+#: spyder/config/utils.py:44
msgid "Json files"
msgstr "Arquivos Json"
-#: spyder/config/utils.py:44
+#: spyder/config/utils.py:45
msgid "IPython notebooks"
msgstr "Notebooks do IPython"
-#: spyder/config/utils.py:45
+#: spyder/config/utils.py:46
msgid "Enaml files"
msgstr "Arquivos Enaml"
-#: spyder/config/utils.py:46
+#: spyder/config/utils.py:47
msgid "Configuration files"
msgstr "Arquivos de Configuração"
-#: spyder/config/utils.py:48
+#: spyder/config/utils.py:49
msgid "Markdown files"
msgstr "Arquivos Markdown"
-#: spyder/config/utils.py:52 spyder/widgets/explorer.py:794
+#: spyder/config/utils.py:53 spyder/widgets/explorer.py:796
msgid "All files"
msgstr "Todos os arquivos"
-#: spyder/config/utils.py:134
+#: spyder/config/utils.py:138
msgid "Supported text files"
msgstr "Arquivos de texto suportados"
-#: spyder/plugins/__init__.py:511 spyder/plugins/editor.py:105
-#: spyder/plugins/editor.py:568 spyder/plugins/editor.py:1816
-#: spyder/plugins/help.py:117 spyder/plugins/help.py:385
-#: spyder/widgets/editor.py:534 spyder/widgets/sourcecode/codeeditor.py:98
-#: spyder/widgets/sourcecode/codeeditor.py:3222
+#: spyder/plugins/__init__.py:512 spyder/plugins/editor.py:105
+#: spyder/plugins/editor.py:568 spyder/plugins/editor.py:1830
+#: spyder/plugins/help.py:117 spyder/plugins/help.py:383
+#: spyder/widgets/editor.py:544 spyder/widgets/sourcecode/codeeditor.py:98
+#: spyder/widgets/sourcecode/codeeditor.py:3229
msgid "Editor"
msgstr "Editor"
-#: spyder/plugins/configdialog.py:144
+#: spyder/plugins/configdialog.py:146
msgid "Reset to defaults"
msgstr "Redefinir Preferências"
-#: spyder/plugins/configdialog.py:156
+#: spyder/plugins/configdialog.py:158
msgid "Preferences"
msgstr "Preferências"
-#: spyder/plugins/configdialog.py:508
+#: spyder/plugins/configdialog.py:514
msgid "Invalid directory path"
msgstr "Caminho de diretório inválido"
-#: spyder/plugins/configdialog.py:511 spyder/plugins/configdialog.py:526
+#: spyder/plugins/configdialog.py:517 spyder/plugins/configdialog.py:532
#: spyder/plugins/runconfig.py:220 spyder/plugins/runconfig.py:268
-#: spyder/plugins/workingdirectory.py:240 spyder/widgets/explorer.py:705
-#: spyder/widgets/findinfiles.py:332 spyder/widgets/pathmanager.py:258
+#: spyder/plugins/workingdirectory.py:241 spyder/widgets/explorer.py:707
+#: spyder/widgets/findinfiles.py:347 spyder/widgets/pathmanager.py:259
#: spyder/widgets/projects/projectdialog.py:155
msgid "Select directory"
msgstr "Selecionar diretório"
-#: spyder/plugins/configdialog.py:538
+#: spyder/plugins/configdialog.py:544 spyder/plugins/configdialog.py:704
msgid "Invalid file path"
-msgstr "Caminho de arquivo inválido "
+msgstr "Caminho de arquivo inválido"
-#: spyder/plugins/configdialog.py:541 spyder/plugins/configdialog.py:558
+#: spyder/plugins/configdialog.py:547 spyder/plugins/configdialog.py:564
+#: spyder/plugins/configdialog.py:707
msgid "Select file"
msgstr "Selecionar arquivo"
-#: spyder/plugins/configdialog.py:557
+#: spyder/plugins/configdialog.py:563
msgid "All files (*)"
msgstr "Todos os arquivos (*)"
-#: spyder/plugins/configdialog.py:630
+#: spyder/plugins/configdialog.py:636
msgid "Bold"
msgstr "Negrito"
-#: spyder/plugins/configdialog.py:633
+#: spyder/plugins/configdialog.py:639
msgid "Italic"
msgstr "Itálico"
-#: spyder/plugins/configdialog.py:687
+#: spyder/plugins/configdialog.py:728
msgid "Font: "
-msgstr "Fonte:"
+msgstr "Fonte: "
-#: spyder/plugins/configdialog.py:693
+#: spyder/plugins/configdialog.py:734
msgid "Size: "
-msgstr "Tamanho:"
+msgstr "Tamanho: "
-#: spyder/plugins/configdialog.py:712
+#: spyder/plugins/configdialog.py:753
msgid "Font style"
msgstr "Estilo de fonte"
-#: spyder/plugins/configdialog.py:789
+#: spyder/plugins/configdialog.py:830
msgid "Spyder needs to restart to change the following setting:"
msgstr "O Spyder precisa ser reiniciado para mudança de tal configuração:"
-#: spyder/plugins/configdialog.py:792
+#: spyder/plugins/configdialog.py:833
msgid "Spyder needs to restart to change the following settings:"
msgstr "O Spyder precisa ser reiniciado para mudança de tais configurações:"
-#: spyder/plugins/configdialog.py:794
+#: spyder/plugins/configdialog.py:835
msgid "Do you wish to restart now?"
msgstr "Você deseja reiniciar agora?"
-#: spyder/plugins/configdialog.py:800
+#: spyder/plugins/configdialog.py:841
msgid "Information"
msgstr "Informação"
-#: spyder/plugins/configdialog.py:814 spyder/plugins/configdialog.py:821
+#: spyder/plugins/configdialog.py:855 spyder/plugins/configdialog.py:862
#: spyder/widgets/projects/configdialog.py:74
msgid "General"
msgstr "Geral"
-#: spyder/plugins/configdialog.py:824
-msgid "Language"
+#: spyder/plugins/configdialog.py:866
+#, fuzzy
+msgid "Language:"
msgstr "Idioma"
-#: spyder/plugins/configdialog.py:827
+#: spyder/plugins/configdialog.py:874
+msgid "Rendering engine:"
+msgstr ""
+
+#: spyder/plugins/configdialog.py:879
msgid "Use a single instance"
-msgstr "Usar uma única instância "
+msgstr "Usar uma única instância"
-#: spyder/plugins/configdialog.py:829
+#: spyder/plugins/configdialog.py:881
msgid ""
"Set this to open external
Python files in an already running instance "
"(Requires a restart)"
@@ -1044,90 +1042,90 @@ msgstr ""
"Selecione esta opção
para abrir arquivos externos de Python nessa "
"instância atual (Requer que seja reiniciado)"
-#: spyder/plugins/configdialog.py:832
+#: spyder/plugins/configdialog.py:885
msgid "Prompt when exiting"
msgstr "Mostrar mensagem de confirmação ao sair"
-#: spyder/plugins/configdialog.py:833
+#: spyder/plugins/configdialog.py:886
msgid "Show internal Spyder errors to report them to Github"
msgstr "Mostrar erros internos do Spyder e reportar eles para o Github"
-#: spyder/plugins/configdialog.py:852 spyder/plugins/editor.py:114
-#: spyder/plugins/ipythonconsole.py:290
+#: spyder/plugins/configdialog.py:914 spyder/plugins/editor.py:114
+#: spyder/plugins/ipythonconsole.py:301
#: spyder/widgets/projects/configdialog.py:81
msgid "Interface"
msgstr "Interface"
-#: spyder/plugins/configdialog.py:860
+#: spyder/plugins/configdialog.py:922
msgid "Qt windows style"
msgstr "Tema do Qt"
-#: spyder/plugins/configdialog.py:866
+#: spyder/plugins/configdialog.py:928
msgid "Icon theme"
msgstr "Tema dos icones"
-#: spyder/plugins/configdialog.py:870
+#: spyder/plugins/configdialog.py:932
msgid "Vertical title bars in panes"
msgstr "Barra de titulo em vertical"
-#: spyder/plugins/configdialog.py:872
+#: spyder/plugins/configdialog.py:934
msgid "Vertical tabs in panes"
msgstr "Abas dos painéis na vertical"
-#: spyder/plugins/configdialog.py:874
+#: spyder/plugins/configdialog.py:936
msgid "Animated toolbars and panes"
msgstr "Barras e painéis animados"
-#: spyder/plugins/configdialog.py:876
+#: spyder/plugins/configdialog.py:938
msgid "Tear off menus"
msgstr "Separar os menus"
-#: spyder/plugins/configdialog.py:877
+#: spyder/plugins/configdialog.py:939
msgid "Set this to detach any
menu from the main window"
msgstr "Habilite esta opção
se deseja separar os menus da janela principal"
-#: spyder/plugins/configdialog.py:879
+#: spyder/plugins/configdialog.py:941
msgid "Custom margin for panes:"
msgstr "Margem personalizada para os painéis:"
-#: spyder/plugins/configdialog.py:881
+#: spyder/plugins/configdialog.py:943
msgid "pixels"
msgstr "pixels"
-#: spyder/plugins/configdialog.py:888
+#: spyder/plugins/configdialog.py:950
msgid "Cursor blinking:"
msgstr "Cursor piscando:"
-#: spyder/plugins/configdialog.py:890
+#: spyder/plugins/configdialog.py:952
msgid "ms"
msgstr "ms"
-#: spyder/plugins/configdialog.py:929
+#: spyder/plugins/configdialog.py:991
msgid "Status bar"
msgstr "Barra de status"
-#: spyder/plugins/configdialog.py:930
+#: spyder/plugins/configdialog.py:992
msgid "Show status bar"
msgstr "Mostrar barra de status"
-#: spyder/plugins/configdialog.py:932
+#: spyder/plugins/configdialog.py:994
msgid "Show memory usage every"
msgstr "Mostrar uso da memória a cada"
-#: spyder/plugins/configdialog.py:934 spyder/plugins/configdialog.py:943
+#: spyder/plugins/configdialog.py:996 spyder/plugins/configdialog.py:1005
#: spyder/plugins/editor.py:139 spyder/plugins/editor.py:283
msgid " ms"
-msgstr "ms"
+msgstr " ms"
-#: spyder/plugins/configdialog.py:941
+#: spyder/plugins/configdialog.py:1003
msgid "Show CPU usage every"
msgstr "Mostrar uso da CPU a cada"
-#: spyder/plugins/configdialog.py:974
+#: spyder/plugins/configdialog.py:1036
msgid "Screen resolution"
msgstr "Resolução da tela"
-#: spyder/plugins/configdialog.py:976
+#: spyder/plugins/configdialog.py:1038
msgid ""
"Configuration for high DPI screens
Please see {0}"
"a><> for more information about these options (in English)."
@@ -1135,28 +1133,28 @@ msgstr ""
"Configuração para telas de alto DPI
Por favor veja {0}"
"<> para mais informações sobre essas opções (em Inglês)."
-#: spyder/plugins/configdialog.py:986
+#: spyder/plugins/configdialog.py:1048
msgid "Normal"
msgstr "Normal"
-#: spyder/plugins/configdialog.py:990
+#: spyder/plugins/configdialog.py:1052
msgid "Enable auto high DPI scaling"
msgstr "Ativar escala automática de DPI"
-#: spyder/plugins/configdialog.py:993
+#: spyder/plugins/configdialog.py:1055
msgid "Set this for high DPI displays"
msgstr "Ativar em telas de alto DPI"
-#: spyder/plugins/configdialog.py:997
+#: spyder/plugins/configdialog.py:1059
msgid "Set a custom high DPI scaling"
msgstr "Definir uma escala de DPI personalizada"
-#: spyder/plugins/configdialog.py:1000
+#: spyder/plugins/configdialog.py:1062
msgid "Set this for high DPI displays when auto scaling does not work"
msgstr ""
-"Definir isso para telas de alto DPI quando a escala automática não funcionar."
+"Definir isso para telas de alto DPI quando a escala automática não funcionar"
-#: spyder/plugins/configdialog.py:1006
+#: spyder/plugins/configdialog.py:1068
msgid ""
"Enter values for different screens separated by semicolons ';', float values "
"are supported"
@@ -1164,31 +1162,37 @@ msgstr ""
"Insira os valores para diferentes telas separadas por ponto-e-vírgula ';', "
"valores float são suportados"
-#: spyder/plugins/configdialog.py:1033
+#: spyder/plugins/configdialog.py:1095
msgid "Plain text font"
msgstr "Texto simples"
-#: spyder/plugins/configdialog.py:1039
+#: spyder/plugins/configdialog.py:1101
msgid "Rich text font"
msgstr "Texto formatado"
-#: spyder/plugins/configdialog.py:1042
+#: spyder/plugins/configdialog.py:1104
msgid "Fonts"
msgstr "Fontes"
-#: spyder/plugins/configdialog.py:1056
+#: spyder/plugins/configdialog.py:1118
msgid "Appearance"
msgstr "Aparência"
-#: spyder/plugins/configdialog.py:1058 spyder/plugins/ipythonconsole.py:579
+#: spyder/plugins/configdialog.py:1120 spyder/plugins/ipythonconsole.py:633
msgid "Advanced Settings"
msgstr "Configurações avançadas"
-#: spyder/plugins/configdialog.py:1094
+#: spyder/plugins/configdialog.py:1155
+msgid ""
+"We're sorry but the following error occurred while trying to set your "
+"selected language:
{}"
+msgstr ""
+
+#: spyder/plugins/configdialog.py:1164
msgid "Syntax coloring"
msgstr "Sintaxe colorida"
-#: spyder/plugins/configdialog.py:1107
+#: spyder/plugins/configdialog.py:1177
msgid ""
"Here you can select the color scheme used in the Editor and all other Spyder "
"plugins.
You can also edit the color schemes provided by Spyder or "
@@ -1198,52 +1202,52 @@ msgstr ""
"plugins do Spyder.
Você pode também editar os esquemas padrões do "
"Spyder ou criar os seus próprios utilizando as opções abaixo.
"
-#: spyder/plugins/configdialog.py:1112
+#: spyder/plugins/configdialog.py:1182
msgid "Edit selected"
msgstr "Editar"
-#: spyder/plugins/configdialog.py:1113
+#: spyder/plugins/configdialog.py:1183
msgid "Create new scheme"
msgstr "Criar novo esquema"
-#: spyder/plugins/configdialog.py:1114 spyder/widgets/explorer.py:583
+#: spyder/plugins/configdialog.py:1184 spyder/widgets/explorer.py:582
#: spyder/widgets/projects/explorer.py:243 spyder/widgets/shell.py:136
msgid "Delete"
msgstr "Deletar"
-#: spyder/plugins/configdialog.py:1117
+#: spyder/plugins/configdialog.py:1187
msgid "Reset"
msgstr "Restaurar"
-#: spyder/plugins/configdialog.py:1124
+#: spyder/plugins/configdialog.py:1194
msgid "Scheme:"
msgstr "Esquema:"
-#: spyder/plugins/configdialog.py:1155
+#: spyder/plugins/configdialog.py:1225
msgid "Manage color schemes"
msgstr "Gerenciar esquemas de cores"
-#: spyder/plugins/configdialog.py:1346
+#: spyder/plugins/configdialog.py:1416
msgid "Are you sure you want to delete this scheme?"
msgstr "Você tem certeza que deseja deletar esse esquema?"
-#: spyder/plugins/configdialog.py:1463
+#: spyder/plugins/configdialog.py:1533
msgid "Text"
msgstr "Texto"
-#: spyder/plugins/configdialog.py:1465
+#: spyder/plugins/configdialog.py:1535
msgid "Highlight"
msgstr "Destaque"
-#: spyder/plugins/configdialog.py:1467
+#: spyder/plugins/configdialog.py:1537
msgid "Background"
msgstr "Plano de fundo"
-#: spyder/plugins/configdialog.py:1471
+#: spyder/plugins/configdialog.py:1541
msgid "Scheme name:"
msgstr "Nome do esquema:"
-#: spyder/plugins/configdialog.py:1478
+#: spyder/plugins/configdialog.py:1548
msgid "Color scheme editor"
msgstr "Edição do esquema de cores"
@@ -1279,26 +1283,26 @@ msgstr "Mostrar conteúdo da sys.path em modo de leitura"
msgid "Buffer..."
msgstr "Buffer..."
-#: spyder/plugins/console.py:163 spyder/plugins/history.py:43
+#: spyder/plugins/console.py:163 spyder/plugins/history.py:45
msgid "Set maximum line count"
msgstr "Definir número máximo de linhas"
#: spyder/plugins/console.py:166
msgid "External editor path..."
-msgstr "Caminho de editor externo:"
+msgstr "Caminho de editor externo..."
#: spyder/plugins/console.py:167
msgid "Set external editor executable path"
msgstr "Definir caminho de editor externo"
#: spyder/plugins/console.py:170 spyder/plugins/editor.py:149
-#: spyder/plugins/help.py:152 spyder/plugins/help.py:360
-#: spyder/plugins/history.py:46 spyder/plugins/history.py:157
+#: spyder/plugins/help.py:152 spyder/plugins/help.py:358
+#: spyder/plugins/history.py:48 spyder/plugins/history.py:159
msgid "Wrap lines"
msgstr "Ajuste de linha automático"
#: spyder/plugins/console.py:173 spyder/plugins/editor.py:185
-#: spyder/plugins/ipythonconsole.py:300
+#: spyder/plugins/ipythonconsole.py:311
msgid "Display balloon tips"
msgstr "Mostrar sugestões"
@@ -1318,7 +1322,8 @@ msgstr "Configurações do console interno"
msgid "Run Python script"
msgstr "Executar script Python"
-#: spyder/plugins/console.py:266 spyder/widgets/explorer.py:809
+#: spyder/plugins/console.py:266 spyder/widgets/explorer.py:811
+#: spyder/plugins/profiler/widgets/profilergui.py:220
msgid "Python scripts"
msgstr "Scripts Python"
@@ -1351,8 +1356,8 @@ msgid "Show tab bar"
msgstr "Mostrar barra de abas"
#: spyder/plugins/editor.py:122 spyder/plugins/editor.py:199
-#: spyder/plugins/help.py:151 spyder/plugins/history.py:45
-#: spyder/plugins/ipythonconsole.py:332
+#: spyder/plugins/help.py:151 spyder/plugins/history.py:47
+#: spyder/plugins/ipythonconsole.py:349
msgid "Source code"
msgstr "Código fonte"
@@ -1446,7 +1451,7 @@ msgstr "Indentação automática depois do 'else', 'elif', etc."
#: spyder/plugins/editor.py:210
msgid "Indentation characters: "
-msgstr "Caracteres de indentação:"
+msgstr "Caracteres de indentação: "
#: spyder/plugins/editor.py:211
msgid "2 spaces"
@@ -1591,8 +1596,8 @@ msgstr ""
msgid "Fix automatically and show warning message box"
msgstr "Corrigir automaticamente e exibir uma mensagem de aviso"
-#: spyder/plugins/editor.py:357 spyder/plugins/ipythonconsole.py:573
-#: spyder/plugins/variableexplorer.py:35
+#: spyder/plugins/editor.py:357 spyder/plugins/ipythonconsole.py:627
+#: spyder/plugins/variableexplorer.py:47
msgid "Display"
msgstr "Visualização"
@@ -1608,8 +1613,8 @@ msgstr "Configurações avançadas"
msgid "&New file..."
msgstr "&Novo arquivo..."
-#: spyder/plugins/editor.py:645 spyder/widgets/explorer.py:786
-#: spyder/widgets/explorer.py:793
+#: spyder/plugins/editor.py:645 spyder/widgets/explorer.py:788
+#: spyder/widgets/explorer.py:795
msgid "New file"
msgstr "Novo arquivo"
@@ -1625,8 +1630,8 @@ msgstr "Abrir último arquivo fechado"
msgid "&Open..."
msgstr "&Abrir..."
-#: spyder/plugins/editor.py:662 spyder/plugins/editor.py:1867
-#: spyder/plugins/editor.py:1873
+#: spyder/plugins/editor.py:662 spyder/plugins/editor.py:1881
+#: spyder/plugins/editor.py:1887
msgid "Open file"
msgstr "Abrir arquivo"
@@ -1642,7 +1647,7 @@ msgstr "Reverter arquivo do disco"
msgid "&Save"
msgstr "&Salvar"
-#: spyder/plugins/editor.py:673 spyder/widgets/editor.py:1672
+#: spyder/plugins/editor.py:673 spyder/widgets/editor.py:1675
msgid "Save file"
msgstr "Salvar arquivo"
@@ -1723,6 +1728,7 @@ msgid "Set/Edit conditional breakpoint"
msgstr "Adicionar ou editar um ponto de interrupção condicional"
#: spyder/plugins/editor.py:755
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:180
msgid "Clear breakpoints in all files"
msgstr "Limpar pontos de interrupção em todos os arquivos"
@@ -1766,8 +1772,10 @@ msgstr "Sair da função/método"
msgid "Run until current function or method returns"
msgstr "Executar até que a função ou método atual terminem"
-#: spyder/plugins/editor.py:796 spyder/widgets/findinfiles.py:438
-#: spyder/widgets/ipythonconsole/client.py:354
+#: spyder/plugins/editor.py:796 spyder/widgets/findinfiles.py:450
+#: spyder/widgets/ipythonconsole/client.py:393
+#: spyder/plugins/pylint/widgets/pylintgui.py:211
+#: spyder/plugins/profiler/widgets/profilergui.py:87
msgid "Stop"
msgstr "Parar"
@@ -1795,7 +1803,7 @@ msgstr "Executar &novamente o último script"
msgid "Run again last file"
msgstr "Executar novamente o mesmo arquivo"
-#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2720
+#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2727
msgid "Run &selection or current line"
msgstr "Executar &seleção ou linha atual"
@@ -1803,7 +1811,7 @@ msgstr "Executar &seleção ou linha atual"
msgid "Run selection or current line"
msgstr "Executar seleção ou linha atual"
-#: spyder/plugins/editor.py:836 spyder/widgets/sourcecode/codeeditor.py:2708
+#: spyder/plugins/editor.py:836 spyder/widgets/sourcecode/codeeditor.py:2715
msgid "Run cell"
msgstr "Executar célula"
@@ -1815,7 +1823,7 @@ msgstr ""
"Executar a célula atual (Ctrl+Enter)\n"
"[Usar #%% para criar células]"
-#: spyder/plugins/editor.py:845 spyder/widgets/sourcecode/codeeditor.py:2712
+#: spyder/plugins/editor.py:845 spyder/widgets/sourcecode/codeeditor.py:2719
msgid "Run cell and advance"
msgstr "Executar célula e avançar"
@@ -1823,9 +1831,9 @@ msgstr "Executar célula e avançar"
msgid "Run current cell and go to the next one (Shift+Enter)"
msgstr "Executar célula atual e ir para a próxima (Shift+Enter)"
-#: spyder/plugins/editor.py:854 spyder/widgets/sourcecode/codeeditor.py:2716
+#: spyder/plugins/editor.py:854 spyder/widgets/sourcecode/codeeditor.py:2723
msgid "Re-run last cell"
-msgstr "Executar novamente a última célula "
+msgstr "Executar novamente a última célula"
#: spyder/plugins/editor.py:855
msgid "Re run last cell "
@@ -1890,11 +1898,11 @@ msgstr "Próxima posição do cursor"
msgid "Go to next cursor position"
msgstr "Ir para a próxima posição do cursor"
-#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Comment"
msgstr "Comentar"
-#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Uncomment"
msgstr "Descomentar"
@@ -1904,7 +1912,7 @@ msgstr "Comentar linha ou seleção atual"
#: spyder/plugins/editor.py:924
msgid "Add &block comment"
-msgstr "Adicionar &bloco de comentário "
+msgstr "Adicionar &bloco de comentário"
#: spyder/plugins/editor.py:925
msgid "Add block comment around current line or selection"
@@ -1992,7 +2000,7 @@ msgid ""
"directory"
msgstr ""
"Definir o diretório de trabalho do console (e do explorador de arquivos) "
-"para o diretório do script atual."
+"para o diretório do script atual"
#: spyder/plugins/editor.py:1006
msgid "Maximum number of recent files..."
@@ -2002,8 +2010,8 @@ msgstr "Número máximo de arquivos recentes..."
msgid "Clear recent files list"
msgstr "Limpar lista de arquivos recentes"
-#: spyder/plugins/editor.py:1009 spyder/plugins/projects.py:107
-#: spyder/widgets/findinfiles.py:246
+#: spyder/plugins/editor.py:1009 spyder/plugins/projects.py:101
+#: spyder/widgets/findinfiles.py:261
msgid "Clear this list"
msgstr "Limpar esta lista"
@@ -2011,39 +2019,39 @@ msgstr "Limpar esta lista"
msgid "Open &recent"
msgstr "Abrir &recente"
-#: spyder/plugins/editor.py:1675
+#: spyder/plugins/editor.py:1674
msgid "Spyder Editor"
msgstr "Spyder Editor"
-#: spyder/plugins/editor.py:1676
+#: spyder/plugins/editor.py:1675
msgid "This is a temporary script file."
msgstr "Este é um arquivo de script temporário."
-#: spyder/plugins/editor.py:1745
+#: spyder/plugins/editor.py:1758
msgid "untitled"
-msgstr "Sem título"
+msgstr "sem título"
-#: spyder/plugins/editor.py:1817
+#: spyder/plugins/editor.py:1831
msgid "Maximum number of recent files"
msgstr "Número máximo de arquivos recentes"
-#: spyder/plugins/editor.py:1963
+#: spyder/plugins/editor.py:1977
msgid "Printing..."
msgstr "Imprimindo..."
-#: spyder/plugins/explorer.py:54
+#: spyder/plugins/explorer.py:55
msgid "File explorer"
msgstr "Explorador de arquivos"
-#: spyder/plugins/findinfiles.py:120 spyder/widgets/findinfiles.py:913
+#: spyder/plugins/findinfiles.py:117 spyder/widgets/findinfiles.py:949
msgid "Find in files"
msgstr "Procurar em arquivos"
-#: spyder/plugins/findinfiles.py:145
+#: spyder/plugins/findinfiles.py:141
msgid "&Find in files"
msgstr "Procurar em arqui&vos"
-#: spyder/plugins/findinfiles.py:150
+#: spyder/plugins/findinfiles.py:146
msgid "Search text in multiple files"
msgstr "Procurar em vários arquivos"
@@ -2053,7 +2061,7 @@ msgstr "Mostra ajuda para objetos do Editor e Consoles em um painel dedicado"
#: spyder/plugins/help.py:109
msgid "Automatic connections"
-msgstr "Conexões automáticas "
+msgstr "Conexões automáticas"
#: spyder/plugins/help.py:110
msgid ""
@@ -2097,47 +2105,47 @@ msgstr "Sphinx %s está instalado atualmente."
msgid "No further documentation available"
msgstr "Nenhuma documentação adicional disponível"
-#: spyder/plugins/help.py:307 spyder/plugins/help.py:347
+#: spyder/plugins/help.py:307 spyder/plugins/help.py:345
msgid "No documentation available"
msgstr "Nenhuma documentação disponível"
-#: spyder/plugins/help.py:378
+#: spyder/plugins/help.py:376
msgid "Source"
msgstr "Origem"
-#: spyder/plugins/help.py:385 spyder/plugins/runconfig.py:170
-#: spyder/plugins/runconfig.py:486 spyder/widgets/ipythonconsole/client.py:288
+#: spyder/plugins/help.py:383 spyder/plugins/runconfig.py:170
+#: spyder/plugins/runconfig.py:486 spyder/widgets/ipythonconsole/client.py:327
msgid "Console"
msgstr "Console"
-#: spyder/plugins/help.py:393
+#: spyder/plugins/help.py:391
msgid "Object"
msgstr "Objeto"
-#: spyder/plugins/help.py:407
+#: spyder/plugins/help.py:405
msgid "Plain Text"
msgstr "Texto Normal"
-#: spyder/plugins/help.py:411
+#: spyder/plugins/help.py:409
msgid "Show Source"
msgstr "Mostrar código fonte"
-#: spyder/plugins/help.py:415
+#: spyder/plugins/help.py:413
msgid "Rich Text"
msgstr "Texto Formatado"
-#: spyder/plugins/help.py:425
+#: spyder/plugins/help.py:423
msgid "Automatic import"
msgstr "Importar automaticamente"
-#: spyder/plugins/help.py:437 spyder/plugins/history.py:106
-#: spyder/widgets/editor.py:728 spyder/widgets/explorer.py:1200
-#: spyder/widgets/ipythonconsole/client.py:378
-#: spyder/widgets/variableexplorer/namespacebrowser.py:148
+#: spyder/plugins/help.py:435 spyder/plugins/history.py:108
+#: spyder/widgets/editor.py:738 spyder/widgets/explorer.py:1205
+#: spyder/widgets/ipythonconsole/client.py:417
+#: spyder/widgets/variableexplorer/namespacebrowser.py:151
msgid "Options"
msgstr "Opções"
-#: spyder/plugins/help.py:696
+#: spyder/plugins/help.py:692
msgid ""
"Here you can get help of any object by pressing %s in front of it, either on "
"the Editor or the Console.%sHelp can also be shown automatically after "
@@ -2149,38 +2157,38 @@ msgstr ""
"também pode ser mostrada automaticamente depois de escrever um parênteses "
"junto a um objeto. Você pode ativar este comportamento em %s."
-#: spyder/plugins/help.py:702
+#: spyder/plugins/help.py:698
msgid "Preferences > Help"
msgstr "Preferências > Ajuda"
-#: spyder/plugins/help.py:709
+#: spyder/plugins/help.py:705
msgid "Usage"
msgstr "Uso"
-#: spyder/plugins/help.py:710
+#: spyder/plugins/help.py:706
msgid "New to Spyder? Read our"
msgstr "Novo no Spyder? Leia nosso"
-#: spyder/plugins/help.py:711
+#: spyder/plugins/help.py:707
msgid "tutorial"
msgstr "tutorial"
-#: spyder/plugins/help.py:718
+#: spyder/plugins/help.py:714
msgid ""
"Please consider installing Sphinx to get documentation rendered in rich text."
msgstr ""
"Por favor considere instalar o Sphinx para obter a documentação em texto "
"formatado."
-#: spyder/plugins/help.py:891
+#: spyder/plugins/help.py:885
msgid "Lock"
msgstr "Trancar"
-#: spyder/plugins/help.py:891
+#: spyder/plugins/help.py:885
msgid "Unlock"
msgstr "Destrancar"
-#: spyder/plugins/help.py:938
+#: spyder/plugins/help.py:932
msgid ""
"The following error occured when calling Sphinx %s.
Incompatible "
"Sphinx version or doc string decoding failed.
Error message:
%s"
@@ -2189,63 +2197,68 @@ msgstr ""
"
Isso se deve a uma versão incompatível do Sphinx ou não foi possível ler "
"a documentação solicitada.
Mensagem de erro:
%s"
-#: spyder/plugins/help.py:982
+#: spyder/plugins/help.py:976
msgid "No source code available."
-msgstr "O código fonte não está disponível"
+msgstr "O código fonte não está disponível."
-#: spyder/plugins/history.py:39
+#: spyder/plugins/history.py:39 spyder/plugins/pylint/plugin.py:35
msgid "Settings"
msgstr "Configurações"
-#: spyder/plugins/history.py:41
+#: spyder/plugins/history.py:43
msgid " entries"
-msgstr "entradas"
+msgstr " entradas"
-#: spyder/plugins/history.py:41
+#: spyder/plugins/history.py:43
msgid "History depth: "
msgstr "Profundidade do histórico: "
-#: spyder/plugins/history.py:48
+#: spyder/plugins/history.py:50
msgid "Scroll automatically to last entry"
msgstr "Ir automaticamente para a última entrada"
-#: spyder/plugins/history.py:126
+#: spyder/plugins/history.py:128
msgid "History log"
-msgstr "Log do histórico "
+msgstr "Log do histórico"
-#: spyder/plugins/history.py:153
+#: spyder/plugins/history.py:153 spyder/plugins/pylint/plugin.py:115
msgid "History..."
msgstr "Histórico..."
-#: spyder/plugins/history.py:155
+#: spyder/plugins/history.py:155 spyder/plugins/pylint/plugin.py:117
msgid "Set history maximum entries"
msgstr "Definir número máximo de entradas para armazenar"
-#: spyder/plugins/history.py:260
+#: spyder/plugins/history.py:260 spyder/plugins/pylint/plugin.py:39
+#: spyder/plugins/pylint/plugin.py:160
msgid "History"
msgstr "Histórico"
-#: spyder/plugins/history.py:261
+#: spyder/plugins/history.py:261 spyder/plugins/pylint/plugin.py:161
msgid "Maximum entries"
msgstr "Número máximo de entradas"
-#: spyder/plugins/ipythonconsole.py:65
+#: spyder/plugins/ipythonconsole.py:64
msgid "Symbolic mathematics in the IPython Console"
msgstr "Matemática simbólica no console IPython"
-#: spyder/plugins/ipythonconsole.py:69
+#: spyder/plugins/ipythonconsole.py:68
msgid "Run Cython files in the IPython Console"
msgstr "Executar arquivos Cython no console IPython"
-#: spyder/plugins/ipythonconsole.py:73
+#: spyder/plugins/ipythonconsole.py:72
msgid "Integrate the IPython console"
msgstr "Integração com o console IPython"
-#: spyder/plugins/ipythonconsole.py:77
+#: spyder/plugins/ipythonconsole.py:76
msgid "IPython interactive python environment"
msgstr "IPython ambiente interativo python"
-#: spyder/plugins/ipythonconsole.py:128
+#: spyder/plugins/ipythonconsole.py:80
+msgid "Display 2D graphics in the IPython Console"
+msgstr "Mostrar gráficos 2D no console IPython"
+
+#: spyder/plugins/ipythonconsole.py:131
msgid ""
"The authenticity of host %s can't be established. Are you sure you "
"want to continue connecting?"
@@ -2253,92 +2266,104 @@ msgstr ""
"A autenticidade do servidor %s não pode ser estabelecida. Você tem "
"certeza que deseja continuar conectando?"
-#: spyder/plugins/ipythonconsole.py:140
+#: spyder/plugins/ipythonconsole.py:143
msgid "The authenticity of the host can't be established"
msgstr "A autenticidade do servidor não pode ser estabelecida"
-#: spyder/plugins/ipythonconsole.py:147
+#: spyder/plugins/ipythonconsole.py:150
msgid "Tunnel '%s' failed to start"
msgstr "O túnel '%s' falhou ao ser iniciado"
-#: spyder/plugins/ipythonconsole.py:152
+#: spyder/plugins/ipythonconsole.py:155
msgid "Could not connect to remote host"
msgstr "Não foi possível conectar ao servidor remoto"
-#: spyder/plugins/ipythonconsole.py:169 spyder/plugins/ipythonconsole.py:799
+#: spyder/plugins/ipythonconsole.py:172 spyder/plugins/ipythonconsole.py:846
msgid "Connect to an existing kernel"
msgstr "Conectar a um kernel já existente"
-#: spyder/plugins/ipythonconsole.py:171
+#: spyder/plugins/ipythonconsole.py:174
msgid ""
-"Please enter the connection info of the kernel you want to connect to. For "
-"that you can either select its JSON connection file using the Browse"
-"tt> button, or write directly its id, in case it's a local kernel (for "
-"example kernel-3764.json or just 3764)."
+"Please select the JSON connection file (e.g. kernel-3764.json"
+"tt>) or enter the 4-digit ID (e.g. 3764) of the existing "
+"kernel to connect to, and enter the SSH host name and credentials if a "
+"remote kernel."
msgstr ""
-"Por favor introduza a informação de conexão do kernel ao qual deseja se "
-"conectar. Para isso você pode selecionar seu arquivo de conexão JSON, usando "
-"o botão Selecionar, ou escrever diretamente seu id, em caso de que "
-"seja um kernel local (por exemplo, kernel-3764.json ou só 3764"
-"tt>)."
-#: spyder/plugins/ipythonconsole.py:182
-msgid "Connection info:"
-msgstr "Informação da conexão:"
+#: spyder/plugins/ipythonconsole.py:183
+#, fuzzy
+msgid "Kernel ID/Connection file:"
+msgstr "Abrir arquivo de conexão"
-#: spyder/plugins/ipythonconsole.py:184
-msgid "Path to connection file or kernel id"
+#: spyder/plugins/ipythonconsole.py:185
+#, fuzzy
+msgid "ID number or path to connection file"
msgstr "Caminho para arquivo de conexão ou id do kernel"
-#: spyder/plugins/ipythonconsole.py:186 spyder/plugins/ipythonconsole.py:203
+#: spyder/plugins/ipythonconsole.py:187 spyder/plugins/ipythonconsole.py:216
msgid "Browse"
msgstr "Navegar"
-#: spyder/plugins/ipythonconsole.py:195
-msgid "This is a remote kernel"
+#: spyder/plugins/ipythonconsole.py:196
+#, fuzzy
+msgid "This is a remote kernel (via SSH)"
msgstr "Este é um kernel remoto"
#: spyder/plugins/ipythonconsole.py:199
+msgid ""
+"Note: If connecting to a remote kernel, only the SSH keyfile or"
+"i> the Password field need to be completed, unless the keyfile is protected "
+"with a passphrase."
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:207
msgid "username@hostname:port"
msgstr "usuário@servidor:porta"
-#: spyder/plugins/ipythonconsole.py:202
-msgid "Path to ssh key file"
-msgstr "Caminho do arquivo de chave ssh"
-
-#: spyder/plugins/ipythonconsole.py:211
-msgid "Password or ssh key passphrase"
+#: spyder/plugins/ipythonconsole.py:210
+#, fuzzy
+msgid "Remote user password or SSH keyfile passphrase"
msgstr "Senha"
#: spyder/plugins/ipythonconsole.py:215
-msgid "Host name"
-msgstr "Nome do host "
+#, fuzzy
+msgid "Path to SSH keyfile (optional)"
+msgstr "Caminho do arquivo de chave ssh"
-#: spyder/plugins/ipythonconsole.py:216
-msgid "Ssh key"
-msgstr "Chave ssh"
+#: spyder/plugins/ipythonconsole.py:224
+#, fuzzy
+msgid "Host name:"
+msgstr "Nome do host"
-#: spyder/plugins/ipythonconsole.py:217
-msgid "Password"
-msgstr "Senha"
+#: spyder/plugins/ipythonconsole.py:225
+#, fuzzy
+msgid "Password:"
+msgstr "Senha: "
-#: spyder/plugins/ipythonconsole.py:246
-msgid "Open connection file"
+#: spyder/plugins/ipythonconsole.py:226
+#, fuzzy
+msgid "SSH keyfile:"
+msgstr "Arquivos NSIS"
+
+#: spyder/plugins/ipythonconsole.py:257
+#, fuzzy
+msgid "Select kernel connection file"
msgstr "Abrir arquivo de conexão"
-#: spyder/plugins/ipythonconsole.py:251
-msgid "Select ssh key"
-msgstr "Selecionar chave ssh"
+#: spyder/plugins/ipythonconsole.py:262
+#, fuzzy
+msgid "Select SSH keyfile"
+msgstr "Selecionar arquivo"
-#: spyder/plugins/ipythonconsole.py:284 spyder/plugins/ipythonconsole.py:734
+#: spyder/plugins/ipythonconsole.py:295 spyder/plugins/ipythonconsole.py:780
msgid "IPython console"
msgstr "Console IPython"
-#: spyder/plugins/ipythonconsole.py:291
+#: spyder/plugins/ipythonconsole.py:302
msgid "Display initial banner"
msgstr "Mostrar o banner inicial"
-#: spyder/plugins/ipythonconsole.py:292
+#: spyder/plugins/ipythonconsole.py:303
msgid ""
"This option lets you hide the message shown at\n"
"the top of the console when it's opened."
@@ -2347,11 +2372,11 @@ msgstr ""
"aparece no topo do console quando se abre\n"
"ele pela primeira vez."
-#: spyder/plugins/ipythonconsole.py:294
+#: spyder/plugins/ipythonconsole.py:305
msgid "Use a pager to display additional text inside the console"
msgstr "Usar um paginador para mostrar textos dentro do console"
-#: spyder/plugins/ipythonconsole.py:296
+#: spyder/plugins/ipythonconsole.py:307
msgid ""
"Useful if you don't want to fill the console with long help or completion "
"texts.\n"
@@ -2360,15 +2385,15 @@ msgstr ""
"Isso é útil se não deseja preencher o console com grandes textos de ajuda.\n"
"Nota: Use a tecla Q para sair do paginador."
-#: spyder/plugins/ipythonconsole.py:301
+#: spyder/plugins/ipythonconsole.py:312
msgid "Ask for confirmation before closing"
msgstr "Mostrar janela de confirmação antes de fechar"
-#: spyder/plugins/ipythonconsole.py:304
+#: spyder/plugins/ipythonconsole.py:315
msgid "Ask for confirmation before removing all user-defined variables"
msgstr "Perguntar antes de remover todas variáveis definidas pelo usuário"
-#: spyder/plugins/ipythonconsole.py:307
+#: spyder/plugins/ipythonconsole.py:318
msgid ""
"This option lets you hide the warning message shown\n"
"when resetting the namespace from Spyder."
@@ -2376,44 +2401,58 @@ msgstr ""
"Esta opção permite ocultar a mensagem de aviso mostrada \n"
"quando se vai remover todas variáveis definidas pelo usuário."
-#: spyder/plugins/ipythonconsole.py:309
-#: spyder/widgets/ipythonconsole/client.py:317
+#: spyder/plugins/ipythonconsole.py:320
+#: spyder/widgets/ipythonconsole/client.py:356
msgid "Show elapsed time"
msgstr "Mostrar tempo de execução"
-#: spyder/plugins/ipythonconsole.py:320
+#: spyder/plugins/ipythonconsole.py:322
+#, fuzzy
+msgid "Ask for confirmation before restarting"
+msgstr "Mostrar janela de confirmação antes de fechar"
+
+#: spyder/plugins/ipythonconsole.py:324
+#, fuzzy
+msgid ""
+"This option lets you hide the warning message shown\n"
+"when restarting the kernel."
+msgstr ""
+"Esta opção permite ocultar a mensagem de aviso mostrada \n"
+"quando se vai remover todas variáveis definidas pelo usuário."
+
+#: spyder/plugins/ipythonconsole.py:337
msgid "Completion Type"
msgstr "Tipo de completação"
-#: spyder/plugins/ipythonconsole.py:321
+#: spyder/plugins/ipythonconsole.py:338
msgid "Decide what type of completion to use"
msgstr "Decidir qual tipo de completação usar"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Graphical"
msgstr "Gráfico"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Plain"
msgstr "Simples"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Terminal"
msgstr "Terminal"
-#: spyder/plugins/ipythonconsole.py:324
+#: spyder/plugins/ipythonconsole.py:341
msgid "Completion:"
msgstr "Completação:"
-#: spyder/plugins/ipythonconsole.py:334
+#: spyder/plugins/ipythonconsole.py:351
msgid " lines"
-msgstr "linhas"
+msgstr " linhas"
-#: spyder/plugins/ipythonconsole.py:334
+#: spyder/plugins/ipythonconsole.py:351
msgid "Buffer: "
msgstr "Buffer: "
-#: spyder/plugins/ipythonconsole.py:336
+#: spyder/plugins/ipythonconsole.py:353
msgid ""
"Set the maximum number of lines of text shown in the\n"
"console before truncation. Specifying -1 disables it\n"
@@ -2423,19 +2462,19 @@ msgstr ""
"no console em qualquer momento. Especificando -1 serão\n"
"mostradas todas as linhas (não é recomendável!)"
-#: spyder/plugins/ipythonconsole.py:345
+#: spyder/plugins/ipythonconsole.py:362
msgid "Support for graphics (Matplotlib)"
msgstr "Suporte para criação de gráficos (Matplotlib)"
-#: spyder/plugins/ipythonconsole.py:346
+#: spyder/plugins/ipythonconsole.py:363
msgid "Activate support"
msgstr "Ativar suporte"
-#: spyder/plugins/ipythonconsole.py:347
+#: spyder/plugins/ipythonconsole.py:364
msgid "Automatically load Pylab and NumPy modules"
msgstr "Carregar automaticamente os módulos do Pylab e do NumPy"
-#: spyder/plugins/ipythonconsole.py:350
+#: spyder/plugins/ipythonconsole.py:367
msgid ""
"This lets you load graphics support without importing \n"
"the commands to do plots. Useful to work with other\n"
@@ -2447,19 +2486,19 @@ msgstr ""
"outras bibliotecas gráficas diferentes da Matplotlib ou para\n"
"desenvolver interfaces gráficas com o Spyder."
-#: spyder/plugins/ipythonconsole.py:365
+#: spyder/plugins/ipythonconsole.py:382
msgid "Inline"
msgstr "Em linha"
-#: spyder/plugins/ipythonconsole.py:366
+#: spyder/plugins/ipythonconsole.py:383
msgid "Automatic"
msgstr "Automático"
-#: spyder/plugins/ipythonconsole.py:367
+#: spyder/plugins/ipythonconsole.py:384
msgid "Graphics backend"
msgstr "Saída gráfica"
-#: spyder/plugins/ipythonconsole.py:368
+#: spyder/plugins/ipythonconsole.py:385
msgid ""
"Decide how graphics are going to be displayed in the console. If unsure, "
"please select %s to put graphics inside the console or %s to "
@@ -2469,60 +2508,79 @@ msgstr ""
"favor selecione %s para colocar os gráficos no console ou %s "
"para interagir com eles (através de zoom) em uma janela separada."
-#: spyder/plugins/ipythonconsole.py:388
+#: spyder/plugins/ipythonconsole.py:405
msgid "Backend:"
msgstr "Saída:"
-#: spyder/plugins/ipythonconsole.py:390
+#: spyder/plugins/ipythonconsole.py:407
msgid "This option will be applied the next time a console is opened."
msgstr "Esta opção será aplicada na próxima vez que um console for aberto."
-#: spyder/plugins/ipythonconsole.py:401
+#: spyder/plugins/ipythonconsole.py:418
msgid "Inline backend"
msgstr "Saída em linha"
-#: spyder/plugins/ipythonconsole.py:402
+#: spyder/plugins/ipythonconsole.py:419
msgid "Decide how to render the figures created by this backend"
msgstr ""
"Decida como renderizar as imagens criados por este tipo de saída gráfica"
-#: spyder/plugins/ipythonconsole.py:406
+#: spyder/plugins/ipythonconsole.py:423
msgid "Format:"
msgstr "Formato:"
-#: spyder/plugins/ipythonconsole.py:409
+#: spyder/plugins/ipythonconsole.py:427
msgid "Resolution:"
msgstr "Resolução:"
-#: spyder/plugins/ipythonconsole.py:409
+#: spyder/plugins/ipythonconsole.py:427
msgid "dpi"
msgstr "dpi"
-#: spyder/plugins/ipythonconsole.py:411
+#: spyder/plugins/ipythonconsole.py:429
msgid "Only used when the format is PNG. Default is 72"
msgstr "Só se usa quando o formato for PNG. O padrão é 72"
-#: spyder/plugins/ipythonconsole.py:414
+#: spyder/plugins/ipythonconsole.py:432
msgid "Width:"
msgstr "Largura:"
-#: spyder/plugins/ipythonconsole.py:414 spyder/plugins/ipythonconsole.py:418
+#: spyder/plugins/ipythonconsole.py:432 spyder/plugins/ipythonconsole.py:436
msgid "inches"
msgstr "polegadas"
-#: spyder/plugins/ipythonconsole.py:416
+#: spyder/plugins/ipythonconsole.py:434
msgid "Default is 6"
msgstr "O padrão é 6"
-#: spyder/plugins/ipythonconsole.py:418
+#: spyder/plugins/ipythonconsole.py:436
msgid "Height:"
msgstr "Altura:"
-#: spyder/plugins/ipythonconsole.py:420
+#: spyder/plugins/ipythonconsole.py:438
msgid "Default is 4"
msgstr "O padrão é 4"
-#: spyder/plugins/ipythonconsole.py:447
+#: spyder/plugins/ipythonconsole.py:440
+msgid "Use a tight layout for inline plots"
+msgstr "Usar um layout apertado para plots em linha"
+
+#: spyder/plugins/ipythonconsole.py:442
+#, fuzzy
+msgid ""
+"Sets bbox_inches to \"tight\" when\n"
+"plotting inline with matplotlib.\n"
+"When enabled, can cause discrepancies\n"
+"between the image displayed inline and\n"
+"that created using savefig."
+msgstr ""
+"Sets bbox_inches to \"tight\" when\n"
+"plotting inline with matplotlib.\n"
+"Quando ativado, pode causar discrepâncias\n"
+"entre a imagem exibida em linha e\n"
+"a criada usando savefig."
+
+#: spyder/plugins/ipythonconsole.py:475
msgid ""
"You can run several lines of code when a console is started. Please "
"introduce each one separated by commas, for example:
import os, import "
@@ -2532,15 +2590,15 @@ msgstr ""
"introduza cada uma separada por vírgulas, por exemplo:
import os, "
"import sys"
-#: spyder/plugins/ipythonconsole.py:453
+#: spyder/plugins/ipythonconsole.py:481
msgid "Lines:"
msgstr "Linhas:"
-#: spyder/plugins/ipythonconsole.py:462
+#: spyder/plugins/ipythonconsole.py:490
msgid "Run a file"
msgstr "Executar arquivo"
-#: spyder/plugins/ipythonconsole.py:463
+#: spyder/plugins/ipythonconsole.py:491
msgid ""
"You can also run a whole file at startup instead of just some lines (This is "
"similar to have a PYTHONSTARTUP file)."
@@ -2548,35 +2606,55 @@ msgstr ""
"Você também pode executar um arquivo por inteiro ao inicializar, em vez de "
"poucas linhas (Isso é similar a ter um arquivo PYTHONSTARTUP)."
-#: spyder/plugins/ipythonconsole.py:467
+#: spyder/plugins/ipythonconsole.py:495
msgid "Use the following file:"
msgstr "Use o seguinte arquivo:"
-#: spyder/plugins/ipythonconsole.py:481
+#: spyder/plugins/ipythonconsole.py:509
+msgid "Jedi completion"
+msgstr "Completador Jedi"
+
+#: spyder/plugins/ipythonconsole.py:510
+msgid ""
+"Enable Jedi-based Tab completion in the IPython console; similar to "
+"the greedy completer, but without evaluating the code.
Warning: "
+"Slows down your console when working with large dataframes!"
+msgstr ""
+"Habilitar a completação Jedi via Tab no console IPython."
+"
Aviso: Pode deixar seu console lento quando estiver trabalhando "
+"com grandes dataframes!"
+
+#: spyder/plugins/ipythonconsole.py:517
+msgid "Use Jedi completion in the IPython console"
+msgstr "Usar completação Jedi no console IPython"
+
+#: spyder/plugins/ipythonconsole.py:530
msgid "Greedy completion"
msgstr "Completação gulosa"
-#: spyder/plugins/ipythonconsole.py:482
+#: spyder/plugins/ipythonconsole.py:531
msgid ""
"Enable Tab completion on elements of lists, results of function "
-"calls, etc, without assigning them to a variable.
For example, you "
-"can get completions on things like li[0].<Tab> or ins."
-"meth().<Tab>"
+"calls, etc, without assigning them to a variable, like li[0].<"
+"Tab> or ins.meth().<Tab>
Warning: Due to a "
+"bug, IPython's greedy completer requires a leading <Space> "
+"for some completions; e.g. np.sin(<Space>np.<Tab> "
+"works while np.sin(np.<Tab> doesn't."
msgstr ""
"Habilita o completador usando a tecla Tab em elementos de listas, "
"resultados de chamadas de funções, etc, sem atribuí-los a uma "
"variável.
Dessa forma pode-se obter sugestões de completação em coisas "
-"como li[0].<Tab> ou ins.meth().<Tab>"
+"como li[0].<Tab> ou ins.meth().<Tab>."
-#: spyder/plugins/ipythonconsole.py:490
-msgid "Use the greedy completer"
-msgstr "Usar o completador guloso"
+#: spyder/plugins/ipythonconsole.py:543
+msgid "Use greedy completion in the IPython console"
+msgstr "Usar completação gulosa no console IPython"
-#: spyder/plugins/ipythonconsole.py:501
+#: spyder/plugins/ipythonconsole.py:555
msgid "Autocall"
msgstr "Autocall"
-#: spyder/plugins/ipythonconsole.py:502
+#: spyder/plugins/ipythonconsole.py:556
msgid ""
"Autocall makes IPython automatically call any callable object even if you "
"didn't type explicit parentheses.
For example, if you type str 43 "
@@ -2586,23 +2664,23 @@ msgstr ""
"se você não tenha digitado os parenteses ao seu redor.
Por exemplo, ao "
"escrever str 43, irá virar automaticamente str(43)."
-#: spyder/plugins/ipythonconsole.py:509
+#: spyder/plugins/ipythonconsole.py:563
msgid "Smart"
msgstr "Inteligente"
-#: spyder/plugins/ipythonconsole.py:510
+#: spyder/plugins/ipythonconsole.py:564
msgid "Full"
msgstr "Total"
-#: spyder/plugins/ipythonconsole.py:511
+#: spyder/plugins/ipythonconsole.py:565
msgid "Off"
msgstr "Desativado"
-#: spyder/plugins/ipythonconsole.py:513
+#: spyder/plugins/ipythonconsole.py:567
msgid "Autocall: "
msgstr "Autocall: "
-#: spyder/plugins/ipythonconsole.py:514
+#: spyder/plugins/ipythonconsole.py:568
msgid ""
"On %s mode, Autocall is not applied if there are no arguments after "
"the callable. On %s mode, all callable objects are automatically "
@@ -2612,11 +2690,11 @@ msgstr ""
"depois do objeto clamável. No modo %s, todos os objetos chamáveis são "
"chamados automaticamente (mesmo se não houver argumentos presentes)."
-#: spyder/plugins/ipythonconsole.py:526
+#: spyder/plugins/ipythonconsole.py:580
msgid "Symbolic Mathematics"
msgstr "Matemática simbólica"
-#: spyder/plugins/ipythonconsole.py:527
+#: spyder/plugins/ipythonconsole.py:581
msgid ""
"Perfom symbolic operations in the console (e.g. integrals, derivatives, "
"vector calculus, etc) and get the outputs in a beautifully printed style (it "
@@ -2626,55 +2704,55 @@ msgstr ""
"vetoria e etcl) tendo os resultados em um belo estilo impresso (requer o "
"módulo Sympy)."
-#: spyder/plugins/ipythonconsole.py:532
+#: spyder/plugins/ipythonconsole.py:586
msgid "Use symbolic math"
msgstr "Usar matemática simbólica"
-#: spyder/plugins/ipythonconsole.py:533
+#: spyder/plugins/ipythonconsole.py:587
msgid ""
"This option loads the Sympy library to work with.
Please refer to its "
"documentation to learn how to use it."
msgstr ""
"Esta opção carrega a biblioteca Sympy para trabalhar
com ela. Por favor "
-"leia sua documentação para aprender a usá-la. "
+"leia sua documentação para aprender a usá-la."
-#: spyder/plugins/ipythonconsole.py:543
+#: spyder/plugins/ipythonconsole.py:597
msgid "Prompts"
msgstr "Prompts"
-#: spyder/plugins/ipythonconsole.py:544
+#: spyder/plugins/ipythonconsole.py:598
msgid "Modify how Input and Output prompts are shown in the console."
msgstr "Modifique como são mostradas as saídas e entradas no console."
-#: spyder/plugins/ipythonconsole.py:547
+#: spyder/plugins/ipythonconsole.py:601
msgid "Input prompt:"
msgstr "Prompt de entrada:"
-#: spyder/plugins/ipythonconsole.py:549
+#: spyder/plugins/ipythonconsole.py:603
msgid ""
"Default is
In [<span class=\"in-prompt-number\">%i</span>]:"
msgstr ""
"O Padrão é
In [<span class=\"in-prompt-number\">%i</span>]:"
-#: spyder/plugins/ipythonconsole.py:553
+#: spyder/plugins/ipythonconsole.py:607
msgid "Output prompt:"
msgstr "Prompt de saída:"
-#: spyder/plugins/ipythonconsole.py:555
+#: spyder/plugins/ipythonconsole.py:609
msgid ""
"Default is
Out[<span class=\"out-prompt-number\">%i</span>]:"
msgstr ""
-"O Padrão é
Out[<span class=\"out-prompt-number\">%i</span>]: "
+"O Padrão é
Out[<span class=\"out-prompt-number\">%i</span>]:"
-#: spyder/plugins/ipythonconsole.py:575
+#: spyder/plugins/ipythonconsole.py:629
msgid "Graphics"
msgstr "Gráficos"
-#: spyder/plugins/ipythonconsole.py:577
+#: spyder/plugins/ipythonconsole.py:631
msgid "Startup"
msgstr "Inicialização"
-#: spyder/plugins/ipythonconsole.py:604
+#: spyder/plugins/ipythonconsole.py:658
msgid ""
"The directory {} is not writable and it is required to create IPython "
"consoles. Please make it writable."
@@ -2682,23 +2760,33 @@ msgstr ""
"O diretório {} não está em modo de escrita e isto é necessário para criar "
"consoles IPython. Por favor deixe-o em modo de escrita."
-#: spyder/plugins/ipythonconsole.py:784
+#: spyder/plugins/ipythonconsole.py:831
msgid "Open an &IPython console"
-msgstr "Abrir um console &IPython "
+msgstr "Abrir um console &IPython"
-#: spyder/plugins/ipythonconsole.py:791
+#: spyder/plugins/ipythonconsole.py:838
msgid "Restart kernel"
msgstr "Reiniciar kernel"
-#: spyder/plugins/ipythonconsole.py:800
+#: spyder/plugins/ipythonconsole.py:847
msgid "Open a new IPython console connected to an existing kernel"
-msgstr "Abrir um novo console do IPython conectado a um kernel existente."
+msgstr "Abrir um novo console do IPython conectado a um kernel existente"
-#: spyder/plugins/ipythonconsole.py:803
+#: spyder/plugins/ipythonconsole.py:850
msgid "Rename tab"
msgstr "Renomear aba"
-#: spyder/plugins/ipythonconsole.py:928
+#: spyder/plugins/ipythonconsole.py:968
+msgid ""
+"
Please exit from debugging before trying to run a file in this "
+"console.\n"
+"
"
+msgstr ""
+"
Por favor saia da depuração antes de executar um arquivo nesse "
+"console.\n"
+"
"
+
+#: spyder/plugins/ipythonconsole.py:988
msgid ""
"No IPython console is currently available to run %s.
Please "
"open a new one and try again."
@@ -2706,27 +2794,26 @@ msgstr ""
"Não existe um console IPython para ser executado %s.
Por favor "
"abra um novo e tente novamente."
-#: spyder/plugins/ipythonconsole.py:1023
+#: spyder/plugins/ipythonconsole.py:1096
+#, fuzzy
msgid ""
-"Your Python environment or installation doesn't have the ipykernel "
-"and cloudpickle modules installed on it. Without these modules is "
-"not possible for Spyder to create a console for you.
You can install "
-"them by running in a system terminal:
pip install ipykernel "
-"cloudpickle
or
conda install ipykernel cloudpickle"
-"tt>"
-msgstr ""
-"Sua instalação do Python não possui os módulos ipykernel e "
-"cloudpickle instalados. Sem esses módulos não é possível que o "
-"Spyder crie um console.
Você pode instalar eles executando no "
-"terminal do sistema tal comando:
pip install ipykernel "
-"cloudpickle
ou
conda install ipykernel cloudpickle"
-"tt>"
-
-#: spyder/plugins/ipythonconsole.py:1316
+"Your Python environment or installation doesn't have the spyder-kernels"
+"tt> module or the right version of it installed. Without this module is not "
+"possible for Spyder to create a console for you.
You can install it "
+"by running in a system terminal:
conda install spyder-kernels=0."
+"*
or
pip install spyder-kernels==0.*"
+msgstr ""
+"Sua instalação do Python não possui o módulo spyder-kernelsl "
+"instalado. Sem esse módulo não é possível que o Spyder crie um console para "
+"você.
Você pode instalar ele executando no terminal do sistema tal "
+"comando:
conda install spyder-kernels"
+"tt>
ou
pip install spyder-kernels"
+
+#: spyder/plugins/ipythonconsole.py:1362
msgid "Do you want to close this console?"
msgstr "Tem certeza que deseja fechar esse console?"
-#: spyder/plugins/ipythonconsole.py:1322
+#: spyder/plugins/ipythonconsole.py:1368
msgid ""
"Do you want to close all other consoles connected to the same kernel as this "
"one?"
@@ -2734,39 +2821,32 @@ msgstr ""
"Você deseja fechar todos os outros consoles conectados ao mesmo kernel como "
"esse?"
-#: spyder/plugins/ipythonconsole.py:1387
+#: spyder/plugins/ipythonconsole.py:1440
+#, fuzzy
msgid ""
"It was not possible to restart the IPython console when switching to this "
-"project. The error was {0}"
+"project. The error was
{0}"
msgstr ""
"Não foi possível reiniciar o console IPython enquanto trocava-se de projeto. "
"O erro foi {0}"
-#: spyder/plugins/ipythonconsole.py:1488
-msgid ""
-"This error was most probably caused by installing Spyder in a directory with "
-"non-ascii characters (i.e. characters with tildes, apostrophes or non-latin "
-"symbols).
To fix it, please reinstall Spyder in a different "
-"location."
-msgstr ""
-"Esse erro provavelmente foi causado pela instalação do Spyder em um "
-"diretório com caracteres não ASCII (p.ex. caracteres com acentos, apostrofes "
-"ou símbolos não Latin).
Para consertar isso por favor reinstale"
-"b> o Spyder em um diretório diferente."
+#: spyder/plugins/ipythonconsole.py:1546 spyder/plugins/ipythonconsole.py:1556
+msgid "The error is:
{}"
+msgstr "O erro é:
{}"
-#: spyder/plugins/ipythonconsole.py:1694
+#: spyder/plugins/ipythonconsole.py:1742
msgid "IPython"
msgstr "IPython"
-#: spyder/plugins/ipythonconsole.py:1695
+#: spyder/plugins/ipythonconsole.py:1743
msgid "Unable to connect to %s"
msgstr "Não foi possível conectar a %s"
-#: spyder/plugins/ipythonconsole.py:1765
+#: spyder/plugins/ipythonconsole.py:1819
msgid "Connection error"
msgstr "Erro de conexão"
-#: spyder/plugins/ipythonconsole.py:1766
+#: spyder/plugins/ipythonconsole.py:1820
msgid ""
"Could not open ssh tunnel. The error was:\n"
"\n"
@@ -2790,31 +2870,36 @@ msgstr "Deletar Layout"
msgid "Layout Display and Order"
msgstr "Ordem dos layouts"
-#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:66
+#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:71
msgid "Python interpreter"
msgstr "Interpretador Python"
-#: spyder/plugins/maininterpreter.py:68
+#: spyder/plugins/maininterpreter.py:73
msgid "Select the Python interpreter for all Spyder consoles"
msgstr "Selecione o interpretador Python para todos os consoles do Spyder"
-#: spyder/plugins/maininterpreter.py:71
+#: spyder/plugins/maininterpreter.py:76
msgid "Default (i.e. the same as Spyder's)"
msgstr "Padrão (o mesmo do Spyder)"
-#: spyder/plugins/maininterpreter.py:74
+#: spyder/plugins/maininterpreter.py:79
msgid "Use the following Python interpreter:"
msgstr "Usar o seguinte interpretador:"
-#: spyder/plugins/maininterpreter.py:77
+#: spyder/plugins/maininterpreter.py:82
msgid "Executables"
-msgstr "Executáveis "
+msgstr "Executáveis"
-#: spyder/plugins/maininterpreter.py:94
+#: spyder/plugins/maininterpreter.py:92
+#, fuzzy
+msgid "Recent custom interpreters"
+msgstr "Interpretador Python"
+
+#: spyder/plugins/maininterpreter.py:107
msgid "User Module Reloader (UMR)"
msgstr "Recarregador de Módulos do Usuário (RMU)"
-#: spyder/plugins/maininterpreter.py:95
+#: spyder/plugins/maininterpreter.py:108
msgid ""
"UMR forces Python to reload modules which were imported when executing a "
"file in a Python or IPython console with the runfile function."
@@ -2822,11 +2907,11 @@ msgstr ""
"O RMU força o Python a recarregar os módulos que foram importados durante a "
"execução de um arquivo no console com a função runfile."
-#: spyder/plugins/maininterpreter.py:100
+#: spyder/plugins/maininterpreter.py:113
msgid "Enable UMR"
msgstr "Ativar RMU"
-#: spyder/plugins/maininterpreter.py:101
+#: spyder/plugins/maininterpreter.py:114
msgid ""
"This option will enable the User Module Reloader (UMR) in Python/IPython "
"consoles. UMR forces Python to reload deeply modules during import when "
@@ -2850,20 +2935,20 @@ msgstr ""
"o atributo Qt.WA_DeleteOnClose em sua janela principal, utilizando o "
"método setAttribute)"
-#: spyder/plugins/maininterpreter.py:117
+#: spyder/plugins/maininterpreter.py:130
msgid "Show reloaded modules list"
msgstr "Mostrar lista de módulos que foram recarregados"
-#: spyder/plugins/maininterpreter.py:118
+#: spyder/plugins/maininterpreter.py:131
msgid "Please note that these changes will be applied only to new consoles"
msgstr ""
"Por favor tenha em nota que as mudanças só serão aplicadas em novos consoles"
-#: spyder/plugins/maininterpreter.py:122
+#: spyder/plugins/maininterpreter.py:135
msgid "Set UMR excluded (not reloaded) modules"
msgstr "Definir lista de módulos excluídos pelo RMU"
-#: spyder/plugins/maininterpreter.py:150
+#: spyder/plugins/maininterpreter.py:163
msgid ""
"You selected an invalid Python interpreter for the console so the previous "
"interpreter will stay. Please make sure to select a valid one."
@@ -2872,7 +2957,7 @@ msgstr ""
"interpretador anterior irá continuar. Por favor tenha certeza se você "
"selecionou um válido."
-#: spyder/plugins/maininterpreter.py:175
+#: spyder/plugins/maininterpreter.py:184
msgid ""
"You selected a Python %d interpreter for the console but Spyder is "
"running on Python %d!.
Although this is possible, we recommend "
@@ -2886,16 +2971,16 @@ msgstr ""
"interpretador selecionado, para evitar ver falsos erros e avisos no Editor "
"devido a sintaxe incompatível entre estas duas versões do Python."
-#: spyder/plugins/maininterpreter.py:186 spyder/plugins/maininterpreter.py:213
-#: spyder/plugins/maininterpreter.py:217
+#: spyder/plugins/maininterpreter.py:195 spyder/plugins/maininterpreter.py:222
+#: spyder/plugins/maininterpreter.py:226
msgid "UMR"
msgstr "RMU"
-#: spyder/plugins/maininterpreter.py:187
+#: spyder/plugins/maininterpreter.py:196
msgid "Set the list of excluded modules as this: numpy, scipy"
msgstr "Defina a lista de módulos excluídos desta forma: numpy, scipy"
-#: spyder/plugins/maininterpreter.py:204
+#: spyder/plugins/maininterpreter.py:213
msgid ""
"You are working with Python 2, this means that you can not import a module "
"that contains non-ascii characters."
@@ -2903,7 +2988,7 @@ msgstr ""
"Você está utilizando Python 2, não é possível importar um módulo que "
"contenha não contenha caracteres ascii."
-#: spyder/plugins/maininterpreter.py:214
+#: spyder/plugins/maininterpreter.py:223
msgid ""
"The following modules are not installed on your machine:\n"
"%s"
@@ -2911,7 +2996,7 @@ msgstr ""
"Os seguintes módulos não estão instalados no seu computador:\n"
"%s"
-#: spyder/plugins/maininterpreter.py:218
+#: spyder/plugins/maininterpreter.py:227
msgid ""
"Please note that these changes will be applied only to new Python/IPython "
"consoles"
@@ -2927,40 +3012,40 @@ msgstr "Ajuda online"
msgid "Outline"
msgstr "Explorador de código"
-#: spyder/plugins/projects.py:83 spyder/widgets/projects/explorer.py:112
+#: spyder/plugins/projects.py:77 spyder/widgets/projects/explorer.py:112
#: spyder/widgets/projects/explorer.py:126
msgid "Project explorer"
msgstr "Explorador de projetos"
-#: spyder/plugins/projects.py:95
+#: spyder/plugins/projects.py:89
msgid "New Project..."
msgstr "Novo Projeto..."
-#: spyder/plugins/projects.py:98
+#: spyder/plugins/projects.py:92
msgid "Open Project..."
msgstr "Abrir Projeto..."
-#: spyder/plugins/projects.py:101
+#: spyder/plugins/projects.py:95
msgid "Close Project"
msgstr "Fechar Projeto"
-#: spyder/plugins/projects.py:104
+#: spyder/plugins/projects.py:98
msgid "Delete Project"
msgstr "Deletar Projeto"
-#: spyder/plugins/projects.py:110
+#: spyder/plugins/projects.py:104
msgid "Project Preferences"
msgstr "Preferências do Projeto"
-#: spyder/plugins/projects.py:112
+#: spyder/plugins/projects.py:106
msgid "Recent Projects"
msgstr "Projetos Recentes"
-#: spyder/plugins/projects.py:249
+#: spyder/plugins/projects.py:264
msgid "Open project"
msgstr "Abrir projeto"
-#: spyder/plugins/projects.py:255
+#: spyder/plugins/projects.py:270
msgid "%s is not a Spyder project!"
msgstr "%s não é um projeto do Spyder!"
@@ -3010,7 +3095,7 @@ msgstr "Configurações gerais"
#: spyder/plugins/runconfig.py:194 spyder/plugins/runconfig.py:236
msgid "Command line options:"
-msgstr "Opções de linha de comando: "
+msgstr "Opções de linha de comando:"
#: spyder/plugins/runconfig.py:202 spyder/plugins/runconfig.py:514
msgid "Working Directory settings"
@@ -3026,7 +3111,7 @@ msgstr "A opção -u foi adicionada a essas opções"
#: spyder/plugins/runconfig.py:250
msgid "this dialog"
-msgstr "este dialogo "
+msgstr "este dialogo"
#: spyder/plugins/runconfig.py:315
msgid "Run configuration"
@@ -3130,7 +3215,7 @@ msgid "Context"
msgstr "Contexto"
#: spyder/plugins/shortcuts.py:587
-#: spyder/widgets/variableexplorer/collectionseditor.py:128
+#: spyder/widgets/variableexplorer/collectionseditor.py:153
msgid "Name"
msgstr "Nome"
@@ -3160,7 +3245,7 @@ msgstr "Procurar: "
#: spyder/plugins/shortcuts.py:847
msgid "Reset to default values"
-msgstr "Restaurar os valores padrões."
+msgstr "Restaurar os valores padrões"
#: spyder/plugins/shortcuts.py:877
msgid "Shortcuts reset"
@@ -3170,36 +3255,45 @@ msgstr "Resetar atalhos"
msgid "Do you want to reset to default values?"
msgstr "Você deseja restaurar os valores padrões?"
-#: spyder/plugins/variableexplorer.py:25
+#: spyder/plugins/variableexplorer.py:24
+msgid "View and edit DataFrames and Series in the Variable Explorer"
+msgstr "Ver e editar DataFrames e Series no Explorador de Variáveis"
+
+#: spyder/plugins/variableexplorer.py:29
+msgid "View and edit two and three dimensional arrays in the Variable Explorer"
+msgstr ""
+"Ver e editar duas e três matrizes dimensionais no Explorador de Variáveis"
+
+#: spyder/plugins/variableexplorer.py:37
msgid "Filter"
msgstr "Filtro"
-#: spyder/plugins/variableexplorer.py:27
-#: spyder/widgets/variableexplorer/namespacebrowser.py:200
+#: spyder/plugins/variableexplorer.py:39
+#: spyder/widgets/variableexplorer/namespacebrowser.py:203
msgid "Exclude private references"
msgstr "Excluir variáveis privadas"
-#: spyder/plugins/variableexplorer.py:28
-#: spyder/widgets/variableexplorer/namespacebrowser.py:215
+#: spyder/plugins/variableexplorer.py:40
+#: spyder/widgets/variableexplorer/namespacebrowser.py:218
msgid "Exclude capitalized references"
msgstr "Excluir variáveis que começam em maiúsculas"
-#: spyder/plugins/variableexplorer.py:29
-#: spyder/widgets/variableexplorer/namespacebrowser.py:208
+#: spyder/plugins/variableexplorer.py:41
+#: spyder/widgets/variableexplorer/namespacebrowser.py:211
msgid "Exclude all-uppercase references"
-msgstr "Excluir variáveis em maiúscula "
+msgstr "Excluir variáveis em maiúscula"
-#: spyder/plugins/variableexplorer.py:30
-#: spyder/widgets/variableexplorer/namespacebrowser.py:223
+#: spyder/plugins/variableexplorer.py:42
+#: spyder/widgets/variableexplorer/namespacebrowser.py:226
msgid "Exclude unsupported data types"
msgstr "Excluir tipos de dados não suportados"
-#: spyder/plugins/variableexplorer.py:36
-#: spyder/widgets/variableexplorer/collectionseditor.py:702
+#: spyder/plugins/variableexplorer.py:48
+#: spyder/widgets/variableexplorer/collectionseditor.py:738
msgid "Show arrays min/max"
msgstr "Mostrar o minimo e máximo de matrizes"
-#: spyder/plugins/variableexplorer.py:178
+#: spyder/plugins/variableexplorer.py:202
msgid "Variable explorer"
msgstr "Explorador de variáveis"
@@ -3229,7 +3323,7 @@ msgstr ""
#: spyder/plugins/workingdirectory.py:62
msgid "the following directory:"
-msgstr "O seguinte diretório:"
+msgstr "o seguinte diretório:"
#: spyder/plugins/workingdirectory.py:64
msgid "The directory when a new console is open will be the specified path"
@@ -3240,12 +3334,12 @@ msgstr ""
msgid "Back"
msgstr "Anterior"
-#: spyder/plugins/workingdirectory.py:132 spyder/widgets/explorer.py:1194
+#: spyder/plugins/workingdirectory.py:130 spyder/widgets/explorer.py:1199
#: spyder/widgets/variableexplorer/importwizard.py:539
msgid "Next"
msgstr "Próximo"
-#: spyder/plugins/workingdirectory.py:143
+#: spyder/plugins/workingdirectory.py:141
msgid ""
"This is the working directory for newly\n"
"opened consoles (Python/IPython consoles and\n"
@@ -3260,31 +3354,37 @@ msgstr ""
"Buscar em arquivos e para os novos\n"
"arquivos criados no Editor"
-#: spyder/plugins/workingdirectory.py:168
+#: spyder/plugins/workingdirectory.py:166
msgid "Browse a working directory"
msgstr "Selecionar um diretório de trabalho"
-#: spyder/plugins/workingdirectory.py:175
+#: spyder/plugins/workingdirectory.py:173
msgid "Change to parent directory"
msgstr "Mudar para diretório superior"
-#: spyder/plugins/workingdirectory.py:182 spyder/widgets/findinfiles.py:225
+#: spyder/plugins/workingdirectory.py:180 spyder/widgets/findinfiles.py:240
msgid "Current working directory"
msgstr "Diretório de trabalho atual"
-#: spyder/utils/codeanalysis.py:92
+#: spyder/utils/codeanalysis.py:94
msgid "Real-time code analysis on the Editor"
msgstr "Análise de código em tempo real no editor"
-#: spyder/utils/codeanalysis.py:96
+#: spyder/utils/codeanalysis.py:98
msgid "Real-time code style analysis on the Editor"
-msgstr "Análise de estilo em tempo real no editor."
+msgstr "Análise de estilo em tempo real no editor"
-#: spyder/utils/environ.py:46
+#: spyder/utils/environ.py:48
msgid "Environment variables"
msgstr "Variáveis de ambiente"
-#: spyder/utils/environ.py:96
+#: spyder/utils/environ.py:57
+msgid ""
+"An error occurred while trying to show your environment variables. The error "
+"was
{0}"
+msgstr ""
+
+#: spyder/utils/environ.py:108
msgid ""
"Module pywin32 was not found.
Please restart this Windows "
"session (not the computer) for changes to take effect."
@@ -3293,7 +3393,7 @@ msgstr ""
"sessão do Windows (não do computador) para que as mudanças tenham "
"efeito."
-#: spyder/utils/environ.py:109
+#: spyder/utils/environ.py:121
msgid ""
"If you accept changes, this will modify the current user environment "
"variables directly in Windows registry. Use it with precautions, at "
@@ -3310,7 +3410,7 @@ msgstr ""
"você executou ele de um atalho, caso contrário reinicie qualquer aplicativo "
"pelo qual você você executou ele, como o Python(x,y) Home)"
-#: spyder/utils/help/sphinxify.py:217 spyder/utils/help/sphinxify.py:227
+#: spyder/utils/help/sphinxify.py:216 spyder/utils/help/sphinxify.py:226
msgid ""
"It was not possible to generate rich text help for this object.Please "
"see it in plain text."
@@ -3323,133 +3423,76 @@ msgstr ""
msgid "Editor's code completion, go-to-definition and help"
msgstr "Completador de código e ajuda no Editor"
-#: spyder/utils/iofuncs.py:408
-msgid "Supported files"
-msgstr "Arquivos suportados"
-
-#: spyder/utils/iofuncs.py:410
-msgid "All files (*.*)"
-msgstr "Todos os arquivos (*.*)"
-
-#: spyder/utils/iofuncs.py:420
-msgid "Spyder data files"
-msgstr "Arquivos data do Spyder"
-
-#: spyder/utils/iofuncs.py:422
-#: spyder/widgets/variableexplorer/collectionseditor.py:1061
-msgid "NumPy arrays"
-msgstr "Matrizes do NumPy"
-
-#: spyder/utils/iofuncs.py:423
-msgid "NumPy zip arrays"
-msgstr "Matrizes comprimidas do NumPy"
-
-#: spyder/utils/iofuncs.py:424
-msgid "Matlab files"
-msgstr "Arquivos do Matlab"
-
-#: spyder/utils/iofuncs.py:425
-msgid "CSV text files"
-msgstr "Arquivos de texto CSV"
-
-#: spyder/utils/iofuncs.py:427
-msgid "JPEG images"
-msgstr "Imagens JPEG"
-
-#: spyder/utils/iofuncs.py:428
-msgid "PNG images"
-msgstr "Imagens PNG"
-
-#: spyder/utils/iofuncs.py:429
-msgid "GIF images"
-msgstr "Imagens GIF"
-
-#: spyder/utils/iofuncs.py:430
-msgid "TIFF images"
-msgstr "Imagens TIFF"
-
-#: spyder/utils/iofuncs.py:431 spyder/utils/iofuncs.py:432
-msgid "Pickle files"
-msgstr "Arquivos Pickle"
-
-#: spyder/utils/iofuncs.py:433
-msgid "JSON files"
-msgstr "Arquivos JSON"
-
-#: spyder/utils/iofuncs.py:452 spyder/utils/iofuncs.py:459
-msgid "Unsupported file type '%s'"
-msgstr "Tipo de arquivo não suportado '%s'"
-
-#: spyder/utils/programs.py:287
+#: spyder/utils/programs.py:308
msgid "It was not possible to run this file in an external terminal"
msgstr "Não foi possível executar este arquivo em um terminal externo"
-#: spyder/utils/syntaxhighlighters.py:34
+#: spyder/utils/syntaxhighlighters.py:35
msgid "Syntax highlighting for Matlab, Julia and other file types"
msgstr "Sintaxe colorida para arquivos do tipo Matlab, Julia e outros tipos"
-#: spyder/utils/syntaxhighlighters.py:43
+#: spyder/utils/syntaxhighlighters.py:44
msgid "Background:"
msgstr "Fundo:"
-#: spyder/utils/syntaxhighlighters.py:44
+#: spyder/utils/syntaxhighlighters.py:45
#: spyder/widgets/sourcecode/codeeditor.py:107
msgid "Current line:"
msgstr "Linha atual:"
-#: spyder/utils/syntaxhighlighters.py:45
+#: spyder/utils/syntaxhighlighters.py:46
msgid "Current cell:"
msgstr "Célula selecionada:"
-#: spyder/utils/syntaxhighlighters.py:46
+#: spyder/utils/syntaxhighlighters.py:47
msgid "Occurrence:"
msgstr "Ocorrência:"
-#: spyder/utils/syntaxhighlighters.py:47
+#: spyder/utils/syntaxhighlighters.py:48
msgid "Link:"
msgstr "Link:"
-#: spyder/utils/syntaxhighlighters.py:48
+#: spyder/utils/syntaxhighlighters.py:49
msgid "Side areas:"
msgstr "Áreas laterais:"
-#: spyder/utils/syntaxhighlighters.py:49
+#: spyder/utils/syntaxhighlighters.py:50
msgid "Matched
parens:"
msgstr "Parênteses fechados:"
-#: spyder/utils/syntaxhighlighters.py:50
+#: spyder/utils/syntaxhighlighters.py:51
msgid "Unmatched
parens:"
msgstr "Parênteses abertos:"
-#: spyder/utils/syntaxhighlighters.py:51
+#: spyder/utils/syntaxhighlighters.py:52
msgid "Normal text:"
msgstr "Texto normal:"
-#: spyder/utils/syntaxhighlighters.py:52
+#: spyder/utils/syntaxhighlighters.py:53
msgid "Keyword:"
msgstr "Palavra chave:"
-#: spyder/utils/syntaxhighlighters.py:53
+#: spyder/utils/syntaxhighlighters.py:54
msgid "Builtin:"
msgstr "Objeto integrado:"
-#: spyder/utils/syntaxhighlighters.py:54
+#: spyder/utils/syntaxhighlighters.py:55
msgid "Definition:"
msgstr "Definição:"
-#: spyder/utils/syntaxhighlighters.py:55
+#: spyder/utils/syntaxhighlighters.py:56
msgid "Comment:"
msgstr "Comentário:"
-#: spyder/utils/syntaxhighlighters.py:56
+#: spyder/utils/syntaxhighlighters.py:57
msgid "String:"
msgstr "String:"
-#: spyder/utils/syntaxhighlighters.py:57
+#: spyder/utils/syntaxhighlighters.py:58
msgid "Number:"
msgstr "Número:"
-#: spyder/utils/syntaxhighlighters.py:58
+#: spyder/utils/syntaxhighlighters.py:59
msgid "Instance:"
msgstr "Instância:"
@@ -3506,53 +3549,53 @@ msgstr ""
msgid "Array dimensions not valid"
msgstr "Dimensões da matriz não é válida"
-#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2731
+#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2738
msgid "Zoom out"
msgstr "Menos zoom"
-#: spyder/widgets/browser.py:61 spyder/widgets/sourcecode/codeeditor.py:2727
+#: spyder/widgets/browser.py:61 spyder/widgets/sourcecode/codeeditor.py:2734
msgid "Zoom in"
msgstr "Mais zoom"
-#: spyder/widgets/browser.py:213
+#: spyder/widgets/browser.py:216
msgid "Home"
msgstr "Página inicial"
-#: spyder/widgets/browser.py:249
+#: spyder/widgets/browser.py:252
msgid "Find text"
msgstr "Procurar texto"
-#: spyder/widgets/browser.py:266
+#: spyder/widgets/browser.py:269
msgid "Address:"
msgstr "Endereço:"
-#: spyder/widgets/browser.py:302
+#: spyder/widgets/browser.py:305
msgid "Unable to load page"
msgstr "Não foi possível carregar a página"
-#: spyder/widgets/comboboxes.py:164
+#: spyder/widgets/comboboxes.py:165
msgid "Press enter to validate this entry"
msgstr "Aperte enter para validar esta entrada"
-#: spyder/widgets/comboboxes.py:165
+#: spyder/widgets/comboboxes.py:166
msgid "This entry is incorrect"
msgstr "Esta entrada é incorreta"
-#: spyder/widgets/comboboxes.py:208
+#: spyder/widgets/comboboxes.py:209
msgid "Press enter to validate this path"
msgstr "Aperte enter para validar esse caminho"
#: spyder/widgets/dependencies.py:63
msgid " Required "
-msgstr "Requerido"
+msgstr " Requerido "
#: spyder/widgets/dependencies.py:63
msgid "Module"
-msgstr "Módulo "
+msgstr "Módulo"
#: spyder/widgets/dependencies.py:64
msgid " Installed "
-msgstr "Instalado"
+msgstr " Instalado "
#: spyder/widgets/dependencies.py:64
msgid "Provided features"
@@ -3575,83 +3618,84 @@ msgstr ""
"funcionalidades corretamente em todos os painéis. A tabela abaixo mostra as "
"versões requeridas e instaladas (se houver) de todos eles.
Nota"
"b>: Você pode usar o Spyder normalmente sem os seguintes módulos instalados: "
-"%se %s"
+"%se %s."
#: spyder/widgets/dependencies.py:157
msgid "Copy to clipboard"
-msgstr "Copiar para área transferência "
+msgstr "Copiar para área transferência"
-#: spyder/widgets/editor.py:501
+#: spyder/widgets/editor.py:511
msgid "Find symbols in file..."
msgstr "Procurar símbolos no arquivo..."
-#: spyder/widgets/editor.py:504
+#: spyder/widgets/editor.py:514
msgid "Copy path to clipboard"
msgstr "Copiar caminho para área de transferência"
-#: spyder/widgets/editor.py:508
+#: spyder/widgets/editor.py:518
msgid "Close all to the right"
msgstr "Fechar todos à direita"
-#: spyder/widgets/editor.py:510
+#: spyder/widgets/editor.py:520
msgid "Close all but this"
msgstr "Fechar todos, menos este"
-#: spyder/widgets/editor.py:514 spyder/widgets/explorer.py:370
+#: spyder/widgets/editor.py:524 spyder/widgets/explorer.py:373
msgid "Show in Finder"
msgstr "Mostrar no Buscador"
-#: spyder/widgets/editor.py:516 spyder/widgets/explorer.py:372
+#: spyder/widgets/editor.py:526 spyder/widgets/explorer.py:375
msgid "Show in external file explorer"
msgstr "Mostrar no explorador de arquivos do sistema"
-#: spyder/widgets/editor.py:1193
+#: spyder/widgets/editor.py:1201
msgid "Temporary file"
-msgstr "Arquivo temporário "
+msgstr "Arquivo temporário"
-#: spyder/widgets/editor.py:1279
+#: spyder/widgets/editor.py:1287
msgid "New window"
msgstr "Nova janela"
-#: spyder/widgets/editor.py:1280
+#: spyder/widgets/editor.py:1288
msgid "Create a new editor window"
msgstr "Criar uma nova janela de edição"
-#: spyder/widgets/editor.py:1283
+#: spyder/widgets/editor.py:1291
msgid "Split vertically"
msgstr "Dividir verticalmente"
-#: spyder/widgets/editor.py:1285
+#: spyder/widgets/editor.py:1293
msgid "Split vertically this editor window"
msgstr "Dividir verticalmente esta janela de edição"
-#: spyder/widgets/editor.py:1287
+#: spyder/widgets/editor.py:1295
msgid "Split horizontally"
msgstr "Dividir horizontalmente"
-#: spyder/widgets/editor.py:1289
+#: spyder/widgets/editor.py:1297
msgid "Split horizontally this editor window"
msgstr "Dividir horizontalmente esta janela de edição"
-#: spyder/widgets/editor.py:1291
+#: spyder/widgets/editor.py:1299
msgid "Close this panel"
msgstr "Fechar este painel"
-#: spyder/widgets/editor.py:1531
+#: spyder/widgets/editor.py:1534
msgid "%s has been modified.
Do you want to save changes?"
msgstr "%s foi modificado.
Deseja salvar as mudanças?"
-#: spyder/widgets/editor.py:1617 spyder/widgets/editor.py:1780
-msgid "Save"
-msgstr "Salvar"
+#: spyder/widgets/editor.py:1620 spyder/widgets/editor.py:1783
+#: spyder/widgets/explorer.py:82
+msgid "Save Error"
+msgstr "Erro de Gravação"
-#: spyder/widgets/editor.py:1618 spyder/widgets/editor.py:1781
-#: spyder/widgets/shell.py:267
+#: spyder/widgets/editor.py:1621 spyder/widgets/editor.py:1784
+#: spyder/widgets/explorer.py:83
msgid "Unable to save file '%s'
Error message:
%s"
msgstr ""
"Não foi possível salvar arquivo '%s'
Mensagem de erro:
%s"
-#: spyder/widgets/editor.py:1968
+#: spyder/widgets/editor.py:1971
msgid ""
"%s is unavailable (this file may have been removed, moved or renamed "
"outside Spyder).
Do you want to close it?"
@@ -3659,7 +3703,7 @@ msgstr ""
"%s está indisponível (o arquivo pode ter sido removido, movido ou "
"renomeado fora do Spyder).
Deseja fechar?"
-#: spyder/widgets/editor.py:1991
+#: spyder/widgets/editor.py:1994
msgid ""
"%s has been modified outside Spyder.
Do you want to reload it and "
"lose all your changes?"
@@ -3667,7 +3711,7 @@ msgstr ""
"%s foi modificado fora do Spyder.
Você deseja recarregar ele e "
"perder todas as modificações?"
-#: spyder/widgets/editor.py:2101
+#: spyder/widgets/editor.py:2104
msgid ""
"All changes to %s will be lost.
Do you want to revert file from "
"disk?"
@@ -3675,11 +3719,11 @@ msgstr ""
"Todas as modificações do %s foram perdidas.
Você deseja reverter o "
"arquivo do disco?"
-#: spyder/widgets/editor.py:2245
+#: spyder/widgets/editor.py:2250
msgid "Loading %s..."
msgstr "Carregando %s..."
-#: spyder/widgets/editor.py:2257
+#: spyder/widgets/editor.py:2262
msgid ""
"%s contains mixed end-of-line characters.
Spyder will fix this "
"automatically."
@@ -3687,11 +3731,11 @@ msgstr ""
"%s contém vários tipos de caracteres de fim de linha.
O Spyder irá "
"corrigir automaticamente."
-#: spyder/widgets/editor.py:2664
+#: spyder/widgets/editor.py:2672
msgid "Close window"
msgstr "Fechar janela"
-#: spyder/widgets/editor.py:2666
+#: spyder/widgets/editor.py:2674
msgid "Close this window"
msgstr "Fechar esta janela"
@@ -3717,13 +3761,13 @@ msgstr "A célula inicia na linha %s"
#: spyder/widgets/editortools.py:201 spyder/widgets/editortools.py:527
msgid "Go to cursor position"
-msgstr "Ir para a posição do cursor "
+msgstr "Ir para a posição do cursor"
#: spyder/widgets/editortools.py:204
msgid "Show absolute path"
msgstr "Mostrar o caminho completo"
-#: spyder/widgets/editortools.py:207 spyder/widgets/explorer.py:283
+#: spyder/widgets/editortools.py:207 spyder/widgets/explorer.py:286
msgid "Show all files"
msgstr "Mostrar todos os arquivos"
@@ -3735,109 +3779,109 @@ msgstr "Mostrar comentários especiais"
msgid "Show/hide outline explorer"
msgstr "Mostrar/esconder o explorador de código"
-#: spyder/widgets/explorer.py:279
+#: spyder/widgets/explorer.py:282
msgid "Edit filename filters..."
msgstr "Editar filtros para nomes de arquivos..."
-#: spyder/widgets/explorer.py:293
+#: spyder/widgets/explorer.py:296
msgid "Edit filename filters"
msgstr "Editar filtros para nomes de arquivos"
-#: spyder/widgets/explorer.py:294
+#: spyder/widgets/explorer.py:297
msgid "Name filters:"
msgstr "Nome dos filtros:"
-#: spyder/widgets/explorer.py:313
+#: spyder/widgets/explorer.py:316
msgid "File..."
msgstr "Arquivo..."
-#: spyder/widgets/explorer.py:317
+#: spyder/widgets/explorer.py:320
msgid "Module..."
msgstr "Módulo..."
-#: spyder/widgets/explorer.py:321
+#: spyder/widgets/explorer.py:324
msgid "Folder..."
msgstr "Pasta..."
-#: spyder/widgets/explorer.py:325
+#: spyder/widgets/explorer.py:328
msgid "Package..."
msgstr "Pacote..."
-#: spyder/widgets/explorer.py:346
-#: spyder/widgets/variableexplorer/collectionseditor.py:677
+#: spyder/widgets/explorer.py:349
+#: spyder/widgets/variableexplorer/collectionseditor.py:713
msgid "Edit"
msgstr "Editar"
-#: spyder/widgets/explorer.py:348
+#: spyder/widgets/explorer.py:351
msgid "Move..."
msgstr "Mover..."
-#: spyder/widgets/explorer.py:351
+#: spyder/widgets/explorer.py:354
msgid "Delete..."
msgstr "Deletar..."
-#: spyder/widgets/explorer.py:354
+#: spyder/widgets/explorer.py:357
msgid "Rename..."
msgstr "Renomear..."
-#: spyder/widgets/explorer.py:357
+#: spyder/widgets/explorer.py:360
msgid "Open"
msgstr "Abrir"
-#: spyder/widgets/explorer.py:358 spyder/widgets/sourcecode/codeeditor.py:2699
+#: spyder/widgets/explorer.py:361 spyder/widgets/sourcecode/codeeditor.py:2706
msgid "Convert to Python script"
msgstr "Converter para um script Python"
-#: spyder/widgets/explorer.py:399
+#: spyder/widgets/explorer.py:393
msgid "Commit"
msgstr "Enviar"
-#: spyder/widgets/explorer.py:402
+#: spyder/widgets/explorer.py:396
msgid "Browse repository"
-msgstr "Explorar repositório "
+msgstr "Explorar repositório"
-#: spyder/widgets/explorer.py:413
+#: spyder/widgets/explorer.py:407
msgid "Open command prompt here"
msgstr "Abrir prompt de comando aqui"
-#: spyder/widgets/explorer.py:415
+#: spyder/widgets/explorer.py:409
msgid "Open terminal here"
msgstr "Abrir terminal aqui"
-#: spyder/widgets/explorer.py:416
+#: spyder/widgets/explorer.py:410
msgid "Open IPython console here"
msgstr "Abrir console IPython aqui"
-#: spyder/widgets/explorer.py:430
+#: spyder/widgets/explorer.py:424
msgid "New"
msgstr "Novo"
-#: spyder/widgets/explorer.py:438
+#: spyder/widgets/explorer.py:432
msgid "Import"
msgstr "Importar"
-#: spyder/widgets/explorer.py:584
+#: spyder/widgets/explorer.py:583
msgid "Do you really want to delete %s?"
msgstr "Deseja mesmo deletar %s?"
-#: spyder/widgets/explorer.py:602
+#: spyder/widgets/explorer.py:601
msgid "delete"
msgstr "deletar"
-#: spyder/widgets/explorer.py:603 spyder/widgets/projects/explorer.py:148
+#: spyder/widgets/explorer.py:602 spyder/widgets/projects/explorer.py:148
#: spyder/widgets/projects/explorer.py:256
msgid "Project Explorer"
msgstr "Explorador de projetos"
-#: spyder/widgets/explorer.py:604 spyder/widgets/projects/explorer.py:149
+#: spyder/widgets/explorer.py:603 spyder/widgets/projects/explorer.py:149
msgid "Unable to %s %s
Error message:
%s"
msgstr "Não foi possível %s %s
Mensagem de erro:
%s"
-#: spyder/widgets/explorer.py:619
+#: spyder/widgets/explorer.py:618
msgid "File Explorer"
msgstr "Explorador de arquivos"
-#: spyder/widgets/explorer.py:620
+#: spyder/widgets/explorer.py:619
msgid ""
"The current directory contains a project.
If you want to delete the "
"project, please go to Projects » Delete Project"
@@ -3845,11 +3889,11 @@ msgstr ""
"O diretório atual contém um projeto.
Se você deseja mesmo deletar o "
"projeto, por favor vá em Projetos » Deletar Projeto"
-#: spyder/widgets/explorer.py:637 spyder/widgets/sourcecode/codeeditor.py:2160
+#: spyder/widgets/explorer.py:636 spyder/widgets/sourcecode/codeeditor.py:2167
msgid "Conversion error"
msgstr "Erro de conversão"
-#: spyder/widgets/explorer.py:638 spyder/widgets/sourcecode/codeeditor.py:2161
+#: spyder/widgets/explorer.py:637 spyder/widgets/sourcecode/codeeditor.py:2168
msgid ""
"It was not possible to convert this notebook. The error is:\n"
"\n"
@@ -3857,99 +3901,101 @@ msgstr ""
"Não foi possível converter esse notebook. O erro é:\n"
"\n"
-#: spyder/widgets/explorer.py:655 spyder/widgets/explorer.py:663
-#: spyder/widgets/explorer.py:674
-#: spyder/widgets/variableexplorer/collectionseditor.py:706
-#: spyder/widgets/variableexplorer/collectionseditor.py:952
+#: spyder/widgets/explorer.py:654 spyder/widgets/explorer.py:662
+#: spyder/widgets/explorer.py:676
+#: spyder/widgets/variableexplorer/collectionseditor.py:742
+#: spyder/widgets/variableexplorer/collectionseditor.py:988
msgid "Rename"
msgstr "Renomear"
-#: spyder/widgets/explorer.py:656
+#: spyder/widgets/explorer.py:655
msgid "New name:"
msgstr "Novo nome:"
-#: spyder/widgets/explorer.py:664
+#: spyder/widgets/explorer.py:663
msgid ""
"Do you really want to rename %s and overwrite the existing file "
"%s?"
msgstr ""
"Você deseja mesmo renomear %s e sobrescrever o arquivo já existente "
-"%s? "
+"%s?"
-#: spyder/widgets/explorer.py:675
+#: spyder/widgets/explorer.py:677
msgid "Unable to rename file %s
Error message:
%s"
msgstr ""
"Não foi possível renomear arquivo %s
Mensagem de erro:"
"
%s"
-#: spyder/widgets/explorer.py:722
+#: spyder/widgets/explorer.py:724
msgid "Unable to move %s
Error message:
%s"
msgstr "Não foi possível mover %s
Mensagem de erro:
%s"
-#: spyder/widgets/explorer.py:740
+#: spyder/widgets/explorer.py:742
msgid "Unable to create folder %s
Error message:
%s"
msgstr ""
"Não foi possível criar pasta %s
Mensagem de erro:
%s"
-#: spyder/widgets/explorer.py:753 spyder/widgets/explorer.py:787
+#: spyder/widgets/explorer.py:755 spyder/widgets/explorer.py:789
msgid "Unable to create file %s
Error message:
%s"
msgstr ""
"Não foi possível criar arquivo %s
Mensagem de erro:
"
"%s"
-#: spyder/widgets/explorer.py:761
+#: spyder/widgets/explorer.py:763
msgid "New folder"
msgstr "Nova pasta"
-#: spyder/widgets/explorer.py:762
+#: spyder/widgets/explorer.py:764
msgid "Folder name:"
msgstr "Nome da pasta:"
-#: spyder/widgets/explorer.py:767
+#: spyder/widgets/explorer.py:769
msgid "New package"
msgstr "Novo pacote"
-#: spyder/widgets/explorer.py:768
+#: spyder/widgets/explorer.py:770
msgid "Package name:"
msgstr "Nome do pacote:"
-#: spyder/widgets/explorer.py:808
+#: spyder/widgets/explorer.py:810
msgid "New module"
-msgstr "Novo módulo "
+msgstr "Novo módulo"
-#: spyder/widgets/explorer.py:823
+#: spyder/widgets/explorer.py:825
msgid ""
"For %s support, please install one of the
following tools:
%s"
msgstr ""
"Para ter suporte ao %s, por favor instale as
seguintes ferramentas:
%s"
-#: spyder/widgets/explorer.py:827
+#: spyder/widgets/explorer.py:829
msgid "Unable to find external program.
%s"
msgstr "Não foi possível encontrar o programa externo.
%s"
-#: spyder/widgets/explorer.py:1048
+#: spyder/widgets/explorer.py:1049
msgid "Show current directory only"
msgstr "Mostrar somente o diretório atual"
-#: spyder/widgets/explorer.py:1158
+#: spyder/widgets/explorer.py:1163
msgid "You don't have the right permissions to open this directory"
msgstr "Você não tem permissão para abrir esse diretório"
-#: spyder/widgets/explorer.py:1189
+#: spyder/widgets/explorer.py:1194
msgid "Show icons and text"
msgstr "Mostrar ícones e texto"
-#: spyder/widgets/explorer.py:1191
+#: spyder/widgets/explorer.py:1196
#: spyder/widgets/variableexplorer/importwizard.py:535
msgid "Previous"
msgstr "Anterior"
-#: spyder/widgets/explorer.py:1197
+#: spyder/widgets/explorer.py:1202
msgid "Parent"
msgstr "Superior"
#: spyder/widgets/fileswitcher.py:110
+#: spyder/plugins/pylint/widgets/pylintgui.py:364
+#: spyder/plugins/profiler/widgets/profilergui.py:296
msgid "unsaved file"
msgstr "arquivo não salvo"
@@ -3971,27 +4017,27 @@ msgstr ""
msgid "lines"
msgstr "linhas"
-#: spyder/widgets/findinfiles.py:124
+#: spyder/widgets/findinfiles.py:121
msgid "Unexpected error: see internal console"
msgstr "Erro inesperado: veja o console interno"
-#: spyder/widgets/findinfiles.py:152
+#: spyder/widgets/findinfiles.py:158
msgid "invalid regular expression"
msgstr "expressão regular inválida"
-#: spyder/widgets/findinfiles.py:202
+#: spyder/widgets/findinfiles.py:217
msgid "permission denied errors were encountered"
msgstr "permissão negada, foram encontrados erros"
-#: spyder/widgets/findinfiles.py:217
+#: spyder/widgets/findinfiles.py:232
msgid "Search directory"
msgstr "Procurar diretório"
-#: spyder/widgets/findinfiles.py:230
+#: spyder/widgets/findinfiles.py:245
msgid "Project"
msgstr "Projeto"
-#: spyder/widgets/findinfiles.py:231
+#: spyder/widgets/findinfiles.py:246
msgid ""
"Search in all files and directories present on the current project path (if "
"opened)"
@@ -3999,251 +4045,387 @@ msgstr ""
"Procurar em todos os arquivos e diretórios presentes no caminho atual do "
"projeto (se aberto)"
-#: spyder/widgets/findinfiles.py:236
+#: spyder/widgets/findinfiles.py:251
msgid "File"
msgstr "Arquivo"
-#: spyder/widgets/findinfiles.py:237
+#: spyder/widgets/findinfiles.py:252
msgid "Search in current opened file"
msgstr "Procurar no arquivo aberto"
-#: spyder/widgets/findinfiles.py:242
+#: spyder/widgets/findinfiles.py:257
msgid "Select other directory"
msgstr "Selecionar outro diretório"
-#: spyder/widgets/findinfiles.py:243
+#: spyder/widgets/findinfiles.py:258
msgid "Search in other folder present on the file system"
msgstr "Procurar em outro diretório do sistema de arquivos"
-#: spyder/widgets/findinfiles.py:247
+#: spyder/widgets/findinfiles.py:262
msgid "Clear the list of other directories"
msgstr "Limpar a lista de outros diretórios"
-#: spyder/widgets/findinfiles.py:318
+#: spyder/widgets/findinfiles.py:333
msgid "Clear other directories"
msgstr "Limpar outros diretórios"
-#: spyder/widgets/findinfiles.py:319
+#: spyder/widgets/findinfiles.py:334
msgid "Do you want to clear the list of other directories?"
msgstr "Você tem certeza que deseja limpar a lista de outros diretórios?"
-#: spyder/widgets/findinfiles.py:415
+#: spyder/widgets/findinfiles.py:404 spyder/widgets/findreplace.py:52
+msgid "Regular expression error"
+msgstr "Erro na expressão regular"
+
+#: spyder/widgets/findinfiles.py:427
msgid "Search pattern"
-msgstr "Padrão de pesquisa "
+msgstr "Padrão de pesquisa"
-#: spyder/widgets/findinfiles.py:418 spyder/widgets/findinfiles.py:458
-#: spyder/widgets/findreplace.py:99
+#: spyder/widgets/findinfiles.py:430 spyder/widgets/findinfiles.py:470
+#: spyder/widgets/findreplace.py:100
msgid "Regular expression"
msgstr "Expressão regular"
-#: spyder/widgets/findinfiles.py:421 spyder/widgets/findreplace.py:105
+#: spyder/widgets/findinfiles.py:433 spyder/widgets/findreplace.py:106
msgid "Case Sensitive"
msgstr ""
"Diferenciar maiúsculas\n"
"de minúsculas"
-#: spyder/widgets/findinfiles.py:432
+#: spyder/widgets/findinfiles.py:444
msgid "Search"
msgstr "Procurar"
-#: spyder/widgets/findinfiles.py:435
+#: spyder/widgets/findinfiles.py:447
msgid "Start search"
msgstr "Iniciar busca"
-#: spyder/widgets/findinfiles.py:442
+#: spyder/widgets/findinfiles.py:454
msgid "Stop search"
msgstr "Parar busca"
-#: spyder/widgets/findinfiles.py:452
-msgid "Excluded filenames pattern"
+#: spyder/widgets/findinfiles.py:464
+#, fuzzy
+msgid "Exclude pattern"
msgstr ""
"Excluir padrões de nomes\n"
"do arquivo"
-#: spyder/widgets/findinfiles.py:461
+#: spyder/widgets/findinfiles.py:473
msgid "Exclude:"
msgstr "Excluir:"
-#: spyder/widgets/findinfiles.py:470
+#: spyder/widgets/findinfiles.py:482
msgid "Search in:"
msgstr "Procurar em:"
-#: spyder/widgets/findinfiles.py:499
+#: spyder/widgets/findinfiles.py:511
msgid "Hide advanced options"
msgstr "Esconder opções avançadas"
-#: spyder/widgets/findinfiles.py:502
+#: spyder/widgets/findinfiles.py:514
msgid "Show advanced options"
-msgstr "Mostrar opções avançadas "
+msgstr "Mostrar opções avançadas"
-#: spyder/widgets/findinfiles.py:759 spyder/widgets/findinfiles.py:843
+#: spyder/widgets/findinfiles.py:790 spyder/widgets/findinfiles.py:877
msgid "String not found"
msgstr "String não encontrada"
-#: spyder/widgets/findinfiles.py:845
+#: spyder/widgets/findinfiles.py:879
msgid "matches in"
msgstr "correspondências em"
-#: spyder/widgets/findinfiles.py:846
+#: spyder/widgets/findinfiles.py:880
msgid "file"
msgstr "arquivo"
-#: spyder/widgets/findinfiles.py:878
+#: spyder/widgets/findinfiles.py:912
msgid " Scanning: {0}"
msgstr " Escaneando: {0}"
-#: spyder/widgets/findinfiles.py:880
+#: spyder/widgets/findinfiles.py:914
msgid " Searching for files in folder: {0}"
msgstr " Procurando por arquivos no diretório: {0}"
-#: spyder/widgets/findinfiles.py:884
+#: spyder/widgets/findinfiles.py:918
msgid " Searching for files..."
msgstr " Procurando por arquivos..."
-#: spyder/widgets/findreplace.py:48
+#: spyder/widgets/findreplace.py:49
msgid "No matches"
msgstr "Sem correspondências"
-#: spyder/widgets/findreplace.py:49 spyder/widgets/findreplace.py:50
-#: spyder/widgets/findreplace.py:72
+#: spyder/widgets/findreplace.py:50 spyder/widgets/findreplace.py:51
+#: spyder/widgets/findreplace.py:73
msgid "Search string"
msgstr "Procurar string"
-#: spyder/widgets/findreplace.py:51
-msgid "Regular expression error"
-msgstr "Erro na expressão regular"
-
-#: spyder/widgets/findreplace.py:111
+#: spyder/widgets/findreplace.py:112
msgid "Whole words"
msgstr "Palavras inteiras"
-#: spyder/widgets/findreplace.py:117
+#: spyder/widgets/findreplace.py:118
msgid "Highlight matches"
-msgstr "Destacar correspondências "
+msgstr "Destacar correspondências"
-#: spyder/widgets/findreplace.py:131
+#: spyder/widgets/findreplace.py:132
msgid "Replace with:"
msgstr "Substituir com:"
-#: spyder/widgets/findreplace.py:133
+#: spyder/widgets/findreplace.py:134
msgid "Replace string"
msgstr "Substituir string"
-#: spyder/widgets/findreplace.py:137
+#: spyder/widgets/findreplace.py:138
msgid "Replace/find next"
msgstr "Substituir/procurar próximo"
-#: spyder/widgets/findreplace.py:142
+#: spyder/widgets/findreplace.py:143
msgid "Replace selection"
msgstr "Substituir seleção"
-#: spyder/widgets/findreplace.py:150
+#: spyder/widgets/findreplace.py:151
msgid "Replace all"
msgstr "Substituir tudo"
-#: spyder/widgets/findreplace.py:577
+#: spyder/widgets/findreplace.py:583
msgid "of"
msgstr "do"
-#: spyder/widgets/findreplace.py:581
+#: spyder/widgets/findreplace.py:587
msgid "matches"
msgstr "correspondências"
-#: spyder/widgets/findreplace.py:584
+#: spyder/widgets/findreplace.py:590
msgid "no matches"
msgstr "sem correspondências"
-#: spyder/widgets/internalshell.py:262
+#: spyder/widgets/github/backend.py:151
+msgid "Invalid credentials"
+msgstr "Credenciais inválidas"
+
+#: spyder/widgets/github/backend.py:152
+msgid "Failed to create Github issue, invalid credentials..."
+msgstr "Falha ao criar issue no Github, credenciais inválidas..."
+
+#: spyder/widgets/github/backend.py:159
+msgid "Failed to create issue"
+msgstr "Falha ao criar uma issue"
+
+#: spyder/widgets/github/backend.py:160
+msgid "Failed to create Github issue. Error %d"
+msgstr "Falha ao criar issue no Github. Error %d"
+
+#: spyder/widgets/github/backend.py:167
+msgid "Issue created on Github"
+msgstr "Issue criada no Github"
+
+#: spyder/widgets/github/backend.py:168
+msgid ""
+"Issue successfully created. Would you like to open the issue in your web "
+"browser?"
+msgstr ""
+"Issue criada com sucesso. Gostaria de abrir a issue no seu navegador web?"
+
+#: spyder/widgets/github/backend.py:195
+msgid "Failed to store password"
+msgstr "Falha ao armazenar senha"
+
+#: spyder/widgets/github/backend.py:196
+msgid ""
+"It was not possible to securely save your password. You will be prompted for "
+"your Github credentials next time you want to report an issue."
+msgstr ""
+"Não foi possível salvar sua senha de forma segura. Será solicitado que você "
+"informe suas credenciais do Github na próxima vez que quiser reportar uma "
+"falha."
+
+#: spyder/widgets/github/backend.py:212
+msgid "Failed to store token"
+msgstr "Falha ao armazenar token"
+
+#: spyder/widgets/github/backend.py:213
+msgid ""
+"It was not possible to securely save your token. You will be prompted for "
+"your Github token next time you want to report an issue."
+msgstr ""
+"Não foi possível salvar seu token de forma segura. Será solicitado que você "
+"informe seu token do Github na próxima vez que quiser reportar uma falha."
+
+#: spyder/widgets/github/backend.py:237
+msgid "Failed to retrieve password"
+msgstr "Falha ao receber senha"
+
+#: spyder/widgets/github/backend.py:238
+msgid ""
+"It was not possible to retrieve your password. Please introduce it again."
+msgstr "Não foi possível receber sua senha. Por favor, tente novamente."
+
+#: spyder/widgets/github/backend.py:249
+msgid "Failed to retrieve token"
+msgstr "Falha ao receber o token"
+
+#: spyder/widgets/github/backend.py:250
+msgid "It was not possible to retrieve your token. Please introduce it again."
+msgstr "Não foi possível receber seu token. Por favor, tente novamente."
+
+#: spyder/widgets/github/gh_login.py:38
+msgid "Sign in to Github"
+msgstr "Autenticar no Github"
+
+#: spyder/widgets/github/gh_login.py:57
+msgid ""
+"For regular users, i.e. users without two-factor authentication "
+"enabled"
+msgstr ""
+"Para usuários regulares, ou seja, usuários sem autenticação de dois "
+"fatores ativada"
+
+#: spyder/widgets/github/gh_login.py:62
+msgid "Username:"
+msgstr "Nome do usuário:"
+
+#: spyder/widgets/github/gh_login.py:69
+msgid "Password: "
+msgstr "Senha: "
+
+#: spyder/widgets/github/gh_login.py:81
+msgid "Remember me"
+msgstr "Lembrar meus dados"
+
+#: spyder/widgets/github/gh_login.py:82
+msgid "Spyder will save your credentials safely"
+msgstr "O Spyder irá salvar as credenciais de forma segura"
+
+#: spyder/widgets/github/gh_login.py:99
+msgid "Password Only"
+msgstr "Somente senha"
+
+#: spyder/widgets/github/gh_login.py:105
+msgid ""
+"For users with two-factor authentication enabled, or who prefer a per-"
+"app token authentication.
You can go here "
+"and click \"Generate token\" at the bottom to create a new token to use for "
+"this, with the appropriate permissions."
+msgstr ""
+"Para usuários com autenticação de dois fatores ativada, ou que "
+"preferem uma autenticação por token.
Você pode ir aqui e clicar em \"Gerar token\"na parte inferior para criar "
+"um novo token, com as permissões apropriadas."
+
+#: spyder/widgets/github/gh_login.py:127
+msgid "Remember token"
+msgstr "Lembrar token"
+
+#: spyder/widgets/github/gh_login.py:128
+msgid "Spyder will save your token safely"
+msgstr "Spyder salvará seu token com segurança"
+
+#: spyder/widgets/github/gh_login.py:145
+msgid "Access Token"
+msgstr "Token de acesso"
+
+#: spyder/widgets/github/gh_login.py:148
+msgid "Sign in"
+msgstr "Login"
+
+#: spyder/widgets/internalshell.py:263
msgid "Help..."
msgstr "Ajuda..."
-#: spyder/widgets/internalshell.py:279
+#: spyder/widgets/internalshell.py:280
msgid "Shell special commands:"
-msgstr "Comando especiais: "
+msgstr "Comando especiais:"
-#: spyder/widgets/internalshell.py:280
+#: spyder/widgets/internalshell.py:281
msgid "Internal editor:"
msgstr "Editor interno:"
-#: spyder/widgets/internalshell.py:281
+#: spyder/widgets/internalshell.py:282
msgid "External editor:"
msgstr "Editor externo:"
-#: spyder/widgets/internalshell.py:282
+#: spyder/widgets/internalshell.py:283
msgid "Run script:"
msgstr "Executar script:"
-#: spyder/widgets/internalshell.py:283
+#: spyder/widgets/internalshell.py:284
msgid "Remove references:"
msgstr "Remover referências:"
-#: spyder/widgets/internalshell.py:284
+#: spyder/widgets/internalshell.py:285
msgid "System commands:"
msgstr "Comandos do sistema:"
-#: spyder/widgets/internalshell.py:285
+#: spyder/widgets/internalshell.py:286
msgid "Python help:"
msgstr "Ajuda do Python:"
-#: spyder/widgets/internalshell.py:286
+#: spyder/widgets/internalshell.py:287
msgid "GUI-based editor:"
msgstr "Editor gráfico:"
-#: spyder/widgets/ipythonconsole/client.py:272
+#: spyder/widgets/internalshell.py:418
+msgid ""
+"In order to use commands like \"raw_input\" or \"input\" run Spyder with the "
+"multithread option (--multithread) from a system terminal"
+msgstr ""
+
+#: spyder/widgets/ipythonconsole/client.py:308
msgid "An error ocurred while starting the kernel"
msgstr "Um erro ocorreu enquanto o kernel era inicializado"
-#: spyder/widgets/ipythonconsole/client.py:313
-#: spyder/widgets/ipythonconsole/client.py:369
-#: spyder/widgets/ipythonconsole/client.py:402
-#: spyder/widgets/ipythonconsole/shell.py:233
-#: spyder/widgets/variableexplorer/namespacebrowser.py:193
+#: spyder/widgets/ipythonconsole/client.py:352
+#: spyder/widgets/ipythonconsole/client.py:408
+#: spyder/widgets/ipythonconsole/client.py:441
+#: spyder/widgets/ipythonconsole/shell.py:234
+#: spyder/widgets/variableexplorer/namespacebrowser.py:196
msgid "Remove all variables"
msgstr "Remover todas variáveis"
-#: spyder/widgets/ipythonconsole/client.py:322
+#: spyder/widgets/ipythonconsole/client.py:361
msgid "Show environment variables"
msgstr "Mostrar variáveis de ambiente"
-#: spyder/widgets/ipythonconsole/client.py:329
+#: spyder/widgets/ipythonconsole/client.py:368
msgid "Show sys.path contents"
msgstr "Mostrar conteúdo do sys.path"
-#: spyder/widgets/ipythonconsole/client.py:356
+#: spyder/widgets/ipythonconsole/client.py:395
msgid "Stop the current command"
msgstr "Parar o comando atual"
-#: spyder/widgets/ipythonconsole/client.py:367
-#: spyder/widgets/variableexplorer/collectionseditor.py:699
-#: spyder/widgets/variableexplorer/collectionseditor.py:934
+#: spyder/widgets/ipythonconsole/client.py:406
+#: spyder/widgets/variableexplorer/collectionseditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:970
msgid "Remove"
msgstr "Remover"
-#: spyder/widgets/ipythonconsole/client.py:390
+#: spyder/widgets/ipythonconsole/client.py:429
msgid "Inspect current object"
msgstr "Inspecionar objeto"
-#: spyder/widgets/ipythonconsole/client.py:396
+#: spyder/widgets/ipythonconsole/client.py:435
msgid "Clear line or block"
msgstr "Limpar linha ou bloco"
-#: spyder/widgets/ipythonconsole/client.py:409
+#: spyder/widgets/ipythonconsole/client.py:448
msgid "Clear console"
msgstr "Limpar console"
-#: spyder/widgets/ipythonconsole/client.py:462
+#: spyder/widgets/ipythonconsole/client.py:507
msgid "Are you sure you want to restart the kernel?"
msgstr "Deseja mesmo reiniciar o kernel?"
-#: spyder/widgets/ipythonconsole/client.py:464
+#: spyder/widgets/ipythonconsole/client.py:509
msgid "Restart kernel?"
msgstr "Reiniciar kernel?"
-#: spyder/widgets/ipythonconsole/client.py:476
+#: spyder/widgets/ipythonconsole/client.py:526
msgid "Error restarting kernel: %s\n"
msgstr "Erro ao reiniciar kernel: %s\n"
-#: spyder/widgets/ipythonconsole/client.py:484
+#: spyder/widgets/ipythonconsole/client.py:534
msgid ""
"
Restarting kernel...\n"
"
"
@@ -4251,40 +4433,40 @@ msgstr ""
"
Reiniciando kernel..\n"
"
"
-#: spyder/widgets/ipythonconsole/client.py:488
+#: spyder/widgets/ipythonconsole/client.py:538
msgid "Cannot restart a kernel not started by Spyder\n"
msgstr "Não é possível reiniciar um kernel que não foi iniciado pelo Spyder\n"
-#: spyder/widgets/ipythonconsole/client.py:597
+#: spyder/widgets/ipythonconsole/client.py:649
msgid "Connecting to kernel..."
msgstr "Conectando ao kernel..."
-#: spyder/widgets/ipythonconsole/help.py:128 spyder/widgets/mixins.py:712
+#: spyder/widgets/ipythonconsole/help.py:128 spyder/widgets/mixins.py:726
msgid "Arguments"
msgstr "Argumentos"
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:129
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:138
msgid "Loading this kind of data while debugging is not supported."
msgstr ""
"O carregamento desse tipo de dado enquanto a depuração ocorre não é "
"suportado."
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:148
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:157
msgid "Saving data while debugging is not supported."
msgstr "Salvar dados enquanto a depuração ocorre não é suportado."
-#: spyder/widgets/ipythonconsole/shell.py:234
+#: spyder/widgets/ipythonconsole/shell.py:235
msgid ""
"All user-defined variables will be removed. Are you sure you want to proceed?"
msgstr ""
"Todas as variáveis definidas pelo usuário serão removidas.
Você tem "
-"certeza diisso?"
+"certeza disso?"
-#: spyder/widgets/ipythonconsole/shell.py:240
+#: spyder/widgets/ipythonconsole/shell.py:241
msgid "Don't show again."
msgstr "Não mostrar novamente."
-#: spyder/widgets/ipythonconsole/shell.py:264
+#: spyder/widgets/ipythonconsole/shell.py:266
msgid ""
"
Removing all variables...\n"
"
"
@@ -4292,15 +4474,15 @@ msgstr ""
"
Removendo todas variáveis...\n"
"
"
-#: spyder/widgets/ipythonconsole/shell.py:430
-msgid "Changing backend to Qt for Mayavi"
-msgstr "Mudando a saída gráfica do Qt para Mayavi"
+#: spyder/widgets/ipythonconsole/shell.py:432
+msgid "Changing backend to Qt4 for Mayavi"
+msgstr "Mudando o backend do Qt para Mayavi"
-#: spyder/widgets/ipythonconsole/shell.py:475
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel died, restarting"
msgstr "O Kernel morreu, reiniciando"
-#: spyder/widgets/ipythonconsole/shell.py:475
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel restarting"
msgstr "Reiniciando Kernel"
@@ -4328,45 +4510,46 @@ msgstr "Reduzir seleção"
msgid "Expand selection"
msgstr "Expandir seleção"
-#: spyder/widgets/pathmanager.py:97
+#: spyder/widgets/pathmanager.py:98
msgid "Move to top"
msgstr "Mover para o inicio"
-#: spyder/widgets/pathmanager.py:103
+#: spyder/widgets/pathmanager.py:104
msgid "Move up"
msgstr "Mover para cima"
-#: spyder/widgets/pathmanager.py:109
+#: spyder/widgets/pathmanager.py:110
msgid "Move down"
msgstr "Mover para baixo"
-#: spyder/widgets/pathmanager.py:115
+#: spyder/widgets/pathmanager.py:116
msgid "Move to bottom"
msgstr "Mover para o final"
-#: spyder/widgets/pathmanager.py:126 spyder/widgets/pathmanager.py:267
+#: spyder/widgets/pathmanager.py:127 spyder/widgets/pathmanager.py:270
+#: spyder/widgets/pathmanager.py:282
msgid "Add path"
msgstr "Adicionar caminho"
-#: spyder/widgets/pathmanager.py:131 spyder/widgets/pathmanager.py:246
+#: spyder/widgets/pathmanager.py:132 spyder/widgets/pathmanager.py:247
msgid "Remove path"
msgstr "Remover caminho"
-#: spyder/widgets/pathmanager.py:141
+#: spyder/widgets/pathmanager.py:142
msgid "Synchronize..."
msgstr "Sincronizar..."
-#: spyder/widgets/pathmanager.py:143
+#: spyder/widgets/pathmanager.py:144
msgid "Synchronize Spyder's path list with PYTHONPATH environment variable"
msgstr ""
"Sincronizar a lista de caminhos do Spyder com a variável\n"
"de ambiente PYTHONPATH"
-#: spyder/widgets/pathmanager.py:155
+#: spyder/widgets/pathmanager.py:156
msgid "Synchronize"
msgstr "Sincronizar"
-#: spyder/widgets/pathmanager.py:156
+#: spyder/widgets/pathmanager.py:157
msgid ""
"This will synchronize Spyder's path list with PYTHONPATH environment "
"variable for current user, allowing you to run your Python modules outside "
@@ -4379,11 +4562,17 @@ msgstr ""
"
Deseja limpar o conteúdo da PYTHONPATH antes de adicionar a lista de "
"caminhos do Spyder?"
-#: spyder/widgets/pathmanager.py:247
+#: spyder/widgets/pathmanager.py:248
msgid "Do you really want to remove selected path?"
msgstr "Você deseja mesmo remover o caminho selecionado?"
-#: spyder/widgets/pathmanager.py:268
+#: spyder/widgets/pathmanager.py:271
+msgid ""
+"You are using Python 2 and the path selected has Unicode characters. The new "
+"path will not be added."
+msgstr ""
+
+#: spyder/widgets/pathmanager.py:283
msgid ""
"This directory is already included in Spyder path list.
Do you want to "
"move it to the top of the list?"
@@ -4510,7 +4699,7 @@ msgstr "Criar"
msgid "Create new project"
msgstr "Criar um novo projeto"
-#: spyder/widgets/projects/type/__init__.py:216
+#: spyder/widgets/projects/type/__init__.py:223
msgid "Empty project"
msgstr "Projeto vazio"
@@ -4522,78 +4711,105 @@ msgstr "Projeto Python"
msgid "Python package"
msgstr "Pacote Python"
-#: spyder/widgets/pydocgui.py:110
+#: spyder/widgets/pydocgui.py:117
msgid "Module or package:"
msgstr "Módulo ou pacote:"
-#: spyder/widgets/reporterror.py:121
-msgid "Spyder internal error"
-msgstr "Erro interno do Spyder"
-
-#: spyder/widgets/reporterror.py:129
-msgid ""
-"Spyder has encountered an internal problem
\n"
-" Before reporting it, please consult our comprehensive \n"
-" Troubleshooting Guide \n"
-" which should help solve most issues, and search for \n"
-" known bugs matching your error \n"
-" message or problem description for a quicker solution.\n"
-"
\n"
-" If you don't find anything, please enter a detailed step-by-"
-"step \n"
-" description (in English) of what led up to the problem "
-"below. \n"
-" Issue reports without a clear way to reproduce them will be \n"
-" closed.
\n"
-" Thanks for helping us making Spyder better for everyone!\n"
-" "
-msgstr ""
-"O Spyder encontrou um erro interno
\n"
-" Antes de reportar ele, por favor consulte nosso \n"
-" Guia de solução de problemas \n"
-" ele pode lhe ajudar a resolver a maioria dos problemas e "
-"procurar por\n"
-" bugs conhecidos que correspondem "
-"a sua mensagem \n"
-" de erro ou problema. \n"
-"
\n"
-" Se você não encontrou nada por favor digite uma descrição "
-"detalhada \n"
-" (em Inglês) do que levou você até o problema. \n"
-" Relatos de falhas sem um caminho claro de como elas "
-"aconteceram \n"
-" serão fechadas
\n"
-" Obrigado por ajudar a gente a fazer um Spyder melhor para "
-"todos!\n"
-" "
-
-#: spyder/widgets/reporterror.py:163
-msgid "Hide all future errors this session"
-msgstr "Esconder todos futuros erros nesta sessão"
-
-#: spyder/widgets/reporterror.py:171
+#: spyder/widgets/reporterror.py:128
+msgid "Issue reporter"
+msgstr "Reportador de issue"
+
+#: spyder/widgets/reporterror.py:136
+msgid "Please fill the following information"
+msgstr "Por favor, preencha as seguintes informações"
+
+#: spyder/widgets/reporterror.py:138
+msgid "Spyder has encountered an internal problem!"
+msgstr "Ocorreu um erro interno no Spyder!"
+
+#: spyder/widgets/reporterror.py:140
+msgid ""
+"{title}
Before reporting this problem, please consult our "
+"comprehensive Troubleshooting Guide "
+"which should help solve most issues, and search for known bugs matching your error message or problem "
+"description for a quicker solution."
+msgstr ""
+"{title}
Antes de reportar esse erro, por favor consulte nosso "
+"Guia de Solução Problemas que pode lhe "
+"ajudar a resolver a maioria dos problemas e procurar por bugs conhecidos que podem corresponder a sua "
+"mensagem de erro ou problema."
+
+#: spyder/widgets/reporterror.py:158 spyder/widgets/reporterror.py:190
+msgid "{} more characters to go..."
+msgstr "{} mais caracteres..."
+
+#: spyder/widgets/reporterror.py:162
+msgid "Title: {}"
+msgstr "Título: {}"
+
+#: spyder/widgets/reporterror.py:168
+msgid "Steps to reproduce: {}"
+msgstr "Etapas para reproduzir: {}"
+
+#: spyder/widgets/reporterror.py:169
+msgid ""
+"Please enter a detailed step-by-step description (in English) of what led up "
+"to the problem below. Issue reports without a clear way to reproduce them "
+"will be closed."
+msgstr ""
+"Por favor, insira uma descrição detalhada passo-a-passo (em inglês) do que o "
+"levou ao problema abaixo. Relatórios de erros emitidos de forma não clara "
+"serão fechados."
+
+#: spyder/widgets/reporterror.py:194
+msgid "Hide all future errors during this session"
+msgstr "Ocultar todos os erros futuros durante esta sessão"
+
+#: spyder/widgets/reporterror.py:201
msgid "Submit to Github"
msgstr "Enviar para o Github"
-#: spyder/widgets/reporterror.py:175 spyder/widgets/reporterror.py:227
+#: spyder/widgets/reporterror.py:205 spyder/widgets/reporterror.py:312
msgid "Show details"
msgstr "Mostrar detalhes"
-#: spyder/widgets/reporterror.py:178
+#: spyder/widgets/reporterror.py:210
+#: spyder/widgets/variableexplorer/arrayeditor.py:740
+#: spyder/widgets/variableexplorer/collectionseditor.py:1397
+#: spyder/widgets/variableexplorer/dataframeeditor.py:756
+#: spyder/widgets/variableexplorer/texteditor.py:72
msgid "Close"
msgstr "Fechar"
-#: spyder/widgets/reporterror.py:235
+#: spyder/widgets/reporterror.py:286
+msgid ""
+"An error occurred while trying to send the issue to Github automatically. "
+"Would you like to open it manually?
If so, please make sure to paste "
+"your clipboard into the issue report box that will appear in a new browser "
+"tab before clicking Submit on that page."
+msgstr ""
+"Aconteceu um erro ao tentar enviar o problema para o Github automaticamente. "
+"Deseja abrir manualmente?
Caso sim, cole sua área de transferência na "
+"caixa do relatório de problemas que será exibida em uma nova guia do "
+"navegador antes de clicar em Enviar nessa página."
+
+#: spyder/widgets/reporterror.py:320
msgid "Hide details"
msgstr "Esconder detalhes"
-#: spyder/widgets/reporterror.py:243
+#: spyder/widgets/reporterror.py:329 spyder/widgets/reporterror.py:337
msgid "more characters to go..."
msgstr "mais caracteres..."
-#: spyder/widgets/reporterror.py:245
-msgid "Submission enabled; thanks!"
-msgstr "Envio habilitado; obrigado!"
+#: spyder/widgets/reporterror.py:331
+msgid "Description complete; thanks!"
+msgstr "Descrição completa; obrigado!"
+
+#: spyder/widgets/reporterror.py:339
+msgid "Title complete; thanks!"
+msgstr "Título completo; obrigado!"
#: spyder/widgets/shell.py:131
msgid "Save history log..."
@@ -4640,27 +4856,27 @@ msgstr "Ir para a linha:"
msgid "Line count:"
msgstr "Número de linhas:"
-#: spyder/widgets/sourcecode/codeeditor.py:1327
+#: spyder/widgets/sourcecode/codeeditor.py:1334
msgid "Breakpoint"
msgstr "Ponto de interrupção"
-#: spyder/widgets/sourcecode/codeeditor.py:1328
+#: spyder/widgets/sourcecode/codeeditor.py:1335
msgid "Condition:"
msgstr "Condição:"
-#: spyder/widgets/sourcecode/codeeditor.py:1733
+#: spyder/widgets/sourcecode/codeeditor.py:1740
msgid "Code analysis"
msgstr "Análise de código"
-#: spyder/widgets/sourcecode/codeeditor.py:1787
+#: spyder/widgets/sourcecode/codeeditor.py:1794
msgid "To do"
msgstr "To do"
-#: spyder/widgets/sourcecode/codeeditor.py:2147
+#: spyder/widgets/sourcecode/codeeditor.py:2154
msgid "Removal error"
msgstr "Erro de remoção"
-#: spyder/widgets/sourcecode/codeeditor.py:2148
+#: spyder/widgets/sourcecode/codeeditor.py:2155
msgid ""
"It was not possible to remove outputs from this notebook. The error is:\n"
"\n"
@@ -4668,15 +4884,15 @@ msgstr ""
"Não foi possível remover as saídas deste notebook. O erro é:\n"
"\n"
-#: spyder/widgets/sourcecode/codeeditor.py:2696
+#: spyder/widgets/sourcecode/codeeditor.py:2703
msgid "Clear all ouput"
-msgstr "Limpar todas as saídas "
+msgstr "Limpar todas as saídas"
-#: spyder/widgets/sourcecode/codeeditor.py:2702
+#: spyder/widgets/sourcecode/codeeditor.py:2709
msgid "Go to definition"
msgstr "Ver definição"
-#: spyder/widgets/sourcecode/codeeditor.py:2735
+#: spyder/widgets/sourcecode/codeeditor.py:2742
msgid "Zoom reset"
msgstr "Resetar Zoom"
@@ -4732,102 +4948,102 @@ msgstr "Navegar pelas abas"
msgid "Close current tab"
msgstr "Fechar aba atual"
-#: spyder/widgets/variableexplorer/arrayeditor.py:511
+#: spyder/widgets/variableexplorer/arrayeditor.py:509
msgid "It was not possible to copy values for this array"
msgstr "Não foi possível copiar os valores dessa matriz"
-#: spyder/widgets/variableexplorer/arrayeditor.py:546
-#: spyder/widgets/variableexplorer/arrayeditor.py:579
-#: spyder/widgets/variableexplorer/dataframeeditor.py:703
-#: spyder/widgets/variableexplorer/dataframeeditor.py:748
+#: spyder/widgets/variableexplorer/arrayeditor.py:545
+#: spyder/widgets/variableexplorer/arrayeditor.py:578
+#: spyder/widgets/variableexplorer/dataframeeditor.py:728
+#: spyder/widgets/variableexplorer/dataframeeditor.py:787
msgid "Format"
msgstr "Formato"
-#: spyder/widgets/variableexplorer/arrayeditor.py:551
-#: spyder/widgets/variableexplorer/dataframeeditor.py:707
+#: spyder/widgets/variableexplorer/arrayeditor.py:550
+#: spyder/widgets/variableexplorer/dataframeeditor.py:732
msgid "Resize"
msgstr "Redimensionar"
-#: spyder/widgets/variableexplorer/arrayeditor.py:554
-#: spyder/widgets/variableexplorer/dataframeeditor.py:711
+#: spyder/widgets/variableexplorer/arrayeditor.py:553
+#: spyder/widgets/variableexplorer/dataframeeditor.py:736
msgid "Background color"
msgstr "Cor de fundo"
-#: spyder/widgets/variableexplorer/arrayeditor.py:580
-#: spyder/widgets/variableexplorer/dataframeeditor.py:749
+#: spyder/widgets/variableexplorer/arrayeditor.py:579
+#: spyder/widgets/variableexplorer/dataframeeditor.py:788
msgid "Float formatting"
msgstr "Formatação de ponto flutuante"
-#: spyder/widgets/variableexplorer/arrayeditor.py:588
+#: spyder/widgets/variableexplorer/arrayeditor.py:587
msgid "Format (%s) is incorrect"
msgstr "O formato (%s) está incorreto"
-#: spyder/widgets/variableexplorer/arrayeditor.py:624
+#: spyder/widgets/variableexplorer/arrayeditor.py:625
msgid "Arrays with more than 3 dimensions are not supported"
msgstr "Matrizes com mais de 3 dimensões não são suportadas"
-#: spyder/widgets/variableexplorer/arrayeditor.py:628
+#: spyder/widgets/variableexplorer/arrayeditor.py:629
msgid "The 'xlabels' argument length do no match array column number"
msgstr ""
"O argumento de comprimento 'xlabels' não corresponde com o número de colunas "
"da matriz"
-#: spyder/widgets/variableexplorer/arrayeditor.py:632
+#: spyder/widgets/variableexplorer/arrayeditor.py:633
msgid "The 'ylabels' argument length do no match array row number"
msgstr ""
"O argumento de comprimento 'ylabels' não corresponde com o número de linhas "
"da matriz"
-#: spyder/widgets/variableexplorer/arrayeditor.py:639
+#: spyder/widgets/variableexplorer/arrayeditor.py:640
msgid "%s arrays"
msgstr "%s matrizes"
-#: spyder/widgets/variableexplorer/arrayeditor.py:640
+#: spyder/widgets/variableexplorer/arrayeditor.py:641
msgid "%s are currently not supported"
msgstr "%s não é suportado no momento"
-#: spyder/widgets/variableexplorer/arrayeditor.py:647
+#: spyder/widgets/variableexplorer/arrayeditor.py:648
msgid "NumPy array"
msgstr "Matriz NumPy"
-#: spyder/widgets/variableexplorer/arrayeditor.py:649
-#: spyder/widgets/variableexplorer/arrayeditor.py:806
+#: spyder/widgets/variableexplorer/arrayeditor.py:650
+#: spyder/widgets/variableexplorer/arrayeditor.py:828
msgid "Array editor"
msgstr "Editor de matrizes"
-#: spyder/widgets/variableexplorer/arrayeditor.py:651
+#: spyder/widgets/variableexplorer/arrayeditor.py:652
msgid "read only"
msgstr "somente leitura"
-#: spyder/widgets/variableexplorer/arrayeditor.py:681
+#: spyder/widgets/variableexplorer/arrayeditor.py:685
msgid "Record array fields:"
msgstr "Campos de matrizes registradas:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Data"
msgstr "Dados"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Mask"
msgstr "Máscara"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Masked data"
msgstr "Dados mascarados"
-#: spyder/widgets/variableexplorer/arrayeditor.py:704
+#: spyder/widgets/variableexplorer/arrayeditor.py:708
msgid "Axis:"
msgstr "Eixo:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:709
+#: spyder/widgets/variableexplorer/arrayeditor.py:713
msgid "Index:"
msgstr "Índice:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:722
+#: spyder/widgets/variableexplorer/arrayeditor.py:726
msgid "Warning: changes are applied separately"
msgstr "Aviso: mudanças são aplicadas de forma separada"
-#: spyder/widgets/variableexplorer/arrayeditor.py:723
+#: spyder/widgets/variableexplorer/arrayeditor.py:727
msgid ""
"For performance reasons, changes applied to masked array won't be reflected "
"in array's data (and vice-versa)."
@@ -4837,47 +5053,54 @@ msgstr ""
"refletidas nos dados da matriz\n"
"(e vice-versa)."
-#: spyder/widgets/variableexplorer/collectionseditor.py:126
+#: spyder/widgets/variableexplorer/arrayeditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:1392
+#: spyder/widgets/variableexplorer/dataframeeditor.py:751
+#: spyder/widgets/variableexplorer/texteditor.py:67
+msgid "Save and Close"
+msgstr "Salvar e Fechar"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:151
msgid "Index"
msgstr "Índice"
-#: spyder/widgets/variableexplorer/collectionseditor.py:131
+#: spyder/widgets/variableexplorer/collectionseditor.py:156
msgid "Tuple"
msgstr "Tupla"
-#: spyder/widgets/variableexplorer/collectionseditor.py:134
+#: spyder/widgets/variableexplorer/collectionseditor.py:159
msgid "List"
msgstr "Lista"
-#: spyder/widgets/variableexplorer/collectionseditor.py:137
+#: spyder/widgets/variableexplorer/collectionseditor.py:162
msgid "Dictionary"
-msgstr "Dicionário "
+msgstr "Dicionário"
-#: spyder/widgets/variableexplorer/collectionseditor.py:139
+#: spyder/widgets/variableexplorer/collectionseditor.py:164
msgid "Key"
msgstr "Chave"
-#: spyder/widgets/variableexplorer/collectionseditor.py:144
+#: spyder/widgets/variableexplorer/collectionseditor.py:169
msgid "Attribute"
msgstr "Atributo"
-#: spyder/widgets/variableexplorer/collectionseditor.py:148
+#: spyder/widgets/variableexplorer/collectionseditor.py:173
msgid "elements"
msgstr "elementos"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Size"
msgstr "Tamanho"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Type"
msgstr "Tipo"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Value"
msgstr "Valor"
-#: spyder/widgets/variableexplorer/collectionseditor.py:417
+#: spyder/widgets/variableexplorer/collectionseditor.py:450
msgid ""
"Opening this variable can be slow\n"
"\n"
@@ -4887,7 +5110,7 @@ msgstr ""
"\n"
"Deseja continuar mesmo assim?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:428
+#: spyder/widgets/variableexplorer/collectionseditor.py:461
msgid ""
"Spyder was unable to retrieve the value of this variable from the console."
"
The error mesage was:
%s"
@@ -4895,149 +5118,164 @@ msgstr ""
"O Spyder não foi capaz de receber o valor desta variável do console."
"
A mensagem de erro foi:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:608
+#: spyder/widgets/variableexplorer/collectionseditor.py:643
msgid "Edit item"
msgstr "Editar item"
-#: spyder/widgets/variableexplorer/collectionseditor.py:609
+#: spyder/widgets/variableexplorer/collectionseditor.py:644
msgid "Unable to assign data to item.
Error message:
%s"
msgstr ""
"Não foi possível atribuir dados ao item.
Mensagem de erro:
"
"%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:669
+#: spyder/widgets/variableexplorer/collectionseditor.py:705
msgid "Resize rows to contents"
-msgstr "Redimensionar linhas para o conteúdo "
+msgstr "Redimensionar linhas para o conteúdo"
-#: spyder/widgets/variableexplorer/collectionseditor.py:680
-#: spyder/widgets/variableexplorer/collectionseditor.py:1030
-#: spyder/widgets/variableexplorer/collectionseditor.py:1047
+#: spyder/widgets/variableexplorer/collectionseditor.py:716
+#: spyder/widgets/variableexplorer/collectionseditor.py:1066
+#: spyder/widgets/variableexplorer/collectionseditor.py:1083
msgid "Plot"
msgstr "Gráfico"
-#: spyder/widgets/variableexplorer/collectionseditor.py:684
+#: spyder/widgets/variableexplorer/collectionseditor.py:720
msgid "Histogram"
msgstr "Histograma"
-#: spyder/widgets/variableexplorer/collectionseditor.py:688
+#: spyder/widgets/variableexplorer/collectionseditor.py:724
msgid "Show image"
msgstr "Mostrar imagem"
-#: spyder/widgets/variableexplorer/collectionseditor.py:692
-#: spyder/widgets/variableexplorer/collectionseditor.py:1055
+#: spyder/widgets/variableexplorer/collectionseditor.py:728
+#: spyder/widgets/variableexplorer/collectionseditor.py:1091
msgid "Save array"
msgstr "Salvar matriz"
-#: spyder/widgets/variableexplorer/collectionseditor.py:696
-#: spyder/widgets/variableexplorer/collectionseditor.py:994
-#: spyder/widgets/variableexplorer/collectionseditor.py:1002
+#: spyder/widgets/variableexplorer/collectionseditor.py:732
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Insert"
msgstr "Inserir"
-#: spyder/widgets/variableexplorer/collectionseditor.py:709
-#: spyder/widgets/variableexplorer/collectionseditor.py:955
+#: spyder/widgets/variableexplorer/collectionseditor.py:745
+#: spyder/widgets/variableexplorer/collectionseditor.py:991
msgid "Duplicate"
msgstr "Duplicar"
-#: spyder/widgets/variableexplorer/collectionseditor.py:932
+#: spyder/widgets/variableexplorer/collectionseditor.py:968
msgid "Do you want to remove the selected item?"
msgstr "Você deseja remover o item selecionado?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:933
+#: spyder/widgets/variableexplorer/collectionseditor.py:969
msgid "Do you want to remove all selected items?"
msgstr "Você deseja remover todos os itens selecionados?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:953
+#: spyder/widgets/variableexplorer/collectionseditor.py:989
msgid "New variable name:"
msgstr "Novo nome da variável:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:956
+#: spyder/widgets/variableexplorer/collectionseditor.py:992
msgid "Variable name:"
msgstr "Nome da variável:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:994
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
msgid "Key:"
msgstr "Chave:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1002
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Value:"
msgstr "Valor:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1018
+#: spyder/widgets/variableexplorer/collectionseditor.py:1054
msgid "Import error"
msgstr "Erro de importação"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1019
+#: spyder/widgets/variableexplorer/collectionseditor.py:1055
msgid "Please install matplotlib or guiqwt."
msgstr "Por favor instale matplotlib ou guiqwt."
-#: spyder/widgets/variableexplorer/collectionseditor.py:1031
+#: spyder/widgets/variableexplorer/collectionseditor.py:1067
msgid "Unable to plot data.
Error message:
%s"
msgstr ""
"Não foi possível mostrar os dados.
Mensagem de erro:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1048
+#: spyder/widgets/variableexplorer/collectionseditor.py:1084
msgid "Unable to show image.
Error message:
%s"
msgstr ""
"Não foi possível mostrar o gráfico.
Mensagem de erro:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1071
+#: spyder/widgets/variableexplorer/collectionseditor.py:1097
+msgid "NumPy arrays"
+msgstr "Matrizes do NumPy"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1107
msgid "Unable to save array
Error message:
%s"
msgstr "Não foi possível salvar matriz
Mensagem de erro:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1096
+#: spyder/widgets/variableexplorer/collectionseditor.py:1132
msgid "It was not possible to copy this array"
msgstr "Não foi possível copiar essa matriz"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1121
+#: spyder/widgets/variableexplorer/collectionseditor.py:1144
+#, fuzzy
+msgid "It was not possible to copy this dataframe"
+msgstr "Não foi possível copiar essa matriz"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1166
msgid "Clipboard contents"
-msgstr "Conteúdo da área de transferência "
+msgstr "Conteúdo da área de transferência"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1136
+#: spyder/widgets/variableexplorer/collectionseditor.py:1181
msgid "Import from clipboard"
-msgstr "Importar da área de transferência "
+msgstr "Importar da área de transferência"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1138
+#: spyder/widgets/variableexplorer/collectionseditor.py:1183
msgid "Empty clipboard"
msgstr "Área de transferência vazia"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1139
+#: spyder/widgets/variableexplorer/collectionseditor.py:1184
msgid "Nothing to be imported from clipboard."
msgstr "Não há nada para ser importado da área de transferência."
-#: spyder/widgets/variableexplorer/dataframeeditor.py:597
+#: spyder/widgets/variableexplorer/dataframeeditor.py:321
+msgid ""
+"It is not possible to display this value because\n"
+"an error ocurred while trying to do it"
+msgstr ""
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To bool"
msgstr "Para booleano"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:597
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To complex"
msgstr "Para complexo"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:598
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To float"
msgstr "Para flutuante"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:598
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To int"
msgstr "Para inteiro"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:599
+#: spyder/widgets/variableexplorer/dataframeeditor.py:623
msgid "To str"
msgstr "Para string"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:683
+#: spyder/widgets/variableexplorer/dataframeeditor.py:707
msgid "%s editor"
msgstr "Editor de %s"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:717
+#: spyder/widgets/variableexplorer/dataframeeditor.py:742
msgid "Column min/max"
msgstr "Min/max de coluna"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:757
+#: spyder/widgets/variableexplorer/dataframeeditor.py:796
msgid "Format ({}) is incorrect"
msgstr "O formato ({}) éincorreto"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:761
+#: spyder/widgets/variableexplorer/dataframeeditor.py:800
msgid "Format ({}) should start with '%'"
msgstr "O formato ({}) deve começar com '%'"
@@ -5149,36 +5387,37 @@ msgstr ""
"Não foi possível prosseguir para o próximo passo
Por favor "
"revise seus dados
Mensagem de erro:
%s"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:181
-#: spyder/widgets/variableexplorer/namespacebrowser.py:385
+#: spyder/widgets/variableexplorer/namespacebrowser.py:184
+#: spyder/widgets/variableexplorer/namespacebrowser.py:397
msgid "Import data"
msgstr "Importar data"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:184
-#: spyder/widgets/variableexplorer/namespacebrowser.py:465
-#: spyder/widgets/variableexplorer/namespacebrowser.py:479
+#: spyder/widgets/variableexplorer/namespacebrowser.py:187
+#: spyder/widgets/variableexplorer/namespacebrowser.py:477
+#: spyder/widgets/variableexplorer/namespacebrowser.py:491
+#: spyder/plugins/profiler/widgets/profilergui.py:121
msgid "Save data"
msgstr "Salvar data"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:189
+#: spyder/widgets/variableexplorer/namespacebrowser.py:192
msgid "Save data as..."
msgstr "Salvar data como..."
-#: spyder/widgets/variableexplorer/namespacebrowser.py:201
+#: spyder/widgets/variableexplorer/namespacebrowser.py:204
msgid "Exclude references which name starts with an underscore"
msgstr "Excluir variáveis cujo nomes comecem com sublinhado"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:209
+#: spyder/widgets/variableexplorer/namespacebrowser.py:212
msgid "Exclude references which name is uppercase"
msgstr ""
"Excluir variáveis cujo nome esteja\n"
"completamente em maiúsculas"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:216
+#: spyder/widgets/variableexplorer/namespacebrowser.py:219
msgid "Exclude references which name starts with an uppercase character"
-msgstr "Excluir variáveis cujo nome comece com maiúsculas. "
+msgstr "Excluir variáveis cujo nome comece com maiúsculas"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:224
+#: spyder/widgets/variableexplorer/namespacebrowser.py:227
msgid ""
"Exclude references to unsupported data types (i.e. which won't be handled/"
"saved correctly)"
@@ -5187,7 +5426,15 @@ msgstr ""
"(aqueles que não podem ser manipulados e armazenados\n"
" corretamente)"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:405
+#: spyder/widgets/variableexplorer/namespacebrowser.py:306
+msgid ""
+"The object you are trying to modify is too big to be sent back to the "
+"kernel. Therefore, your modifications won't take place."
+msgstr ""
+"O objeto que você está tentando modificar é muito grande para ser enviado "
+"de volta ao kernel. Então suas modificações não serão aplicadas."
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:417
msgid ""
"Unsupported file extension '%s'
Would you like to import it "
"anyway (by selecting a known file format)?"
@@ -5195,38 +5442,29 @@ msgstr ""
"Tipo de arquivo não suportado '%s'
Deseja importar mesmo assim "
"(selecionando um formato conhecido)?"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:413
+#: spyder/widgets/variableexplorer/namespacebrowser.py:425
msgid "Open file as:"
msgstr "Abrir arquivo como:"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:447
+#: spyder/widgets/variableexplorer/namespacebrowser.py:459
msgid "Unable to load '%s'
Error message:
%s"
msgstr "Não foi possível carregar '%s'
Mensagem de erro:
%s"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:480
+#: spyder/widgets/variableexplorer/namespacebrowser.py:492
msgid "Unable to save current workspace
Error message:
%s"
msgstr ""
"Não foi possível salvar o espaço de trabalho atual
Mensagem de "
"erro:
%s"
-#: spyder/widgets/variableexplorer/texteditor.py:74
+#: spyder/widgets/variableexplorer/texteditor.py:84
msgid "Text editor"
msgstr "Editor de texto"
-#: spyder/widgets/variableexplorer/utils.py:31
-msgid "View and edit DataFrames and Series in the Variable Explorer"
-msgstr "Ver e editar DataFrames e Series no Explorador de Variáveis"
-
-#: spyder/widgets/variableexplorer/utils.py:36
-msgid "View and edit two and three dimensional arrays in the Variable Explorer"
-msgstr ""
-"Ver e editar duas e três matrizes dimensionais no Explorador de Variáveis"
-
-#: spyder/workers/updates.py:90 spyder/workers/updates.py:92
+#: spyder/workers/updates.py:128 spyder/workers/updates.py:130
msgid "Unable to retrieve information."
msgstr "Não foi possível receber a informação."
-#: spyder/workers/updates.py:94
+#: spyder/workers/updates.py:132
msgid ""
"Unable to connect to the internet.
Make sure the connection is "
"working properly."
@@ -5234,310 +5472,452 @@ msgstr ""
"Não foi possível conectar a internet.
Tenha certeza se a conexão "
"está realmente funcionando."
-#: spyder/workers/updates.py:97
+#: spyder/workers/updates.py:135
msgid "Unable to check for updates."
msgstr "Não foi possível verificar por atualizações."
-#~ msgid "Pop up internal console when internal errors appear"
-#~ msgstr "Mostrar o terminal interno quando houver erros"
+#~ msgid "ViTables"
+#~ msgstr "ViTables"
#~ msgid ""
-#~ "Spyder has encountered a problem.
Sorry for the inconvenience."
-#~ "
You can automatically submit this error to our Github issues "
-#~ "tracker.
Note: You need a Github account for that."
+#~ "Update LANGUAGE_CODES (inside config/base.py) if a new translation has "
+#~ "been added to Spyder"
#~ msgstr ""
-#~ "Spyder encontrou um problema.
Desculpe pela inconveniência."
-#~ "
Você pode enviar este erro para nosso controle de bugs."
-#~ "
Nota: Você precisa de uma conta no Github para isso."
+#~ "Atualize LANGUAGE_CODES (config/base.py) se um novo idioma for adicionado "
+#~ "ao Spyder"
#~ msgid ""
-#~ "Search in all files and directories present on thecurrent Spyder path"
+#~ "Please enter the connection info of the kernel you want to connect to. "
+#~ "For that you can either select its JSON connection file using the "
+#~ "Browse button, or write directly its id, in case it's a local "
+#~ "kernel (for example kernel-3764.json or just 3764)."
#~ msgstr ""
-#~ "Procurar em todos os arquivos e diretórios presentes no caminho atual do "
-#~ "Spyder"
+#~ "Por favor introduza a informação de conexão do kernel ao qual deseja se "
+#~ "conectar. Para isso você pode selecionar seu arquivo de conexão JSON, "
+#~ "usando o botão Selecionar, ou escrever diretamente seu id, em "
+#~ "caso de que seja um kernel local (por exemplo, kernel-3764.json "
+#~ "ou só 3764)."
-#, fuzzy
-#~ msgid "At startup, the current working directory is:"
-#~ msgstr "Ao iniciar, o diretório de trabalho global é:"
+#~ msgid "Connection info:"
+#~ msgstr "Informação da conexão:"
-#, fuzzy
-#~ msgid "At startup,"
-#~ msgstr "Inicialização"
+#~ msgid "Ssh key"
+#~ msgstr "Chave ssh"
-#, fuzzy
-#~ msgid "At startup, the current working directory will be the specified path"
-#~ msgstr "Ao iniciar o diretório de trabalho será o seguinte"
+#~ msgid "Password"
+#~ msgstr "Senha"
-#~ msgid "Reset namespace"
-#~ msgstr "Resetar namespace"
+#~ msgid "Select ssh key"
+#~ msgstr "Selecionar chave ssh"
-#~ msgid "Reset IPython namespace"
-#~ msgstr "Resetar IPython namespace"
-
-#~ msgid "Loading external console..."
-#~ msgstr "Carregando console externo..."
+#~ msgid "PyQt4 Reference Guide"
+#~ msgstr "Guia de referência do PyQt4"
-#~ msgid "The Python console"
-#~ msgstr "O Console Python"
+#~ msgid "PyQt4 API Reference"
+#~ msgstr "Referência da API do PyQt4"
-#~ msgid ""
-#~ "You can also run your code on a Python console. These consoles are useful "
-#~ "because they let you run a file in a console dedicated only to it.To "
-#~ "select this behavior, please press the F6 key.
By pressing "
-#~ "the button below and then focusing the Variable Explorer, you will notice "
-#~ "that Python consoles are also connected to that pane, and that the "
-#~ "Variable Explorer only shows the variables of the currently focused "
-#~ "console."
-#~ msgstr ""
-#~ "Você também pode executar seu código em um console Python. Estes consoles "
-#~ "são úteis porque permitem que você execute um arquivo em um console "
-#~ "dedicado apenas para ele. Para selecionar este comportamento por favor "
-#~ "pressione a tecla F6.
Apertando o botão abaixo e indo no "
-#~ "Explorador de Variáveis você irá notar que os consoles Python também "
-#~ "estão conectados a este painel e que o Explorador de Variáveis só mostra "
-#~ "as variáveis do console atual."
+#~ msgid "Qt examples"
+#~ msgstr "Exemplos do Qt"
-#~ msgid "Sort files according to full path"
-#~ msgstr "Ordenar arquivos seguindo seu caminho completo"
+#~ msgid "Use the greedy completer"
+#~ msgstr "Usar o completador guloso"
-#~ msgid "&Configure..."
-#~ msgstr "&Configurar..."
-
-#~ msgid "Show TODO/FIXME/XXX/HINT/TIP/@todo comments list"
+#~ msgid ""
+#~ "This error was most probably caused by installing Spyder in a directory "
+#~ "with non-ascii characters (i.e. characters with tildes, apostrophes or "
+#~ "non-latin symbols).
To fix it, please reinstall Spyder in a "
+#~ "different location."
#~ msgstr ""
-#~ "Mostrar a lista de comentários dos\n"
-#~ "TODO/FIXME/XXX/HINT/TIP/@todo"
+#~ "Esse erro provavelmente foi causado pela instalação do Spyder em um "
+#~ "diretório com caracteres não ASCII (p.ex. caracteres com acentos, "
+#~ "apostrofes ou símbolos não Latin).
Para consertar isso por favor "
+#~ "reinstale o Spyder em um diretório diferente."
-#~ msgid "Interactive data plotting in the consoles"
-#~ msgstr "Mostra dados interativos no console"
+#~ msgid "Supported files"
+#~ msgstr "Arquivos suportados"
-#~ msgid "Python console"
-#~ msgstr "Console Python"
+#~ msgid "All files (*.*)"
+#~ msgstr "Todos os arquivos (*.*)"
-#~ msgid "One tab per script"
-#~ msgstr "Uma aba por script"
+#~ msgid "Spyder data files"
+#~ msgstr "Arquivos data do Spyder"
-#~ msgid "Buffer: "
-#~ msgstr "Buffer:"
+#~ msgid "NumPy zip arrays"
+#~ msgstr "Matrizes comprimidas do NumPy"
-#~ msgid "Merge process standard output/error channels"
-#~ msgstr "Combinar os canais de saída/erro do processo"
+#~ msgid "Matlab files"
+#~ msgstr "Arquivos do Matlab"
-#~ msgid ""
-#~ "Merging the output channels of the process means that\n"
-#~ "the standard error won't be written in red anymore,\n"
-#~ "but this has the effect of speeding up display."
-#~ msgstr ""
-#~ "Combinar os canais de saída do processo significa que\n"
-#~ "o erro padrão não será escrito em vermelho, mas isso ajuda a\n"
-#~ "melhorar a velocidade em que aparece o texto no console."
+#~ msgid "CSV text files"
+#~ msgstr "Arquivos de texto CSV"
-#~ msgid "Colorize standard error channel using ANSI escape codes"
-#~ msgstr "Colorir o canal de error padrão utilizando códigos de escape ANSI "
+#~ msgid "JPEG images"
+#~ msgstr "Imagens JPEG"
-#~ msgid ""
-#~ "This method is the only way to have colorized standard\n"
-#~ "error channel when the output channels have been merged."
-#~ msgstr ""
-#~ "Este método é a única forma de ter cor no canal de erro\n"
-#~ "padrão quando os canais de saída forem combinados."
+#~ msgid "PNG images"
+#~ msgstr "Imagens PNG"
-#~ msgid ""
-#~ "This option will be applied the next time a Python console or a terminal "
-#~ "is opened."
-#~ msgstr ""
-#~ "Esta opção será ativada na próxima vez que um console Python ou um "
-#~ "terminal for aberto."
+#~ msgid "GIF images"
+#~ msgstr "Imagens GIF"
-#~ msgid "Light background (white color)"
-#~ msgstr "Fundo claro (cor branca)"
+#~ msgid "TIFF images"
+#~ msgstr "Imagens TIFF"
-#~ msgid "PYTHONSTARTUP replacement"
-#~ msgstr "Substituto do PYTHONSTARTUP"
+#~ msgid "Pickle files"
+#~ msgstr "Arquivos Pickle"
-#~ msgid ""
-#~ "This option will override the PYTHONSTARTUP environment variable which\n"
-#~ "defines the script to be executed during the Python console startup."
-#~ msgstr ""
-#~ "Esta opção modificará a variável de ambiente PYTHONSTARTUP, a qual\n"
-#~ "define o script que é executado durante a inicialização do console\n"
-#~ "Python."
+#~ msgid "JSON files"
+#~ msgstr "Arquivos JSON"
-#~ msgid "Default PYTHONSTARTUP script"
-#~ msgstr "Script PYTHONSTARTUP padrão"
+#~ msgid "Unsupported file type '%s'"
+#~ msgstr "Tipo de arquivo não suportado '%s'"
-#~ msgid "Use the following startup script:"
-#~ msgstr "Usar o seguinte script de inicialização:"
+#~ msgid "Save"
+#~ msgstr "Salvar"
-#~ msgid "Monitor"
-#~ msgstr "Monitor"
+#~ msgid "Spyder internal error"
+#~ msgstr "Erro interno do Spyder"
#~ msgid ""
-#~ "The monitor provides introspection features to console: code completion, "
-#~ "calltips and variable explorer. Because it relies on several modules, "
-#~ "disabling the monitor may be useful to accelerate console startup."
+#~ "Spyder has encountered an internal problem
\n"
+#~ " Before reporting it, please consult our "
+#~ "comprehensive \n"
+#~ " Troubleshooting Guide \n"
+#~ " which should help solve most issues, and search for \n"
+#~ " known bugs matching your "
+#~ "error \n"
+#~ " message or problem description for a quicker solution.\n"
+#~ "
\n"
+#~ " If you don't find anything, please enter a detailed step-by-"
+#~ "step \n"
+#~ " description (in English) of what led up to the problem "
+#~ "below. \n"
+#~ " Issue reports without a clear way to reproduce them will "
+#~ "be \n"
+#~ " closed.
\n"
+#~ " Thanks for helping us making Spyder better for everyone!\n"
+#~ " "
#~ msgstr ""
-#~ "O monitor fornece características de introspecção para o console: "
-#~ "completador de código, sugestões e o explorador de variáveis. Porque ele "
-#~ "depende de vários módulos adicionais, desativando o monitor é possível "
-#~ "acelerar a inicialização do console."
+#~ "O Spyder encontrou um erro interno
\n"
+#~ " Antes de reportar ele, por favor consulte nosso \n"
+#~ " Guia de solução de problemas \n"
+#~ " ele pode lhe ajudar a resolver a maioria dos problemas e "
+#~ "procurar por\n"
+#~ " bugs conhecidos que "
+#~ "correspondem a sua mensagem \n"
+#~ " de erro ou problema. \n"
+#~ "
\n"
+#~ " Se você não encontrou nada por favor digite uma descrição "
+#~ "detalhada \n"
+#~ " (em Inglês) do que levou você até o problema. \n"
+#~ " Relatos de falhas sem um caminho claro de como elas "
+#~ "aconteceram \n"
+#~ " serão fechadas
\n"
+#~ " Obrigado por ajudar a gente a fazer um Spyder melhor para "
+#~ "todos!\n"
+#~ " "
+
+#~ msgid "Submission enabled; thanks!"
+#~ msgstr "Envio habilitado; obrigado!"
-#~ msgid "Enable monitor"
-#~ msgstr "Ativar monitor"
-
-#~ msgid "Default library"
-#~ msgstr "Biblioteca padrão"
-
-#~ msgid "Qt-Python Bindings"
-#~ msgstr "Integração Qt-Python"
-
-#~ msgid "Library:"
-#~ msgstr "Biblioteca:"
+#~ msgid "Pop up internal console when internal errors appear"
+#~ msgstr "Mostrar o terminal interno quando houver erros"
#~ msgid ""
-#~ "This option will act on
libraries such as Matplotlib, guidata or ETS"
+#~ "Spyder has encountered a problem.
Sorry for the inconvenience."
+#~ "
You can automatically submit this error to our Github issues "
+#~ "tracker.
Note: You need a Github account for that."
#~ msgstr ""
-#~ "Esta opção trará efeitos
em bibliotecas como Matplotlib, guidata ou "
-#~ "ETS"
+#~ "Spyder encontrou um problema.
Desculpe pela inconveniência."
+#~ "
Você pode enviar este erro para nosso controle de bugs."
+#~ "
Nota: Você precisa de uma conta no Github para isso."
#~ msgid ""
-#~ "Decide which backend to use to display graphics. If unsure, please select "
-#~ "the Automatic backend.
Note: We support a very "
-#~ "limited number of backends in our Python consoles. If you prefer to work "
-#~ "with a different one, please use an IPython console."
+#~ "Search in all files and directories present on thecurrent Spyder path"
#~ msgstr ""
-#~ "Decidir qual saída usar para mostrar gráficos. Se não possui certeza, por "
-#~ "favor selecione a saída Automática.
Nota: Suportamos "
-#~ "um número muito limitado de saídas nos consoles Python. Se você preferir "
-#~ "preferir trabalhar com uma diferente utilize um console IPython."
+#~ "Procurar em todos os arquivos e diretórios presentes no caminho atual do "
+#~ "Spyder"
-#~ msgid "None"
-#~ msgstr "Nenhum"
+#: spyder/plugins/breakpoints/plugin.py:45
+msgid "Breakpoints"
+msgstr "Pontos de interrupção"
-#~ msgid "Enthought Tool Suite"
-#~ msgstr "Enthought Tool Suite"
+#, fuzzy
+#~ msgid "At startup,"
+#~ msgstr "Inicialização"
-#~ msgid ""
-#~ "Enthought Tool Suite (ETS) supports PyQt4 (qt4) and wxPython (wx) "
-#~ "graphical user interfaces."
-#~ msgstr ""
-#~ "Enthought Tool Suite (ETS) suporta as bibliotecas gráficas PyQt4 (qt4) "
-#~ "e \n"
-#~ "wxPython (wx)."
+#, fuzzy
+#~ msgid "At startup, the current working directory will be the specified path"
+#~ msgstr "Ao iniciar o diretório de trabalho será o seguinte"
-#~ msgid "ETS_TOOLKIT:"
-#~ msgstr "ETS_TOOLKIT:"
+#~ msgid "Reset namespace"
+#~ msgstr "Resetar namespace"
-#~ msgid "External modules"
-#~ msgstr "Módulos externos"
+#~ msgid "Reset IPython namespace"
+#~ msgstr "Resetar IPython namespace"
-#~ msgid ""
-#~ "No Python console is currently selected to run %s.
Please "
-#~ "select or open a new Python console and try again."
-#~ msgstr ""
-#~ "Nenhum console Python foi selecionado para executar %s.
Por "
-#~ "favor selecione ou abra um novo console Python e tente novamente."
-#~ msgid ""
-#~ "%s is already running in a separate process.\n"
-#~ "Do you want to kill the process before starting a new one?"
-#~ msgstr ""
-#~ "%s já está sendo executado em um processo separado.\n"
-#~ "Você deseja matar o processo antes de iniciar um novo?"
+#: spyder/plugins/breakpoints/plugin.py:80
+msgid "List breakpoints"
+msgstr "Listar pontos de interrupção"
-#~ msgid "Command Window"
-#~ msgstr "Janela de comando"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "Condition"
+msgstr "Condição"
-#~ msgid "Open a &Python console"
-#~ msgstr "Abrir um console &Python"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "File"
+msgstr "Arquivo"
-#~ msgid "Open &command prompt"
-#~ msgstr "Abrir &prompt de comando"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "Line"
+msgstr "Linha"
-#~ msgid "Open a Windows command prompt"
-#~ msgstr "Abrir o prompt de comando do Windows"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:201
+msgid "Clear this breakpoint"
+msgstr "Limpar este ponto"
-#~ msgid "Open a &terminal"
-#~ msgstr "Abrir um &terminal"
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:206
+msgid "Edit this breakpoint"
+msgstr "Editar este ponto"
-#~ msgid "Open a terminal window"
-#~ msgstr "Abrir uma janela de terminal"
+#: spyder/plugins/pylint/plugin.py:36
+msgid "Save file before analyzing it"
+msgstr "Salvar arquivo antes de analisá-lo"
-#~ msgid "Python Console"
-#~ msgstr "Console Python"
+#: spyder/plugins/pylint/plugin.py:40
+msgid "The following option will be applied at next startup."
+msgstr ""
+"A seguinte opção será aplicada na próxima vez que o Spyder for iniciado."
+#: spyder/plugins/pylint/plugin.py:43
+msgid "History: "
+msgstr "Histórico:"
-#~ msgid "Light background"
-#~ msgstr "Fundo claro"
+#: spyder/plugins/pylint/plugin.py:44
+msgid " results"
+msgstr " resultados"
-#~ msgid "Dark background"
-#~ msgstr "Fundo escuro"
+#: spyder/plugins/pylint/plugin.py:47 spyder/plugins/profiler/plugin.py:33
+msgid "Results"
+msgstr "Resultados"
-#~ msgid "Working directory:"
-#~ msgstr "Diretório de trabalho:"
+#: spyder/plugins/pylint/plugin.py:48
+msgid "Results are stored here:"
+msgstr "Os resultados são armazenados aqui:"
-#~ msgid "Dedicated Python console"
-#~ msgstr "Console do Python dedicado"
+#: spyder/plugins/pylint/plugin.py:98
+#: spyder/plugins/pylint/widgets/pylintgui.py:83
+msgid "Static code analysis"
+msgstr "Análise de código"
-#~ msgid "Show warning when killing running process"
-#~ msgstr "Mostrar um aviso quando matar o processo"
+#: spyder/plugins/pylint/plugin.py:133
+msgid "Run static code analysis"
+msgstr "Executar análise de código"
-#~ msgid "Run Settings"
-#~ msgstr "Opções de execução"
+#: spyder/plugins/pylint/widgets/pylintgui.py:117
+msgid "Results for "
+msgstr "Resultados para "
-#~ msgid "the script directory"
-#~ msgstr "Diretório do script atual"
+#: spyder/plugins/pylint/widgets/pylintgui.py:122
+msgid "Convention"
+msgstr "Convention"
-#~ msgid "Show warning when killing running processes"
-#~ msgstr "Mostrar aviso quando um processo em execução for morto"
+#: spyder/plugins/pylint/widgets/pylintgui.py:124
+msgid "Refactor"
+msgstr "Refatoração"
-#~ msgid "Autorefresh"
-#~ msgstr "Atualizar automaticamente"
+#: spyder/plugins/pylint/widgets/pylintgui.py:206
+msgid "Analyze"
+msgstr "Analisar"
-#~ msgid "Enable autorefresh"
-#~ msgstr "Ativar atualização automatica"
+#: spyder/plugins/pylint/widgets/pylintgui.py:207
+msgid "Run analysis"
+msgstr "Executar análise"
-#~ msgid "Refresh interval: "
-#~ msgstr "Intervalo de atualização"
+#: spyder/plugins/pylint/widgets/pylintgui.py:212
+msgid "Stop current analysis"
+msgstr "Parar análise atual"
-#~ msgid ""
-#~ "The global working directory is the working directory for newly "
-#~ "opened consoles (Python/IPython consoles and terminals), for the "
-#~ "file explorer, for the find in files plugin and for new "
-#~ "files created in the editor."
-#~ msgstr ""
-#~ "O diretório de trabalho global é o diretório de trabalho para os "
-#~ "consoles recém abertos (do IPython/Python e dos terminais), para o "
-#~ "Explorador de arquivos, Buscar em arquivos e para os novos "
-#~ "arquivos criados no Editor."
+#: spyder/plugins/pylint/widgets/pylintgui.py:218
+#: spyder/plugins/pylint/widgets/pylintgui.py:288
+msgid "Select Python file"
+msgstr "Selecionar arquivo Python"
-#~ msgid "the same as in last session"
-#~ msgstr "O mesmo da última sessão"
+#: spyder/plugins/pylint/widgets/pylintgui.py:224
+#: spyder/plugins/profiler/widgets/profilergui.py:102
+msgid "Output"
+msgstr "Saída"
-#~ msgid ""
-#~ "At startup, Spyder will restore the global directory from last session"
-#~ msgstr ""
-#~ "Ao iniciar o Spyder irá restaurar o diretório global da última sessão"
+#: spyder/plugins/pylint/widgets/pylintgui.py:226
+msgid "Complete output"
+msgstr "Saída completa"
-#~ msgid "Files are opened from:"
-#~ msgstr "Os arquivos são abertos de:"
+#: spyder/plugins/pylint/widgets/pylintgui.py:260
+msgid "Pylint script was not found. Please add \"%s\" to PATH."
+msgstr ""
+"O script do Pylint não foi encontrada. Por favor adicione \"%s\" ao PATH."
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:263
+msgid "Please install pylint:"
+msgstr "Por favor instale o pylint:"
-#~ msgid "the current file directory"
-#~ msgstr "O diretório do arquivo atual"
+#: spyder/plugins/pylint/widgets/pylintgui.py:326
+msgid "Pylint output"
+msgstr "Saída do Pylint"
-#~ msgid "the global working directory"
-#~ msgstr "O diretório de trabalho global"
+#: spyder/plugins/pylint/widgets/pylintgui.py:465
+msgid "Source code has not been rated yet."
+msgstr "O código fonte não foi avaliado ainda."
-#~ msgid "Files are created in:"
-#~ msgstr "Os arquivos são criados em:"
+#: spyder/plugins/pylint/widgets/pylintgui.py:471
+msgid "Analysis did not succeed (see output for more details)."
+msgstr "A análise não foi bem sucedida (veja a saída para mais detalhes)."
-#~ msgid "Change to file base directory"
-#~ msgstr "Mudar para diretório base do arquivo"
+#: spyder/plugins/pylint/widgets/pylintgui.py:484
+msgid "Global evaluation:"
+msgstr "Avaliação global:"
-#~ msgid "When opening a file"
-#~ msgstr "Ao abrir um arquivo"
+#: spyder/plugins/pylint/widgets/pylintgui.py:488
+msgid "previous run:"
+msgstr "análise anterior:"
-#~ msgid "When saving a file"
-#~ msgstr "Ao salvar um arquivo"
+#: spyder/plugins/profiler/plugin.py:34
+msgid ""
+"Profiler plugin results (the output of python's profile/cProfile)\n"
+"are stored here:"
+msgstr "Os resultados do plugin Profiler são armazenados aqui: "
+
+#: spyder/plugins/profiler/plugin.py:75
+msgid "Profiler"
+msgstr "Profiler"
+
+#: spyder/plugins/profiler/plugin.py:104
+#: spyder/plugins/profiler/widgets/profilergui.py:81
+msgid "Profile"
+msgstr "Profiler"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:82
+msgid "Run profiler"
+msgstr "Executar Profiler"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:88
+msgid "Stop current profiling"
+msgstr "Parar processo atual"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:96
+#: spyder/plugins/profiler/widgets/profilergui.py:219
+msgid "Select Python script"
+msgstr "Selecionar script Python"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:104
+msgid "Show program's output"
+msgstr "Mostrar saída do programa"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:113
+msgid "Collapse one level up"
+msgstr "Subir um nível"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:118
+msgid "Expand one level down"
+msgstr "Descer um nível"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:124
+msgid "Save profiling data"
+msgstr "Salvar dados"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:126
+msgid "Load data"
+msgstr "Carregar data"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:129
+msgid "Load profiling data for comparison"
+msgstr "Carregar dados para comparação"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:131
+msgid "Clear comparison"
+msgstr "Limpar comparação"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:171
+msgid "Please install"
+msgstr "Por favor instale"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:172
+msgid "the Python profiler modules"
+msgstr "Módulos do Python Profiler"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:179
+msgid "Save profiler result"
+msgstr "Salvar profiler result"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:182
+#: spyder/plugins/profiler/widgets/profilergui.py:188
+msgid "Profiler result"
+msgstr "Resultado do Profiler"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:187
+msgid "Select script to compare"
+msgstr "Selecione um script para comparar"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:227
+#: spyder/plugins/profiler/widgets/profilergui.py:232
+msgid "Profiler output"
+msgstr "Saída do Profiler"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:251
+msgid "Profiling, please wait..."
+msgstr "Processando..."
+
+#: spyder/plugins/profiler/widgets/profilergui.py:343
+msgid "Sorting data, please wait..."
+msgstr "Ordenando dados..."
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Function/Module"
+msgstr "Função/Módulo"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Total Time"
+msgstr "Tempo Total"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Diff"
+msgstr "Diff"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Calls"
+msgstr "Chamadas"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Local Time"
+msgstr "Hora Local"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:391
+msgid "File:line"
+msgstr "Arquivo/Linha"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:565
+msgid "Function or module name"
+msgstr "Nome da função ou módulo"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:569
+msgid "Time in function (including sub-functions)"
+msgstr "Tempo decorrido na função (sub-funções incluídas)"
+#: spyder/plugins/profiler/widgets/profilergui.py:578
+msgid "Local time in function (not in sub-functions)"
+msgstr "Tempo decorrido na função (excluindo sub-funções)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:588
+msgid "Total number of calls (including recursion)"
+msgstr "Número total de chamadas (incluindo recursão)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:598
+msgid "File:line where function is defined"
+msgstr "Arquivo/Linha onde a função está definida"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:603
+msgid "recursion"
+msgstr "recursão"
#~ msgid "Global working directory"
#~ msgstr "Diretório de trabalho global"
diff --git a/spyder/locale/ru/LC_MESSAGES/spyder.mo b/spyder/locale/ru/LC_MESSAGES/spyder.mo
index d9ae37bd219..7ee0138f1b7 100644
Binary files a/spyder/locale/ru/LC_MESSAGES/spyder.mo and b/spyder/locale/ru/LC_MESSAGES/spyder.mo differ
diff --git a/spyder/locale/ru/LC_MESSAGES/spyder.po b/spyder/locale/ru/LC_MESSAGES/spyder.po
index ba2462a57a5..13f9529976c 100644
--- a/spyder/locale/ru/LC_MESSAGES/spyder.po
+++ b/spyder/locale/ru/LC_MESSAGES/spyder.po
@@ -1,15 +1,21 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR ORGANIZATION
-# FIRST AUTHOR , YEAR.
-# FULL NAME , 2014.
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+#
+# Spyder's Russian gettext translation file
+#
# Zgarbul Andrey , 2014.
#
msgid ""
msgstr ""
"Project-Id-Version: 3.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-02-19 11:56+-05\n"
-"PO-Revision-Date: 2018-02-20 20:55+0300\n"
+"POT-Creation-Date: 2018-11-13 11:49+-05\n"
+"PO-Revision-Date: 2018-11-15 12:37+0300\n"
"Last-Translator: Andrey Zgarbul \n"
"Language-Team: русский \n"
"Language: ru_RU\n"
@@ -17,53 +23,45 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
-"X-Generator: Poedit 1.8.7.1\n"
+"X-Generator: Poedit 2.0.6\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"X-Poedit-Basepath: ../../..\n"
"X-Poedit-SearchPath-0: .\n"
-#: spyder/app/mainwindow.py:134
+#: spyder/app/mainwindow.py:139
msgid "Initializing..."
msgstr "Инициализация..."
-#: spyder/app/mainwindow.py:238
+#: spyder/app/mainwindow.py:252
msgid "Python2 documentation"
msgstr "Документация Python2"
-#: spyder/app/mainwindow.py:240
+#: spyder/app/mainwindow.py:254
msgid "Python3 documentation"
msgstr "Документация Python3"
-#: spyder/app/mainwindow.py:242
+#: spyder/app/mainwindow.py:256
msgid "Numpy and Scipy documentation"
msgstr "Документация Numpy и Scipy"
-#: spyder/app/mainwindow.py:244
+#: spyder/app/mainwindow.py:258
msgid "Matplotlib documentation"
msgstr "Документация Matplotlib"
-#: spyder/app/mainwindow.py:247
-msgid "PyQt4 Reference Guide"
-msgstr "Справочное руководство по PyQt4"
-
-#: spyder/app/mainwindow.py:250
-msgid "PyQt4 API Reference"
-msgstr "Справка по API PyQt4"
-
-#: spyder/app/mainwindow.py:253
+#: spyder/app/mainwindow.py:261
msgid "PyQt5 Reference Guide"
msgstr "Справочное руководство по PyQt5"
-#: spyder/app/mainwindow.py:256
+#: spyder/app/mainwindow.py:264
msgid "PyQt5 API Reference"
msgstr "Справка по API PyQt5"
-#: spyder/app/mainwindow.py:258
+#: spyder/app/mainwindow.py:266
msgid "WinPython"
msgstr "WinPython"
-#: spyder/app/mainwindow.py:518
+#: spyder/app/mainwindow.py:525
msgid ""
"An error occurred while creating a socket needed by Spyder. Please, try to "
"run as an Administrator from cmd.exe the following command and then restart "
@@ -75,172 +73,172 @@ msgstr ""
"компьютер: \n"
"
netsh winsock reset
"
-#: spyder/app/mainwindow.py:550
+#: spyder/app/mainwindow.py:557
msgid "Close current pane"
msgstr "Закрыть текущую панель"
-#: spyder/app/mainwindow.py:555
+#: spyder/app/mainwindow.py:562
msgid "Lock panes"
msgstr "Закрепить панели"
-#: spyder/app/mainwindow.py:562
+#: spyder/app/mainwindow.py:569
msgid "Use next layout"
msgstr "Исп. следующую компоновку"
-#: spyder/app/mainwindow.py:566
+#: spyder/app/mainwindow.py:573
msgid "Use previous layout"
msgstr "Исп. предыдущую компоновку"
-#: spyder/app/mainwindow.py:576 spyder/widgets/editor.py:497
+#: spyder/app/mainwindow.py:583 spyder/widgets/editor.py:507
msgid "File switcher..."
msgstr "Переключение по файлам..."
-#: spyder/app/mainwindow.py:578
+#: spyder/app/mainwindow.py:585
msgid "Fast switch between files"
msgstr "Быстрое переключение между файлами"
-#: spyder/app/mainwindow.py:584
+#: spyder/app/mainwindow.py:591
msgid "Symbol finder..."
msgstr "Поиск символов..."
-#: spyder/app/mainwindow.py:586
+#: spyder/app/mainwindow.py:593
msgid "Fast symbol search in file"
msgstr "Быстрый поиск в файле"
-#: spyder/app/mainwindow.py:605 spyder/widgets/sourcecode/codeeditor.py:2673
+#: spyder/app/mainwindow.py:612 spyder/widgets/sourcecode/codeeditor.py:2680
msgid "Undo"
msgstr "Отменить"
-#: spyder/app/mainwindow.py:607 spyder/widgets/sourcecode/codeeditor.py:2676
+#: spyder/app/mainwindow.py:614 spyder/widgets/sourcecode/codeeditor.py:2683
msgid "Redo"
msgstr "Вернуть"
-#: spyder/app/mainwindow.py:609 spyder/widgets/shell.py:123
-#: spyder/widgets/sourcecode/codeeditor.py:2682
-#: spyder/widgets/variableexplorer/arrayeditor.py:467
-#: spyder/widgets/variableexplorer/collectionseditor.py:674
-#: spyder/widgets/variableexplorer/dataframeeditor.py:592
+#: spyder/app/mainwindow.py:616 spyder/widgets/shell.py:123
+#: spyder/widgets/sourcecode/codeeditor.py:2689
+#: spyder/widgets/variableexplorer/arrayeditor.py:465
+#: spyder/widgets/variableexplorer/collectionseditor.py:710
+#: spyder/widgets/variableexplorer/dataframeeditor.py:616
msgid "Copy"
msgstr "Копировать"
-#: spyder/app/mainwindow.py:611 spyder/widgets/shell.py:119
-#: spyder/widgets/sourcecode/codeeditor.py:2679
+#: spyder/app/mainwindow.py:618 spyder/widgets/shell.py:119
+#: spyder/widgets/sourcecode/codeeditor.py:2686
msgid "Cut"
msgstr "Вырезать"
-#: spyder/app/mainwindow.py:613 spyder/widgets/shell.py:127
-#: spyder/widgets/sourcecode/codeeditor.py:2685
-#: spyder/widgets/variableexplorer/collectionseditor.py:671
+#: spyder/app/mainwindow.py:620 spyder/widgets/shell.py:127
+#: spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/widgets/variableexplorer/collectionseditor.py:707
msgid "Paste"
msgstr "Вставить"
-#: spyder/app/mainwindow.py:616 spyder/widgets/shell.py:140
-#: spyder/widgets/sourcecode/codeeditor.py:2688
+#: spyder/app/mainwindow.py:623 spyder/widgets/shell.py:140
+#: spyder/widgets/sourcecode/codeeditor.py:2695
msgid "Select All"
msgstr "Выделить всё"
-#: spyder/app/mainwindow.py:626 spyder/plugins/editor.py:1422
+#: spyder/app/mainwindow.py:633 spyder/plugins/editor.py:1421
msgid "&File"
msgstr "&Файл"
-#: spyder/app/mainwindow.py:627 spyder/plugins/editor.py:1410
+#: spyder/app/mainwindow.py:634 spyder/plugins/editor.py:1409
msgid "File toolbar"
msgstr "Панель файлов"
-#: spyder/app/mainwindow.py:631 spyder/plugins/editor.py:1423
+#: spyder/app/mainwindow.py:638 spyder/plugins/editor.py:1422
msgid "&Edit"
msgstr "&Правка"
-#: spyder/app/mainwindow.py:632 spyder/plugins/editor.py:1420
+#: spyder/app/mainwindow.py:639 spyder/plugins/editor.py:1419
msgid "Edit toolbar"
msgstr "Панель правки"
-#: spyder/app/mainwindow.py:636 spyder/plugins/editor.py:1424
+#: spyder/app/mainwindow.py:643 spyder/plugins/editor.py:1423
msgid "&Search"
msgstr "П&оиск"
-#: spyder/app/mainwindow.py:637 spyder/plugins/editor.py:1412
+#: spyder/app/mainwindow.py:644 spyder/plugins/editor.py:1411
msgid "Search toolbar"
msgstr "Панель поиска"
-#: spyder/app/mainwindow.py:641 spyder/plugins/editor.py:1425
+#: spyder/app/mainwindow.py:648 spyder/plugins/editor.py:1424
msgid "Sour&ce"
msgstr "&Документ"
-#: spyder/app/mainwindow.py:642 spyder/plugins/editor.py:1414
+#: spyder/app/mainwindow.py:649 spyder/plugins/editor.py:1413
msgid "Source toolbar"
msgstr "Панель кода"
-#: spyder/app/mainwindow.py:646 spyder/plugins/editor.py:803
-#: spyder/plugins/editor.py:1426
+#: spyder/app/mainwindow.py:653 spyder/plugins/editor.py:803
+#: spyder/plugins/editor.py:1425
msgid "&Run"
msgstr "&Запуск"
-#: spyder/app/mainwindow.py:647 spyder/plugins/editor.py:1416
+#: spyder/app/mainwindow.py:654 spyder/plugins/editor.py:1415
msgid "Run toolbar"
msgstr "Панель запуска"
-#: spyder/app/mainwindow.py:651 spyder/plugins/editor.py:762
+#: spyder/app/mainwindow.py:658 spyder/plugins/editor.py:762
msgid "&Debug"
msgstr "&Отладка"
-#: spyder/app/mainwindow.py:652 spyder/plugins/editor.py:1418
+#: spyder/app/mainwindow.py:659 spyder/plugins/editor.py:1417
msgid "Debug toolbar"
msgstr "Панель отладки"
-#: spyder/app/mainwindow.py:656
+#: spyder/app/mainwindow.py:663
msgid "C&onsoles"
msgstr "&Консоли"
-#: spyder/app/mainwindow.py:659
+#: spyder/app/mainwindow.py:666
msgid "&Projects"
msgstr "&Проекты"
-#: spyder/app/mainwindow.py:662 spyder/plugins/editor.py:1427
+#: spyder/app/mainwindow.py:669 spyder/plugins/editor.py:1426
msgid "&Tools"
msgstr "&Инструменты"
-#: spyder/app/mainwindow.py:665 spyder/plugins/editor.py:1428
+#: spyder/app/mainwindow.py:672 spyder/plugins/editor.py:1427
msgid "&View"
msgstr "&Вид"
-#: spyder/app/mainwindow.py:668 spyder/plugins/editor.py:1429
+#: spyder/app/mainwindow.py:675 spyder/plugins/editor.py:1428
msgid "&Help"
msgstr "Спр&авка"
-#: spyder/app/mainwindow.py:673
+#: spyder/app/mainwindow.py:680
msgid "Welcome to Spyder!"
msgstr "Добро пожаловать в Spyder!"
-#: spyder/app/mainwindow.py:678
+#: spyder/app/mainwindow.py:685
msgid "Pre&ferences"
msgstr "&Параметры"
-#: spyder/app/mainwindow.py:685 spyder/widgets/pathmanager.py:53
+#: spyder/app/mainwindow.py:692 spyder/widgets/pathmanager.py:54
msgid "PYTHONPATH manager"
msgstr "Менеджер PYTHONPATH"
-#: spyder/app/mainwindow.py:688
+#: spyder/app/mainwindow.py:695
msgid "Python Path Manager"
msgstr "Менеджер путей Python"
-#: spyder/app/mainwindow.py:691
+#: spyder/app/mainwindow.py:698
msgid "Update module names list"
msgstr "Обновить список модулей"
-#: spyder/app/mainwindow.py:694
+#: spyder/app/mainwindow.py:701
msgid "Refresh list of module names available in PYTHONPATH"
msgstr "Обновить список имён модулей, доступных в PYTHONPATH"
-#: spyder/app/mainwindow.py:697
+#: spyder/app/mainwindow.py:704
msgid "Reset Spyder to factory defaults"
msgstr "Вернуть Spyder к заводским настройкам"
-#: spyder/app/mainwindow.py:702
+#: spyder/app/mainwindow.py:709
msgid "Current user environment variables..."
msgstr "Переменные cреды текущего пользователя..."
-#: spyder/app/mainwindow.py:704
+#: spyder/app/mainwindow.py:711
msgid ""
"Show and edit current user environment variables in Windows registry (i.e. "
"for all sessions)"
@@ -248,51 +246,43 @@ msgstr ""
"Показывать и редактировать переменные среды в реестре Windows (т.е. для всех "
"сессий)"
-#: spyder/app/mainwindow.py:713 spyder/app/mainwindow.py:1137
+#: spyder/app/mainwindow.py:720 spyder/app/mainwindow.py:1115
msgid "External Tools"
msgstr "Внешние инструменты"
-#: spyder/app/mainwindow.py:716
+#: spyder/app/mainwindow.py:723
msgid "WinPython control panel"
-msgstr "контрольная панель WinPython"
+msgstr "Контрольная панель WinPython"
-#: spyder/app/mainwindow.py:725
+#: spyder/app/mainwindow.py:733
msgid "Qt Designer"
msgstr "Qt дизайнер"
-#: spyder/app/mainwindow.py:730
+#: spyder/app/mainwindow.py:737
msgid "Qt Linguist"
msgstr "Qt Linguist"
-#: spyder/app/mainwindow.py:736
-msgid "Qt examples"
-msgstr "Примеры Qt"
-
-#: spyder/app/mainwindow.py:756
+#: spyder/app/mainwindow.py:758
msgid "guidata examples"
msgstr "примеры guidata"
-#: spyder/app/mainwindow.py:767
+#: spyder/app/mainwindow.py:769
msgid "guiqwt examples"
msgstr "примеры guiqwt"
-#: spyder/app/mainwindow.py:772
+#: spyder/app/mainwindow.py:774
msgid "Sift"
msgstr "Sift"
-#: spyder/app/mainwindow.py:782
-msgid "ViTables"
-msgstr "ViTables"
-
-#: spyder/app/mainwindow.py:796
+#: spyder/app/mainwindow.py:792
msgid "Fullscreen mode"
msgstr "Полноэкранный режим"
-#: spyder/app/mainwindow.py:808
+#: spyder/app/mainwindow.py:804
msgid "Main toolbar"
msgstr "Главная панель"
-#: spyder/app/mainwindow.py:817
+#: spyder/app/mainwindow.py:813
msgid ""
"Spyder Internal Console\n"
"\n"
@@ -314,167 +304,172 @@ msgstr ""
"Пожалуйста, не используйте её для\n"
"запуска своего кода\n"
-#: spyder/app/mainwindow.py:834
+#: spyder/app/mainwindow.py:830
msgid "Loading help..."
msgstr "Загрузка справки..."
-#: spyder/app/mainwindow.py:841
+#: spyder/app/mainwindow.py:837
msgid "Loading outline explorer..."
msgstr "Загузка менеджера структуры..."
-#: spyder/app/mainwindow.py:847
+#: spyder/app/mainwindow.py:843
msgid "Loading editor..."
msgstr "Загрузка редактора..."
-#: spyder/app/mainwindow.py:853 spyder/plugins/console.py:141
-#: spyder/widgets/ipythonconsole/client.py:414
+#: spyder/app/mainwindow.py:849 spyder/plugins/console.py:141
+#: spyder/widgets/ipythonconsole/client.py:453
msgid "&Quit"
msgstr "В&ыход"
-#: spyder/app/mainwindow.py:855 spyder/plugins/console.py:143
+#: spyder/app/mainwindow.py:851 spyder/plugins/console.py:143
msgid "Quit"
msgstr "Выход"
-#: spyder/app/mainwindow.py:859
+#: spyder/app/mainwindow.py:855
msgid "&Restart"
msgstr "Пе&резапуск"
-#: spyder/app/mainwindow.py:861
+#: spyder/app/mainwindow.py:857
msgid "Restart"
msgstr "Перезапуск"
-#: spyder/app/mainwindow.py:875
+#: spyder/app/mainwindow.py:871
msgid "Loading file explorer..."
msgstr "Загрузка менеджера файлов..."
-#: spyder/app/mainwindow.py:882
+#: spyder/app/mainwindow.py:878
msgid "Loading history plugin..."
msgstr "Загрузка модуля истории..."
-#: spyder/app/mainwindow.py:893
+#: spyder/app/mainwindow.py:889
msgid "Loading online help..."
msgstr "Загрузка онлайн-помощи..."
-#: spyder/app/mainwindow.py:898
+#: spyder/app/mainwindow.py:894
msgid "Loading project explorer..."
msgstr "Загрузка менеджера проектов..."
-#: spyder/app/mainwindow.py:911
+#: spyder/app/mainwindow.py:907
msgid "Loading namespace browser..."
msgstr "Загрузка менеджера пространств имён..."
-#: spyder/app/mainwindow.py:917
+#: spyder/app/mainwindow.py:913
msgid "Loading IPython console..."
msgstr "Загрузка консоли IPython..."
-#: spyder/app/mainwindow.py:922
+#: spyder/app/mainwindow.py:918
msgid "Setting up main window..."
msgstr "Создание главного окна..."
-#: spyder/app/mainwindow.py:926
+#: spyder/app/mainwindow.py:922
msgid "Troubleshooting..."
msgstr "Устранение ошибок..."
-#: spyder/app/mainwindow.py:928
+#: spyder/app/mainwindow.py:924
msgid "Dependencies..."
msgstr "Зависимости..."
-#: spyder/app/mainwindow.py:932
+#: spyder/app/mainwindow.py:928
msgid "Report issue..."
msgstr "Отправить отчёт о проблеме..."
-#: spyder/app/mainwindow.py:936
+#: spyder/app/mainwindow.py:932
msgid "Spyder support..."
msgstr "Поддержка Spyder..."
-#: spyder/app/mainwindow.py:939
+#: spyder/app/mainwindow.py:935
msgid "Check for updates..."
msgstr "Проверить обновления..."
-#: spyder/app/mainwindow.py:962
+#: spyder/app/mainwindow.py:940
msgid "Spyder documentation"
msgstr "Документация Spyder"
-#: spyder/app/mainwindow.py:970
+#: spyder/app/mainwindow.py:948
msgid "Spyder tutorial"
msgstr "Руководство Spyder"
-#: spyder/app/mainwindow.py:975
+#: spyder/app/mainwindow.py:953
msgid "Shortcuts Summary"
msgstr "Перечень комбинаций клавиш"
-#: spyder/app/mainwindow.py:981
+#: spyder/app/mainwindow.py:959
msgid "Interactive tours"
msgstr "Интерактивные туры"
-#: spyder/app/mainwindow.py:1008
+#: spyder/app/mainwindow.py:986
msgid "Python documentation"
msgstr "Документация Python"
-#: spyder/app/mainwindow.py:1014
+#: spyder/app/mainwindow.py:992
msgid "IPython documentation"
msgstr "Документация IPython"
-#: spyder/app/mainwindow.py:1015
+#: spyder/app/mainwindow.py:993
msgid "Intro to IPython"
msgstr "Введение в IPython"
-#: spyder/app/mainwindow.py:1017
+#: spyder/app/mainwindow.py:995
msgid "Quick reference"
msgstr "Краткий справочник"
-#: spyder/app/mainwindow.py:1019
+#: spyder/app/mainwindow.py:997
msgid "Console help"
msgstr "Консольная справка"
-#: spyder/app/mainwindow.py:1049
+#: spyder/app/mainwindow.py:1027
msgid "Installed Python modules"
msgstr "Установленные модули Python"
-#: spyder/app/mainwindow.py:1053
+#: spyder/app/mainwindow.py:1031
msgid "Online documentation"
msgstr "Онлайн документация"
-#: spyder/app/mainwindow.py:1066
+#: spyder/app/mainwindow.py:1044
msgid "Qt documentation"
msgstr "Документация Qt"
-#: spyder/app/mainwindow.py:1072
+#: spyder/app/mainwindow.py:1050
msgid "About %s..."
msgstr "О %s..."
-#: spyder/app/mainwindow.py:1103
+#: spyder/app/mainwindow.py:1081
msgid "Panes"
msgstr "Плавающие окна"
-#: spyder/app/mainwindow.py:1105
+#: spyder/app/mainwindow.py:1083
msgid "Toolbars"
msgstr "Панели инструментов"
-#: spyder/app/mainwindow.py:1106
+#: spyder/app/mainwindow.py:1084
msgid "Window layouts"
msgstr "Компоновка окон"
-#: spyder/app/mainwindow.py:1115 spyder/app/mainwindow.py:1943
-#: spyder/app/mainwindow.py:1944
+#: spyder/app/mainwindow.py:1093 spyder/app/mainwindow.py:1920
+#: spyder/app/mainwindow.py:1921
msgid "Show toolbars"
msgstr "Показывать панели инструментов"
-#: spyder/app/mainwindow.py:1130
+#: spyder/app/mainwindow.py:1108
msgid "Attached console window (debugging)"
msgstr "Прикреплённая консоль (отладка)"
-#: spyder/app/mainwindow.py:1322 spyder/plugins/projects.py:254
-#: spyder/widgets/explorer.py:721 spyder/widgets/explorer.py:826
-#: spyder/widgets/variableexplorer/arrayeditor.py:587
-#: spyder/widgets/variableexplorer/collectionseditor.py:427
-#: spyder/widgets/variableexplorer/dataframeeditor.py:758
-#: spyder/widgets/variableexplorer/dataframeeditor.py:762
-#: spyder/widgets/variableexplorer/namespacebrowser.py:299
+#: spyder/app/mainwindow.py:1298 spyder/app/mainwindow.py:1988
+#: spyder/plugins/configdialog.py:1154 spyder/plugins/projects.py:269
+#: spyder/widgets/explorer.py:723 spyder/widgets/explorer.py:828
+#: spyder/widgets/reporterror.py:285
+#: spyder/widgets/variableexplorer/arrayeditor.py:586
+#: spyder/widgets/variableexplorer/collectionseditor.py:460
+#: spyder/widgets/variableexplorer/dataframeeditor.py:797
+#: spyder/plugins/pylint/widgets/pylintgui.py:128
+#: spyder/widgets/variableexplorer/namespacebrowser.py:311
+#: spyder/plugins/pylint/widgets/pylintgui.py:363
+#: spyder/plugins/pylint/widgets/pylintgui.py:391
+#: spyder/plugins/profiler/widgets/profilergui.py:295
msgid "Error"
msgstr "Ошибка"
-#: spyder/app/mainwindow.py:1323
+#: spyder/app/mainwindow.py:1299
msgid ""
"You have missing dependencies!
%s
Please "
"install them to avoid this message.
Note: Spyder could "
@@ -494,38 +489,41 @@ msgstr ""
"найденные ошибки не являются прямым результатот отсутствия некоторых "
"зависимостей."
-#: spyder/app/mainwindow.py:1779
+#: spyder/app/mainwindow.py:1756
msgid "Spyder Default Layout"
msgstr "Стандартная компоновка Spyder"
-#: spyder/app/mainwindow.py:1797
+#: spyder/app/mainwindow.py:1774
msgid "Save current layout"
msgstr "Сохранить текущую компоновку"
-#: spyder/app/mainwindow.py:1801
+#: spyder/app/mainwindow.py:1778
msgid "Layout preferences"
msgstr "Параметры компоновки"
-#: spyder/app/mainwindow.py:1805
+#: spyder/app/mainwindow.py:1782
msgid "Reset to spyder default"
msgstr "Вернуть компоновку по умолчанию"
-#: spyder/app/mainwindow.py:1825 spyder/app/mainwindow.py:1847
-#: spyder/app/mainwindow.py:1913 spyder/app/mainwindow.py:1921
-#: spyder/app/mainwindow.py:2799 spyder/plugins/configdialog.py:1345
-#: spyder/plugins/ipythonconsole.py:131 spyder/plugins/ipythonconsole.py:927
-#: spyder/plugins/ipythonconsole.py:1386 spyder/plugins/maininterpreter.py:149
-#: spyder/plugins/maininterpreter.py:174 spyder/plugins/maininterpreter.py:203
-#: spyder/utils/environ.py:95 spyder/utils/environ.py:108
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:131
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:149
-#: spyder/widgets/variableexplorer/arrayeditor.py:510
-#: spyder/widgets/variableexplorer/collectionseditor.py:416
-#: spyder/widgets/variableexplorer/collectionseditor.py:1095
+#: spyder/app/mainwindow.py:1802 spyder/app/mainwindow.py:1824
+#: spyder/app/mainwindow.py:1890 spyder/app/mainwindow.py:1898
+#: spyder/app/mainwindow.py:2843 spyder/plugins/configdialog.py:1415
+#: spyder/plugins/ipythonconsole.py:134 spyder/plugins/ipythonconsole.py:987
+#: spyder/plugins/ipythonconsole.py:1439 spyder/plugins/maininterpreter.py:162
+#: spyder/plugins/maininterpreter.py:183 spyder/plugins/maininterpreter.py:212
+#: spyder/utils/environ.py:56 spyder/utils/environ.py:107
+#: spyder/utils/environ.py:120
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:140
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:158
+#: spyder/widgets/variableexplorer/arrayeditor.py:508
+#: spyder/widgets/variableexplorer/collectionseditor.py:449
+#: spyder/plugins/pylint/widgets/pylintgui.py:126
+#: spyder/widgets/variableexplorer/collectionseditor.py:1143
+#: spyder/widgets/variableexplorer/namespacebrowser.py:305
msgid "Warning"
msgstr "Предупреждение"
-#: spyder/app/mainwindow.py:1826
+#: spyder/app/mainwindow.py:1803
msgid ""
"Window layout will be reset to default settings: this affects window "
"position, size and dockwidgets.\n"
@@ -535,14 +533,14 @@ msgstr ""
"размере и объединении окон.\n"
"Хотите продолжить?"
-#: spyder/app/mainwindow.py:1848
+#: spyder/app/mainwindow.py:1825
msgid ""
"Layout %s will be "
"overwritten. Do you want to "
"continue?"
msgstr "Компоновка %s будет перезаписана. Хотите продолжить?"
-#: spyder/app/mainwindow.py:1914
+#: spyder/app/mainwindow.py:1891
msgid ""
"Error opening the custom layout. Please close Spyder and try again. If the "
"issue persists, then you must use 'Reset to Spyder default' from the layout "
@@ -552,42 +550,50 @@ msgstr ""
"повторите. Если проблема не устранилась, используйте 'Вернуть компоновку по "
"умолчанию' из меню."
-#: spyder/app/mainwindow.py:1922
+#: spyder/app/mainwindow.py:1899
msgid "Quick switch layout #%s has not yet been defined."
msgstr "Быстрое переключение компоновки #%s не было определено."
-#: spyder/app/mainwindow.py:1940 spyder/app/mainwindow.py:1941
+#: spyder/app/mainwindow.py:1917 spyder/app/mainwindow.py:1918
msgid "Hide toolbars"
msgstr "Скрыть панели инструментов"
-#: spyder/app/mainwindow.py:2256 spyder/app/mainwindow.py:2257
+#: spyder/app/mainwindow.py:1989
+msgid ""
+"{} is no longer a valid Spyder project! Since it is the current "
+"active project, it will be closed automatically."
+msgstr ""
+"{} - больше не корректный проект Spyder! Так как это текущий активный "
+"проект, он будет закрыт автоматически."
+
+#: spyder/app/mainwindow.py:2252 spyder/app/mainwindow.py:2253
msgid "Maximize current pane"
msgstr "Развернуть текущую панель"
-#: spyder/app/mainwindow.py:2260
+#: spyder/app/mainwindow.py:2256
msgid "Restore current pane"
msgstr "Восстановить текущую панель"
-#: spyder/app/mainwindow.py:2261
+#: spyder/app/mainwindow.py:2257
msgid "Restore pane to its original size"
msgstr "Вернуть панель к первоначальному размеру"
-#: spyder/app/mainwindow.py:2359
+#: spyder/app/mainwindow.py:2439
msgid "About %s"
msgstr "О %s"
-#: spyder/app/mainwindow.py:2538 spyder/plugins/editor.py:168
+#: spyder/app/mainwindow.py:2579 spyder/plugins/editor.py:168
#: spyder/plugins/runconfig.py:354 spyder/plugins/runconfig.py:476
-#: spyder/utils/programs.py:286 spyder/widgets/explorer.py:344
+#: spyder/utils/programs.py:307 spyder/widgets/explorer.py:347
msgid "Run"
msgstr "Запуск"
-#: spyder/app/mainwindow.py:2539
+#: spyder/app/mainwindow.py:2580
msgid "Running an external system terminal is not supported on platform %s."
msgstr ""
"Запуск внешнего системного терминала не поддерживается на платформе %s."
-#: spyder/app/mainwindow.py:2800
+#: spyder/app/mainwindow.py:2844
msgid ""
"Spyder will restart and reset to default settings:
Do you want to "
"continue?"
@@ -595,15 +601,15 @@ msgstr ""
"Spyder будет перезапущен, настройки возвращены по умолчанию:
Хотите "
"продолжить?"
-#: spyder/app/mainwindow.py:2928 spyder/widgets/helperwidgets.py:254
+#: spyder/app/mainwindow.py:2973 spyder/widgets/helperwidgets.py:254
msgid "Spyder updates"
msgstr "Обновления Spyder"
-#: spyder/app/mainwindow.py:2929 spyder/plugins/configdialog.py:835
+#: spyder/app/mainwindow.py:2974 spyder/plugins/configdialog.py:888
msgid "Check for updates on startup"
msgstr "Проверять обновления при старте"
-#: spyder/app/mainwindow.py:2948
+#: spyder/app/mainwindow.py:2993
msgid ""
"
IMPORTANT NOTE: It seems that you are using Spyder with "
"Anaconda/Miniconda. Please don't use pip
to "
@@ -617,7 +623,7 @@ msgstr ""
"этого, пожалуйста, дождитесь выхода новых пакетов и используйте conda"
"code> для установки обновлений.
"
-#: spyder/app/mainwindow.py:2958
+#: spyder/app/mainwindow.py:3003
msgid ""
"Spyder %s is available!
Please use your package manager to "
"update Spyder or go to our Releases page to download this "
@@ -629,7 +635,7 @@ msgstr ""
"загрузки новой версии.
Если Вы не уверены, как произвести обновление "
"Spyder, ознакомьтесь с нашими инструкциями по Установке."
-#: spyder/app/mainwindow.py:2971
+#: spyder/app/mainwindow.py:3016
msgid "Spyder is up to date."
msgstr "Spyder обновлён."
@@ -761,8 +767,8 @@ msgstr ""
"шаге тура. Двойным щелчком на любом из них открывается окно, где можно "
"тщательно изучить и изменить содержимое."
-#: spyder/app/tour.py:179 spyder/plugins/help.py:484 spyder/plugins/help.py:937
-#: spyder/widgets/internalshell.py:270
+#: spyder/app/tour.py:179 spyder/plugins/help.py:482 spyder/plugins/help.py:931
+#: spyder/widgets/internalshell.py:271
msgid "Help"
msgstr "Справка"
@@ -828,216 +834,213 @@ msgstr "Обучающий тур"
msgid "New features in version 3.0"
msgstr "Новые возможности в версии 3.0"
-#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:446
+#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:474
msgid "Run code"
msgstr "Выполнить код"
#: spyder/app/tour.py:830
msgid "Go to step: "
-msgstr "Перейти к шагу:"
-
-#: spyder/config/base.py:269
-msgid ""
-"Update LANGUAGE_CODES (inside config/base.py) if a new translation has been "
-"added to Spyder"
-msgstr ""
-"Обновите LANGUAGE_CODES (в файле config/base.py) если добавили новый перевод "
-"в Spyder"
+msgstr "Перейти к шагу: "
-#: spyder/config/utils.py:24
+#: spyder/config/utils.py:24 spyder/plugins/pylint/widgets/pylintgui.py:289
msgid "Python files"
msgstr "Файлы Python"
-#: spyder/config/utils.py:25
+#: spyder/config/utils.py:26
msgid "Cython/Pyrex files"
msgstr "Файлы Cython/Pyrex"
-#: spyder/config/utils.py:26
+#: spyder/config/utils.py:27
msgid "C files"
msgstr "Файлы C"
-#: spyder/config/utils.py:27
+#: spyder/config/utils.py:28
msgid "C++ files"
msgstr "Файлы C++"
-#: spyder/config/utils.py:28
+#: spyder/config/utils.py:29
msgid "OpenCL files"
msgstr "Файлы OpenCL"
-#: spyder/config/utils.py:29
+#: spyder/config/utils.py:30
msgid "Fortran files"
msgstr "Файлы Fortran"
-#: spyder/config/utils.py:30
+#: spyder/config/utils.py:31
msgid "IDL files"
msgstr "Файлы IDL"
-#: spyder/config/utils.py:31
+#: spyder/config/utils.py:32
msgid "MATLAB files"
msgstr "Файлы MATLAB"
-#: spyder/config/utils.py:32
+#: spyder/config/utils.py:33
msgid "Julia files"
msgstr "Файлы Julia"
-#: spyder/config/utils.py:33
+#: spyder/config/utils.py:34
msgid "Yaml files"
msgstr "Файлы Yaml"
-#: spyder/config/utils.py:34
+#: spyder/config/utils.py:35
msgid "Patch and diff files"
msgstr "Файлы патчей и diff"
-#: spyder/config/utils.py:35
+#: spyder/config/utils.py:36
msgid "Batch files"
msgstr "Файлы Batch"
-#: spyder/config/utils.py:36 spyder/utils/iofuncs.py:426
+#: spyder/config/utils.py:37
msgid "Text files"
msgstr "Текстовые файлы"
-#: spyder/config/utils.py:37
+#: spyder/config/utils.py:38
msgid "reStructuredText files"
msgstr "Файлы reStructuredText"
-#: spyder/config/utils.py:38
+#: spyder/config/utils.py:39
msgid "gettext files"
msgstr "Файлы gettext"
-#: spyder/config/utils.py:39
+#: spyder/config/utils.py:40
msgid "NSIS files"
msgstr "Файлы NSIS"
-#: spyder/config/utils.py:40
+#: spyder/config/utils.py:41
msgid "Web page files"
msgstr "Файлы Веб-страниц"
-#: spyder/config/utils.py:41
+#: spyder/config/utils.py:42
msgid "XML files"
msgstr "Файлы XML"
-#: spyder/config/utils.py:42
+#: spyder/config/utils.py:43
msgid "Javascript files"
msgstr "Файлы Javascript"
-#: spyder/config/utils.py:43
+#: spyder/config/utils.py:44
msgid "Json files"
msgstr "Файлы Json"
-#: spyder/config/utils.py:44
+#: spyder/config/utils.py:45
msgid "IPython notebooks"
msgstr "Блокноты IPython"
-#: spyder/config/utils.py:45
+#: spyder/config/utils.py:46
msgid "Enaml files"
msgstr "Файлы Enaml"
-#: spyder/config/utils.py:46
+#: spyder/config/utils.py:47
msgid "Configuration files"
msgstr "Файлы настроек"
-#: spyder/config/utils.py:48
+#: spyder/config/utils.py:49
msgid "Markdown files"
msgstr "Файлы Markdown"
-#: spyder/config/utils.py:52 spyder/widgets/explorer.py:794
+#: spyder/config/utils.py:53 spyder/widgets/explorer.py:796
msgid "All files"
msgstr "Все файлы"
-#: spyder/config/utils.py:134
+#: spyder/config/utils.py:138
msgid "Supported text files"
msgstr "Поддерживаемые текстовые файлы"
-#: spyder/plugins/__init__.py:511 spyder/plugins/editor.py:105
-#: spyder/plugins/editor.py:568 spyder/plugins/editor.py:1816
-#: spyder/plugins/help.py:117 spyder/plugins/help.py:385
-#: spyder/widgets/editor.py:534 spyder/widgets/sourcecode/codeeditor.py:98
-#: spyder/widgets/sourcecode/codeeditor.py:3222
+#: spyder/plugins/__init__.py:512 spyder/plugins/editor.py:105
+#: spyder/plugins/editor.py:568 spyder/plugins/editor.py:1830
+#: spyder/plugins/help.py:117 spyder/plugins/help.py:383
+#: spyder/widgets/editor.py:544 spyder/widgets/sourcecode/codeeditor.py:98
+#: spyder/widgets/sourcecode/codeeditor.py:3229
msgid "Editor"
msgstr "Редактор"
-#: spyder/plugins/configdialog.py:144
+#: spyder/plugins/configdialog.py:146
msgid "Reset to defaults"
msgstr "Восстановить значения по умолчанию"
-#: spyder/plugins/configdialog.py:156
+#: spyder/plugins/configdialog.py:158
msgid "Preferences"
msgstr "Параметры"
-#: spyder/plugins/configdialog.py:508
+#: spyder/plugins/configdialog.py:514
msgid "Invalid directory path"
msgstr "Неверный путь каталога"
-#: spyder/plugins/configdialog.py:511 spyder/plugins/configdialog.py:526
+#: spyder/plugins/configdialog.py:517 spyder/plugins/configdialog.py:532
#: spyder/plugins/runconfig.py:220 spyder/plugins/runconfig.py:268
-#: spyder/plugins/workingdirectory.py:240 spyder/widgets/explorer.py:705
-#: spyder/widgets/findinfiles.py:332 spyder/widgets/pathmanager.py:258
+#: spyder/plugins/workingdirectory.py:241 spyder/widgets/explorer.py:707
+#: spyder/widgets/findinfiles.py:347 spyder/widgets/pathmanager.py:259
#: spyder/widgets/projects/projectdialog.py:155
msgid "Select directory"
msgstr "Выберите каталог"
-#: spyder/plugins/configdialog.py:538
+#: spyder/plugins/configdialog.py:544 spyder/plugins/configdialog.py:704
msgid "Invalid file path"
msgstr "Неверный путь файла"
-#: spyder/plugins/configdialog.py:541 spyder/plugins/configdialog.py:558
+#: spyder/plugins/configdialog.py:547 spyder/plugins/configdialog.py:564
+#: spyder/plugins/configdialog.py:707
msgid "Select file"
msgstr "Выберите файл"
-#: spyder/plugins/configdialog.py:557
+#: spyder/plugins/configdialog.py:563
msgid "All files (*)"
msgstr "Все файлы (*)"
-#: spyder/plugins/configdialog.py:630
+#: spyder/plugins/configdialog.py:636
msgid "Bold"
msgstr "Жирный"
-#: spyder/plugins/configdialog.py:633
+#: spyder/plugins/configdialog.py:639
msgid "Italic"
msgstr "Курсив"
-#: spyder/plugins/configdialog.py:687
+#: spyder/plugins/configdialog.py:728
msgid "Font: "
msgstr "Шрифт: "
-#: spyder/plugins/configdialog.py:693
+#: spyder/plugins/configdialog.py:734
msgid "Size: "
msgstr "Размер: "
-#: spyder/plugins/configdialog.py:712
+#: spyder/plugins/configdialog.py:753
msgid "Font style"
msgstr "Стиль шрифта"
-#: spyder/plugins/configdialog.py:789
+#: spyder/plugins/configdialog.py:830
msgid "Spyder needs to restart to change the following setting:"
msgstr "Необходим перезапуск Spyder для изменения параметра:"
-#: spyder/plugins/configdialog.py:792
+#: spyder/plugins/configdialog.py:833
msgid "Spyder needs to restart to change the following settings:"
msgstr "Необходим перезапуск Spyder для изменения настроек:"
-#: spyder/plugins/configdialog.py:794
+#: spyder/plugins/configdialog.py:835
msgid "Do you wish to restart now?"
msgstr "Хотите выполнить перезапуск сейчас?"
-#: spyder/plugins/configdialog.py:800
+#: spyder/plugins/configdialog.py:841
msgid "Information"
msgstr "Информация"
-#: spyder/plugins/configdialog.py:814 spyder/plugins/configdialog.py:821
+#: spyder/plugins/configdialog.py:855 spyder/plugins/configdialog.py:862
#: spyder/widgets/projects/configdialog.py:74
msgid "General"
msgstr "Основные"
-#: spyder/plugins/configdialog.py:824
-msgid "Language"
-msgstr "Язык"
+#: spyder/plugins/configdialog.py:866
+msgid "Language:"
+msgstr "Язык:"
+
+#: spyder/plugins/configdialog.py:874
+msgid "Rendering engine:"
+msgstr "Движок рендеринга:"
-#: spyder/plugins/configdialog.py:827
+#: spyder/plugins/configdialog.py:879
msgid "Use a single instance"
msgstr "Запускать только одну копию"
-#: spyder/plugins/configdialog.py:829
+#: spyder/plugins/configdialog.py:881
msgid ""
"Set this to open external
Python files in an already running instance "
"(Requires a restart)"
@@ -1045,90 +1048,90 @@ msgstr ""
"Отметьте для открытия внешних
файлов Python в уже запущенном окружении "
"(требуется перезапуск)"
-#: spyder/plugins/configdialog.py:832
+#: spyder/plugins/configdialog.py:885
msgid "Prompt when exiting"
msgstr "Спрашиваить подтверждение при закрытии"
-#: spyder/plugins/configdialog.py:833
+#: spyder/plugins/configdialog.py:886
msgid "Show internal Spyder errors to report them to Github"
msgstr "Показать внутренние ошибки Spyder для отправки на Github"
-#: spyder/plugins/configdialog.py:852 spyder/plugins/editor.py:114
-#: spyder/plugins/ipythonconsole.py:290
+#: spyder/plugins/configdialog.py:914 spyder/plugins/editor.py:114
+#: spyder/plugins/ipythonconsole.py:301
#: spyder/widgets/projects/configdialog.py:81
msgid "Interface"
msgstr "Интерфейс"
-#: spyder/plugins/configdialog.py:860
+#: spyder/plugins/configdialog.py:922
msgid "Qt windows style"
msgstr "Стиль окон Qt"
-#: spyder/plugins/configdialog.py:866
+#: spyder/plugins/configdialog.py:928
msgid "Icon theme"
msgstr "Тема значков"
-#: spyder/plugins/configdialog.py:870
+#: spyder/plugins/configdialog.py:932
msgid "Vertical title bars in panes"
msgstr "Названия плавающих окон - вертикально"
-#: spyder/plugins/configdialog.py:872
+#: spyder/plugins/configdialog.py:934
msgid "Vertical tabs in panes"
msgstr "Вертикальные вкладки на плавающих окнах"
-#: spyder/plugins/configdialog.py:874
+#: spyder/plugins/configdialog.py:936
msgid "Animated toolbars and panes"
msgstr "Анимировать панели инструментов и плавающие окна"
-#: spyder/plugins/configdialog.py:876
+#: spyder/plugins/configdialog.py:938
msgid "Tear off menus"
msgstr "Открепляемые меню"
-#: spyder/plugins/configdialog.py:877
+#: spyder/plugins/configdialog.py:939
msgid "Set this to detach any
menu from the main window"
msgstr "Отметьте для возможности отделить
любое меню от главного окна"
-#: spyder/plugins/configdialog.py:879
+#: spyder/plugins/configdialog.py:941
msgid "Custom margin for panes:"
msgstr "Настроить отступы панелей:"
-#: spyder/plugins/configdialog.py:881
+#: spyder/plugins/configdialog.py:943
msgid "pixels"
msgstr "пикселей"
-#: spyder/plugins/configdialog.py:888
+#: spyder/plugins/configdialog.py:950
msgid "Cursor blinking:"
msgstr "Мигание курсора:"
-#: spyder/plugins/configdialog.py:890
+#: spyder/plugins/configdialog.py:952
msgid "ms"
msgstr "мс"
-#: spyder/plugins/configdialog.py:929
+#: spyder/plugins/configdialog.py:991
msgid "Status bar"
msgstr "Панель состояния"
-#: spyder/plugins/configdialog.py:930
+#: spyder/plugins/configdialog.py:992
msgid "Show status bar"
msgstr "Показывать панель состояния"
-#: spyder/plugins/configdialog.py:932
+#: spyder/plugins/configdialog.py:994
msgid "Show memory usage every"
msgstr "Показывать использование памяти каждые"
-#: spyder/plugins/configdialog.py:934 spyder/plugins/configdialog.py:943
+#: spyder/plugins/configdialog.py:996 spyder/plugins/configdialog.py:1005
#: spyder/plugins/editor.py:139 spyder/plugins/editor.py:283
msgid " ms"
msgstr " мс"
-#: spyder/plugins/configdialog.py:941
+#: spyder/plugins/configdialog.py:1003
msgid "Show CPU usage every"
msgstr "Показывать загрузку ЦП каждые"
-#: spyder/plugins/configdialog.py:974
+#: spyder/plugins/configdialog.py:1036
msgid "Screen resolution"
msgstr "Разрешение экрана"
-#: spyder/plugins/configdialog.py:976
+#: spyder/plugins/configdialog.py:1038
msgid ""
"Configuration for high DPI screens
Please see {0}"
"a><> for more information about these options (in English)."
@@ -1136,28 +1139,28 @@ msgstr ""
"Настройки для экранов высокого разрешения
Больше о этих опциях можно "
"прочесть на {0}<> (на англ.)."
-#: spyder/plugins/configdialog.py:986
+#: spyder/plugins/configdialog.py:1048
msgid "Normal"
msgstr "Нормальное"
-#: spyder/plugins/configdialog.py:990
+#: spyder/plugins/configdialog.py:1052
msgid "Enable auto high DPI scaling"
msgstr "Включить автомасштабирование для high DPI"
-#: spyder/plugins/configdialog.py:993
+#: spyder/plugins/configdialog.py:1055
msgid "Set this for high DPI displays"
msgstr "Используется для мониторов с высоким разрешением"
-#: spyder/plugins/configdialog.py:997
+#: spyder/plugins/configdialog.py:1059
msgid "Set a custom high DPI scaling"
msgstr "Фиксированный масштаб для high DPI"
-#: spyder/plugins/configdialog.py:1000
+#: spyder/plugins/configdialog.py:1062
msgid "Set this for high DPI displays when auto scaling does not work"
msgstr ""
"Установить для экранов с высоким DPI, если автомасштабирование не работает"
-#: spyder/plugins/configdialog.py:1006
+#: spyder/plugins/configdialog.py:1068
msgid ""
"Enter values for different screens separated by semicolons ';', float values "
"are supported"
@@ -1165,31 +1168,39 @@ msgstr ""
"Введите значения для разных экранов, разденные точками с запятой ';', "
"вещественные числа поддерживаются"
-#: spyder/plugins/configdialog.py:1033
+#: spyder/plugins/configdialog.py:1095
msgid "Plain text font"
msgstr "Шрифт текста"
-#: spyder/plugins/configdialog.py:1039
+#: spyder/plugins/configdialog.py:1101
msgid "Rich text font"
msgstr "Шрифт форматированного текста"
-#: spyder/plugins/configdialog.py:1042
+#: spyder/plugins/configdialog.py:1104
msgid "Fonts"
msgstr "Шрифты"
-#: spyder/plugins/configdialog.py:1056
+#: spyder/plugins/configdialog.py:1118
msgid "Appearance"
msgstr "Внешний вид"
-#: spyder/plugins/configdialog.py:1058 spyder/plugins/ipythonconsole.py:579
+#: spyder/plugins/configdialog.py:1120 spyder/plugins/ipythonconsole.py:633
msgid "Advanced Settings"
msgstr "Расширенные настройки"
-#: spyder/plugins/configdialog.py:1094
+#: spyder/plugins/configdialog.py:1155
+msgid ""
+"We're sorry but the following error occurred while trying to set your "
+"selected language:
{}"
+msgstr ""
+"Во время попытки установить выбранный Вами язык произошла следующая ошибка:"
+"
{}"
+
+#: spyder/plugins/configdialog.py:1164
msgid "Syntax coloring"
msgstr "Подсветка синтаксиса"
-#: spyder/plugins/configdialog.py:1107
+#: spyder/plugins/configdialog.py:1177
msgid ""
"Here you can select the color scheme used in the Editor and all other Spyder "
"plugins.
You can also edit the color schemes provided by Spyder or "
@@ -1197,54 +1208,54 @@ msgid ""
msgstr ""
"Здесь можно выбрать цветовую схему, используемую в Редакторе и всех других "
"модулях Spyder.
Вы можете редактировать цветовые схемы, предлагаемые "
-"Spyder, или создать новую с помощью опций, приведённых ниже."
+"Spyder, или создать новую с помощью опций, приведённых ниже.
"
-#: spyder/plugins/configdialog.py:1112
+#: spyder/plugins/configdialog.py:1182
msgid "Edit selected"
msgstr "Редактировать выбранную"
-#: spyder/plugins/configdialog.py:1113
+#: spyder/plugins/configdialog.py:1183
msgid "Create new scheme"
msgstr "Создать новую схему"
-#: spyder/plugins/configdialog.py:1114 spyder/widgets/explorer.py:583
+#: spyder/plugins/configdialog.py:1184 spyder/widgets/explorer.py:582
#: spyder/widgets/projects/explorer.py:243 spyder/widgets/shell.py:136
msgid "Delete"
msgstr "Удалить"
-#: spyder/plugins/configdialog.py:1117
+#: spyder/plugins/configdialog.py:1187
msgid "Reset"
msgstr "Восстановить"
-#: spyder/plugins/configdialog.py:1124
+#: spyder/plugins/configdialog.py:1194
msgid "Scheme:"
-msgstr "Схема: "
+msgstr "Схема:"
-#: spyder/plugins/configdialog.py:1155
+#: spyder/plugins/configdialog.py:1225
msgid "Manage color schemes"
msgstr "Настроить цветовые схемы"
-#: spyder/plugins/configdialog.py:1346
+#: spyder/plugins/configdialog.py:1416
msgid "Are you sure you want to delete this scheme?"
msgstr "Вы уверены, что хотите удалить цветовую схему?"
-#: spyder/plugins/configdialog.py:1463
+#: spyder/plugins/configdialog.py:1533
msgid "Text"
msgstr "Текст"
-#: spyder/plugins/configdialog.py:1465
+#: spyder/plugins/configdialog.py:1535
msgid "Highlight"
msgstr "Подсветка"
-#: spyder/plugins/configdialog.py:1467
+#: spyder/plugins/configdialog.py:1537
msgid "Background"
msgstr "Фон"
-#: spyder/plugins/configdialog.py:1471
+#: spyder/plugins/configdialog.py:1541
msgid "Scheme name:"
msgstr "Название схемы:"
-#: spyder/plugins/configdialog.py:1478
+#: spyder/plugins/configdialog.py:1548
msgid "Color scheme editor"
msgstr "Редактор цветовой схемы"
@@ -1280,7 +1291,7 @@ msgstr "Показать (только чтение) sys.path"
msgid "Buffer..."
msgstr "Буфер..."
-#: spyder/plugins/console.py:163 spyder/plugins/history.py:43
+#: spyder/plugins/console.py:163 spyder/plugins/history.py:45
msgid "Set maximum line count"
msgstr "Установить максимальное число строк"
@@ -1293,13 +1304,13 @@ msgid "Set external editor executable path"
msgstr "Установить путь запуска внешнего редактора"
#: spyder/plugins/console.py:170 spyder/plugins/editor.py:149
-#: spyder/plugins/help.py:152 spyder/plugins/help.py:360
-#: spyder/plugins/history.py:46 spyder/plugins/history.py:157
+#: spyder/plugins/help.py:152 spyder/plugins/help.py:358
+#: spyder/plugins/history.py:48 spyder/plugins/history.py:159
msgid "Wrap lines"
msgstr "Переносить строки"
#: spyder/plugins/console.py:173 spyder/plugins/editor.py:185
-#: spyder/plugins/ipythonconsole.py:300
+#: spyder/plugins/ipythonconsole.py:311
msgid "Display balloon tips"
msgstr "Показывать всплывающие подсказки"
@@ -1319,7 +1330,8 @@ msgstr "Настройки встроенной консоли"
msgid "Run Python script"
msgstr "Запуск скрипта Python"
-#: spyder/plugins/console.py:266 spyder/widgets/explorer.py:809
+#: spyder/plugins/console.py:266 spyder/widgets/explorer.py:811
+#: spyder/plugins/profiler/widgets/profilergui.py:220
msgid "Python scripts"
msgstr "Скрипты Python"
@@ -1352,8 +1364,8 @@ msgid "Show tab bar"
msgstr "Показывать панель вкладок"
#: spyder/plugins/editor.py:122 spyder/plugins/editor.py:199
-#: spyder/plugins/help.py:151 spyder/plugins/history.py:45
-#: spyder/plugins/ipythonconsole.py:332
+#: spyder/plugins/help.py:151 spyder/plugins/history.py:47
+#: spyder/plugins/ipythonconsole.py:349
msgid "Source code"
msgstr "Исходный код"
@@ -1593,8 +1605,8 @@ msgstr ""
msgid "Fix automatically and show warning message box"
msgstr "Автоматически исправлять и показывать окно предупреждений"
-#: spyder/plugins/editor.py:357 spyder/plugins/ipythonconsole.py:573
-#: spyder/plugins/variableexplorer.py:35
+#: spyder/plugins/editor.py:357 spyder/plugins/ipythonconsole.py:627
+#: spyder/plugins/variableexplorer.py:47
msgid "Display"
msgstr "Отображение"
@@ -1608,10 +1620,10 @@ msgstr "Дополнительные настройки"
#: spyder/plugins/editor.py:644
msgid "&New file..."
-msgstr "&Новый файл"
+msgstr "&Новый файл..."
-#: spyder/plugins/editor.py:645 spyder/widgets/explorer.py:786
-#: spyder/widgets/explorer.py:793
+#: spyder/plugins/editor.py:645 spyder/widgets/explorer.py:788
+#: spyder/widgets/explorer.py:795
msgid "New file"
msgstr "Новый файл"
@@ -1625,10 +1637,10 @@ msgstr "Открыть последний закрытый"
#: spyder/plugins/editor.py:661
msgid "&Open..."
-msgstr "&Открыть"
+msgstr "&Открыть..."
-#: spyder/plugins/editor.py:662 spyder/plugins/editor.py:1867
-#: spyder/plugins/editor.py:1873
+#: spyder/plugins/editor.py:662 spyder/plugins/editor.py:1881
+#: spyder/plugins/editor.py:1887
msgid "Open file"
msgstr "Открыть файл"
@@ -1644,7 +1656,7 @@ msgstr "Загрузить файл с диска"
msgid "&Save"
msgstr "&Сохранить"
-#: spyder/plugins/editor.py:673 spyder/widgets/editor.py:1672
+#: spyder/plugins/editor.py:673 spyder/widgets/editor.py:1675
msgid "Save file"
msgstr "Сохранить файл"
@@ -1678,11 +1690,11 @@ msgstr "Предварительный просмотр..."
#: spyder/plugins/editor.py:698
msgid "&Print..."
-msgstr "&Печать"
+msgstr "&Печать..."
#: spyder/plugins/editor.py:699
msgid "Print current file..."
-msgstr "Печатать текущий файл"
+msgstr "Печать текущего файла..."
#: spyder/plugins/editor.py:702
msgid "&Close"
@@ -1725,6 +1737,7 @@ msgid "Set/Edit conditional breakpoint"
msgstr "Поставить/Редактировать условную точку останова"
#: spyder/plugins/editor.py:755
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:180
msgid "Clear breakpoints in all files"
msgstr "Очистить точки останова во всех файлах"
@@ -1768,8 +1781,10 @@ msgstr "Шаг из функции"
msgid "Run until current function or method returns"
msgstr "Выполнять пока функция или метод не завершатся"
-#: spyder/plugins/editor.py:796 spyder/widgets/findinfiles.py:438
-#: spyder/widgets/ipythonconsole/client.py:354
+#: spyder/plugins/editor.py:796 spyder/widgets/findinfiles.py:450
+#: spyder/widgets/ipythonconsole/client.py:393
+#: spyder/plugins/pylint/widgets/pylintgui.py:211
+#: spyder/plugins/profiler/widgets/profilergui.py:87
msgid "Stop"
msgstr "Стоп"
@@ -1797,7 +1812,7 @@ msgstr "Перезапустить последний скрипт"
msgid "Run again last file"
msgstr "Выполнить снова последний файл"
-#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2720
+#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2727
msgid "Run &selection or current line"
msgstr "Выполнить в&ыделенное или текущую строку"
@@ -1805,7 +1820,7 @@ msgstr "Выполнить в&ыделенное или текущую стро
msgid "Run selection or current line"
msgstr "Выполнить выделенное или текущую строку"
-#: spyder/plugins/editor.py:836 spyder/widgets/sourcecode/codeeditor.py:2708
+#: spyder/plugins/editor.py:836 spyder/widgets/sourcecode/codeeditor.py:2715
msgid "Run cell"
msgstr "Выполнить &блок"
@@ -1817,7 +1832,7 @@ msgstr ""
"Выполнить текущий блок (Ctrl+Enter)\n"
"[Используйте #%% для создания блоков]"
-#: spyder/plugins/editor.py:845 spyder/widgets/sourcecode/codeeditor.py:2712
+#: spyder/plugins/editor.py:845 spyder/widgets/sourcecode/codeeditor.py:2719
msgid "Run cell and advance"
msgstr "Выполнить блок и перейти далее"
@@ -1825,13 +1840,13 @@ msgstr "Выполнить блок и перейти далее"
msgid "Run current cell and go to the next one (Shift+Enter)"
msgstr "Выполнить текущий блок и перейти к следующему (Shift+Enter)"
-#: spyder/plugins/editor.py:854 spyder/widgets/sourcecode/codeeditor.py:2716
+#: spyder/plugins/editor.py:854 spyder/widgets/sourcecode/codeeditor.py:2723
msgid "Re-run last cell"
msgstr "Перезапустить последний блок"
#: spyder/plugins/editor.py:855
msgid "Re run last cell "
-msgstr "Перезапустить последний блок"
+msgstr "Перезапустить последний блок "
#: spyder/plugins/editor.py:865
msgid "Show todo list"
@@ -1892,11 +1907,11 @@ msgstr "Следующая позиция курсора"
msgid "Go to next cursor position"
msgstr "Перейти к следующей позиции курсора"
-#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Comment"
msgstr "Комментировать"
-#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Uncomment"
msgstr "Раскомментировать"
@@ -1994,7 +2009,7 @@ msgid ""
"directory"
msgstr ""
"Установить каталог текущего скрипта как рабочий для текущей консоли (и "
-"файлового менеджера) "
+"файлового менеджера)"
#: spyder/plugins/editor.py:1006
msgid "Maximum number of recent files..."
@@ -2004,8 +2019,8 @@ msgstr "Максимальное количество недавних файл
msgid "Clear recent files list"
msgstr "Очистить список недавних файлов"
-#: spyder/plugins/editor.py:1009 spyder/plugins/projects.py:107
-#: spyder/widgets/findinfiles.py:246
+#: spyder/plugins/editor.py:1009 spyder/plugins/projects.py:101
+#: spyder/widgets/findinfiles.py:261
msgid "Clear this list"
msgstr "Очистить этот список"
@@ -2013,39 +2028,39 @@ msgstr "Очистить этот список"
msgid "Open &recent"
msgstr "Открыть не&давние"
-#: spyder/plugins/editor.py:1675
+#: spyder/plugins/editor.py:1674
msgid "Spyder Editor"
msgstr "Редактор Spyder"
-#: spyder/plugins/editor.py:1676
+#: spyder/plugins/editor.py:1675
msgid "This is a temporary script file."
msgstr "Это временный скриптовый файл."
-#: spyder/plugins/editor.py:1745
+#: spyder/plugins/editor.py:1758
msgid "untitled"
msgstr "untitled"
-#: spyder/plugins/editor.py:1817
+#: spyder/plugins/editor.py:1831
msgid "Maximum number of recent files"
msgstr "Максимальное количество недавних файлов"
-#: spyder/plugins/editor.py:1963
+#: spyder/plugins/editor.py:1977
msgid "Printing..."
msgstr "Печать..."
-#: spyder/plugins/explorer.py:54
+#: spyder/plugins/explorer.py:55
msgid "File explorer"
msgstr "Файловый менеджер"
-#: spyder/plugins/findinfiles.py:120 spyder/widgets/findinfiles.py:913
+#: spyder/plugins/findinfiles.py:117 spyder/widgets/findinfiles.py:949
msgid "Find in files"
msgstr "Найти в файлах"
-#: spyder/plugins/findinfiles.py:145
+#: spyder/plugins/findinfiles.py:141
msgid "&Find in files"
msgstr "Найти в &файлах"
-#: spyder/plugins/findinfiles.py:150
+#: spyder/plugins/findinfiles.py:146
msgid "Search text in multiple files"
msgstr "Искать текст в нескольких файлах"
@@ -2100,47 +2115,47 @@ msgstr "Sphinx %s на данный момент установлено."
msgid "No further documentation available"
msgstr "Дополнительная документация отсутствует"
-#: spyder/plugins/help.py:307 spyder/plugins/help.py:347
+#: spyder/plugins/help.py:307 spyder/plugins/help.py:345
msgid "No documentation available"
msgstr "Дополнительная документация отсутствует"
-#: spyder/plugins/help.py:378
+#: spyder/plugins/help.py:376
msgid "Source"
msgstr "Исходник"
-#: spyder/plugins/help.py:385 spyder/plugins/runconfig.py:170
-#: spyder/plugins/runconfig.py:486 spyder/widgets/ipythonconsole/client.py:288
+#: spyder/plugins/help.py:383 spyder/plugins/runconfig.py:170
+#: spyder/plugins/runconfig.py:486 spyder/widgets/ipythonconsole/client.py:327
msgid "Console"
msgstr "Консоль"
-#: spyder/plugins/help.py:393
+#: spyder/plugins/help.py:391
msgid "Object"
msgstr "Объект"
-#: spyder/plugins/help.py:407
+#: spyder/plugins/help.py:405
msgid "Plain Text"
msgstr "Простой текст"
-#: spyder/plugins/help.py:411
+#: spyder/plugins/help.py:409
msgid "Show Source"
msgstr "Показать исходник"
-#: spyder/plugins/help.py:415
+#: spyder/plugins/help.py:413
msgid "Rich Text"
msgstr "Форматированный текст"
-#: spyder/plugins/help.py:425
+#: spyder/plugins/help.py:423
msgid "Automatic import"
msgstr "Автоматический импорт"
-#: spyder/plugins/help.py:437 spyder/plugins/history.py:106
-#: spyder/widgets/editor.py:728 spyder/widgets/explorer.py:1200
-#: spyder/widgets/ipythonconsole/client.py:378
-#: spyder/widgets/variableexplorer/namespacebrowser.py:148
+#: spyder/plugins/help.py:435 spyder/plugins/history.py:108
+#: spyder/widgets/editor.py:738 spyder/widgets/explorer.py:1205
+#: spyder/widgets/ipythonconsole/client.py:417
+#: spyder/widgets/variableexplorer/namespacebrowser.py:151
msgid "Options"
msgstr "Опции"
-#: spyder/plugins/help.py:696
+#: spyder/plugins/help.py:692
msgid ""
"Here you can get help of any object by pressing %s in front of it, either on "
"the Editor or the Console.%sHelp can also be shown automatically after "
@@ -2152,38 +2167,38 @@ msgstr ""
"автоматически показываться при вводе открывающей круглой скобки после "
"объекта. Вы можете активировать эту возможность в %s."
-#: spyder/plugins/help.py:702
+#: spyder/plugins/help.py:698
msgid "Preferences > Help"
msgstr "Параметры > Справка"
-#: spyder/plugins/help.py:709
+#: spyder/plugins/help.py:705
msgid "Usage"
msgstr "Использование"
-#: spyder/plugins/help.py:710
+#: spyder/plugins/help.py:706
msgid "New to Spyder? Read our"
msgstr "Используете Spyder впервые? Прочитайте наше"
-#: spyder/plugins/help.py:711
+#: spyder/plugins/help.py:707
msgid "tutorial"
msgstr "руководство"
-#: spyder/plugins/help.py:718
+#: spyder/plugins/help.py:714
msgid ""
"Please consider installing Sphinx to get documentation rendered in rich text."
msgstr ""
"Пожалуйста, подумайте об установке Sphinx для просмотра документации в "
"форматированном виде."
-#: spyder/plugins/help.py:891
+#: spyder/plugins/help.py:885
msgid "Lock"
msgstr "Заблокировать"
-#: spyder/plugins/help.py:891
+#: spyder/plugins/help.py:885
msgid "Unlock"
msgstr "Разблокировать"
-#: spyder/plugins/help.py:938
+#: spyder/plugins/help.py:932
msgid ""
"The following error occured when calling Sphinx %s.
Incompatible "
"Sphinx version or doc string decoding failed.
Error message:
%s"
@@ -2192,63 +2207,68 @@ msgstr ""
"версия Sphinx или ошибка декодирования строки документации.
Сообщение "
"об ошибке:
%s"
-#: spyder/plugins/help.py:982
+#: spyder/plugins/help.py:976
msgid "No source code available."
msgstr "Исходный код не доступен."
-#: spyder/plugins/history.py:39
+#: spyder/plugins/history.py:39 spyder/plugins/pylint/plugin.py:35
msgid "Settings"
msgstr "Настройки"
-#: spyder/plugins/history.py:41
+#: spyder/plugins/history.py:43
msgid " entries"
msgstr " записей"
-#: spyder/plugins/history.py:41
+#: spyder/plugins/history.py:43
msgid "History depth: "
msgstr "Глубина истории: "
-#: spyder/plugins/history.py:48
+#: spyder/plugins/history.py:50
msgid "Scroll automatically to last entry"
msgstr "Автоматически пролистывать к последней записи"
-#: spyder/plugins/history.py:126
+#: spyder/plugins/history.py:128
msgid "History log"
msgstr "Журнал истории"
-#: spyder/plugins/history.py:153
+#: spyder/plugins/history.py:153 spyder/plugins/pylint/plugin.py:115
msgid "History..."
msgstr "История..."
-#: spyder/plugins/history.py:155
+#: spyder/plugins/history.py:155 spyder/plugins/pylint/plugin.py:117
msgid "Set history maximum entries"
msgstr "Установить максимум записей истории"
-#: spyder/plugins/history.py:260
+#: spyder/plugins/history.py:260 spyder/plugins/pylint/plugin.py:39
+#: spyder/plugins/pylint/plugin.py:160
msgid "History"
msgstr "История"
-#: spyder/plugins/history.py:261
+#: spyder/plugins/history.py:261 spyder/plugins/pylint/plugin.py:161
msgid "Maximum entries"
msgstr "Максимум записей"
-#: spyder/plugins/ipythonconsole.py:65
+#: spyder/plugins/ipythonconsole.py:64
msgid "Symbolic mathematics in the IPython Console"
msgstr "Символьная математика в консоли Python"
-#: spyder/plugins/ipythonconsole.py:69
+#: spyder/plugins/ipythonconsole.py:68
msgid "Run Cython files in the IPython Console"
msgstr "Запустить файлы Cython в консоли IPython"
-#: spyder/plugins/ipythonconsole.py:73
+#: spyder/plugins/ipythonconsole.py:72
msgid "Integrate the IPython console"
msgstr "Интегрирует консоли IPython"
-#: spyder/plugins/ipythonconsole.py:77
+#: spyder/plugins/ipythonconsole.py:76
msgid "IPython interactive python environment"
msgstr "IPython, интерактивная оболочка для python"
-#: spyder/plugins/ipythonconsole.py:128
+#: spyder/plugins/ipythonconsole.py:80
+msgid "Display 2D graphics in the IPython Console"
+msgstr "Отображать 2-мерную графику в консоли Python"
+
+#: spyder/plugins/ipythonconsole.py:131
msgid ""
"The authenticity of host %s can't be established. Are you sure you "
"want to continue connecting?"
@@ -2256,91 +2276,101 @@ msgstr ""
"Подлинность хоста %s не может быть установлена. Вы уверены, что "
"хотите продолжить соединение?"
-#: spyder/plugins/ipythonconsole.py:140
+#: spyder/plugins/ipythonconsole.py:143
msgid "The authenticity of the host can't be established"
msgstr "Подлинность хоста не может быть установлена"
-#: spyder/plugins/ipythonconsole.py:147
+#: spyder/plugins/ipythonconsole.py:150
msgid "Tunnel '%s' failed to start"
msgstr "Туннель '%s' не удалось запустить"
-#: spyder/plugins/ipythonconsole.py:152
+#: spyder/plugins/ipythonconsole.py:155
msgid "Could not connect to remote host"
msgstr "Не удалось подключиться к удалённому хосту"
-#: spyder/plugins/ipythonconsole.py:169 spyder/plugins/ipythonconsole.py:799
+#: spyder/plugins/ipythonconsole.py:172 spyder/plugins/ipythonconsole.py:846
msgid "Connect to an existing kernel"
msgstr "Подключиться к работающему ядру"
-#: spyder/plugins/ipythonconsole.py:171
+#: spyder/plugins/ipythonconsole.py:174
msgid ""
-"Please enter the connection info of the kernel you want to connect to. For "
-"that you can either select its JSON connection file using the Browse"
-"tt> button, or write directly its id, in case it's a local kernel (for "
-"example kernel-3764.json or just 3764)."
+"Please select the JSON connection file (e.g. kernel-3764.json"
+"tt>) or enter the 4-digit ID (e.g. 3764) of the existing "
+"kernel to connect to, and enter the SSH host name and credentials if a "
+"remote kernel."
msgstr ""
-"Пожалуйста, введите информацию о соединении для ядра, к которому пытаетесь "
-"подключиться. Для этого либо выберите JSON-файл соединения кнопкой "
-"Обзор, либо, если ядро локальное, введите его id (напр. "
-"kernel-3764.json или просто 3764)."
+"Пожалуйста выберите JSON-файл соединения (например kernel-3764."
+"json) или введите ID из 4 цифр (например 3764) "
+"существующего ядра для подключения к нему, а также введите имя SSH-хоста и "
+"учетные данные в случае если ядро удаленное."
-#: spyder/plugins/ipythonconsole.py:182
-msgid "Connection info:"
-msgstr "Информация о соединении:"
+#: spyder/plugins/ipythonconsole.py:183
+msgid "Kernel ID/Connection file:"
+msgstr "ID ядра/файл соединения:"
-#: spyder/plugins/ipythonconsole.py:184
-msgid "Path to connection file or kernel id"
-msgstr "Путь к файлу соединения или id ядра"
+#: spyder/plugins/ipythonconsole.py:185
+msgid "ID number or path to connection file"
+msgstr "ID-номер или путь к файлу соединения"
-#: spyder/plugins/ipythonconsole.py:186 spyder/plugins/ipythonconsole.py:203
+#: spyder/plugins/ipythonconsole.py:187 spyder/plugins/ipythonconsole.py:216
msgid "Browse"
msgstr "Обзор"
-#: spyder/plugins/ipythonconsole.py:195
-msgid "This is a remote kernel"
-msgstr "Это удалённо-управляемое ядро"
+#: spyder/plugins/ipythonconsole.py:196
+msgid "This is a remote kernel (via SSH)"
+msgstr "Это удалённо-управляемое ядро (через SSH)"
#: spyder/plugins/ipythonconsole.py:199
+msgid ""
+"Note: If connecting to a remote kernel, only the SSH keyfile or"
+"i> the Password field need to be completed, unless the keyfile is protected "
+"with a passphrase."
+msgstr ""
+"Примечание: Если Вы подключаетесь к удаленному ядру, нужно заполнить "
+"только файл ключа SSH или поле Пароль, в случае если файл ключа не "
+"защищен паролем."
+
+#: spyder/plugins/ipythonconsole.py:207
msgid "username@hostname:port"
msgstr "username@hostname:port"
-#: spyder/plugins/ipythonconsole.py:202
-msgid "Path to ssh key file"
-msgstr "Путь к ключу ssh"
-
-#: spyder/plugins/ipythonconsole.py:211
-msgid "Password or ssh key passphrase"
-msgstr "Пароль или кодовая фраза ключа ssh"
+#: spyder/plugins/ipythonconsole.py:210
+msgid "Remote user password or SSH keyfile passphrase"
+msgstr "Пароль удаленного пользователя или кодовая фраза ключа SSH"
#: spyder/plugins/ipythonconsole.py:215
-msgid "Host name"
-msgstr "Имя хоста"
+msgid "Path to SSH keyfile (optional)"
+msgstr "Путь к файлу ключа SSH (опционально)"
-#: spyder/plugins/ipythonconsole.py:216
-msgid "Ssh key"
-msgstr "Ключ ssh"
+#: spyder/plugins/ipythonconsole.py:224
+msgid "Host name:"
+msgstr "Имя хоста:"
-#: spyder/plugins/ipythonconsole.py:217
-msgid "Password"
-msgstr "Пароль"
+#: spyder/plugins/ipythonconsole.py:225
+msgid "Password:"
+msgstr "Пароль:"
-#: spyder/plugins/ipythonconsole.py:246
-msgid "Open connection file"
-msgstr "Открыть файл соединения IPython"
+#: spyder/plugins/ipythonconsole.py:226
+msgid "SSH keyfile:"
+msgstr "Файл ключа SSH:"
-#: spyder/plugins/ipythonconsole.py:251
-msgid "Select ssh key"
-msgstr "Выберите ключ ssh"
+#: spyder/plugins/ipythonconsole.py:257
+msgid "Select kernel connection file"
+msgstr "Открыть файл соединения ядра"
-#: spyder/plugins/ipythonconsole.py:284 spyder/plugins/ipythonconsole.py:734
+#: spyder/plugins/ipythonconsole.py:262
+msgid "Select SSH keyfile"
+msgstr "Выберите файл ключа SSH"
+
+#: spyder/plugins/ipythonconsole.py:295 spyder/plugins/ipythonconsole.py:780
msgid "IPython console"
msgstr "Консоль IPython"
-#: spyder/plugins/ipythonconsole.py:291
+#: spyder/plugins/ipythonconsole.py:302
msgid "Display initial banner"
msgstr "Показывать стартовый баннер"
-#: spyder/plugins/ipythonconsole.py:292
+#: spyder/plugins/ipythonconsole.py:303
msgid ""
"This option lets you hide the message shown at\n"
"the top of the console when it's opened."
@@ -2348,12 +2378,12 @@ msgstr ""
"Эта опция позволяет Вам спрятать сообщение,\n"
"показываемое вверху консоли при открытии."
-#: spyder/plugins/ipythonconsole.py:294
+#: spyder/plugins/ipythonconsole.py:305
msgid "Use a pager to display additional text inside the console"
msgstr ""
"Использовать постраничный вывод для показа дополнительного текста в консоли"
-#: spyder/plugins/ipythonconsole.py:296
+#: spyder/plugins/ipythonconsole.py:307
msgid ""
"Useful if you don't want to fill the console with long help or completion "
"texts.\n"
@@ -2363,16 +2393,16 @@ msgstr ""
"текстом.\n"
"Примечание: Используйте клавишу Q для выхода из постраничного вывода."
-#: spyder/plugins/ipythonconsole.py:301
+#: spyder/plugins/ipythonconsole.py:312
msgid "Ask for confirmation before closing"
msgstr "Спрашивать подтверждение перед закрытием"
-#: spyder/plugins/ipythonconsole.py:304
+#: spyder/plugins/ipythonconsole.py:315
msgid "Ask for confirmation before removing all user-defined variables"
msgstr ""
"Спрашивать подтверждение перед удалением всех пользовательских переменных"
-#: spyder/plugins/ipythonconsole.py:307
+#: spyder/plugins/ipythonconsole.py:318
msgid ""
"This option lets you hide the warning message shown\n"
"when resetting the namespace from Spyder."
@@ -2380,44 +2410,56 @@ msgstr ""
"Эта опция позволяет Вам спрятать сообщение,\n"
"показываемое при перезапуске окружения Spyder."
-#: spyder/plugins/ipythonconsole.py:309
-#: spyder/widgets/ipythonconsole/client.py:317
+#: spyder/plugins/ipythonconsole.py:320
+#: spyder/widgets/ipythonconsole/client.py:356
msgid "Show elapsed time"
msgstr "Показывать прошедшее время"
-#: spyder/plugins/ipythonconsole.py:320
+#: spyder/plugins/ipythonconsole.py:322
+msgid "Ask for confirmation before restarting"
+msgstr "Спрашивать подтверждение перед перезапуском"
+
+#: spyder/plugins/ipythonconsole.py:324
+msgid ""
+"This option lets you hide the warning message shown\n"
+"when restarting the kernel."
+msgstr ""
+"Эта опция позволяет Вам спрятать сообщение,\n"
+"показываемое при перезапуске ядра."
+
+#: spyder/plugins/ipythonconsole.py:337
msgid "Completion Type"
msgstr "Тип автодополнения"
-#: spyder/plugins/ipythonconsole.py:321
+#: spyder/plugins/ipythonconsole.py:338
msgid "Decide what type of completion to use"
msgstr "Выберите какой тип автодополнения использовать"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Graphical"
msgstr "Графический"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Plain"
msgstr "Простой"
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Terminal"
msgstr "Терминал"
-#: spyder/plugins/ipythonconsole.py:324
+#: spyder/plugins/ipythonconsole.py:341
msgid "Completion:"
msgstr "Автодополнение:"
-#: spyder/plugins/ipythonconsole.py:334
+#: spyder/plugins/ipythonconsole.py:351
msgid " lines"
msgstr " строк"
-#: spyder/plugins/ipythonconsole.py:334
+#: spyder/plugins/ipythonconsole.py:351
msgid "Buffer: "
msgstr "Буфер: "
-#: spyder/plugins/ipythonconsole.py:336
+#: spyder/plugins/ipythonconsole.py:353
msgid ""
"Set the maximum number of lines of text shown in the\n"
"console before truncation. Specifying -1 disables it\n"
@@ -2427,19 +2469,19 @@ msgstr ""
"в консоли перед усечением. Значение -1 отключает функцию\n"
"(не рекомендуется!)"
-#: spyder/plugins/ipythonconsole.py:345
+#: spyder/plugins/ipythonconsole.py:362
msgid "Support for graphics (Matplotlib)"
msgstr "Поддержка графики (Matplotlib)"
-#: spyder/plugins/ipythonconsole.py:346
+#: spyder/plugins/ipythonconsole.py:363
msgid "Activate support"
msgstr "Активировать поддержку"
-#: spyder/plugins/ipythonconsole.py:347
+#: spyder/plugins/ipythonconsole.py:364
msgid "Automatically load Pylab and NumPy modules"
msgstr "Автоматически загружать модули Pylab и NumPy"
-#: spyder/plugins/ipythonconsole.py:350
+#: spyder/plugins/ipythonconsole.py:367
msgid ""
"This lets you load graphics support without importing \n"
"the commands to do plots. Useful to work with other\n"
@@ -2451,19 +2493,19 @@ msgstr ""
"графическими библиотеками, отличными от Matplotlib или\n"
"разработки GUI в Spyder."
-#: spyder/plugins/ipythonconsole.py:365
+#: spyder/plugins/ipythonconsole.py:382
msgid "Inline"
msgstr "Встроенный"
-#: spyder/plugins/ipythonconsole.py:366
+#: spyder/plugins/ipythonconsole.py:383
msgid "Automatic"
msgstr "Автоматически"
-#: spyder/plugins/ipythonconsole.py:367
+#: spyder/plugins/ipythonconsole.py:384
msgid "Graphics backend"
msgstr "Графический бэкенд"
-#: spyder/plugins/ipythonconsole.py:368
+#: spyder/plugins/ipythonconsole.py:385
msgid ""
"Decide how graphics are going to be displayed in the console. If unsure, "
"please select %s to put graphics inside the console or %s to "
@@ -2474,59 +2516,78 @@ msgstr ""
"для взаимодействия с ними (через масштабирование и панорамирование) в "
"отдельном окне."
-#: spyder/plugins/ipythonconsole.py:388
+#: spyder/plugins/ipythonconsole.py:405
msgid "Backend:"
msgstr "Бэкенд:"
-#: spyder/plugins/ipythonconsole.py:390
+#: spyder/plugins/ipythonconsole.py:407
msgid "This option will be applied the next time a console is opened."
msgstr "Эта опция будет принята при следующем открытии консоли."
-#: spyder/plugins/ipythonconsole.py:401
+#: spyder/plugins/ipythonconsole.py:418
msgid "Inline backend"
msgstr "Встроенный бекэнд"
-#: spyder/plugins/ipythonconsole.py:402
+#: spyder/plugins/ipythonconsole.py:419
msgid "Decide how to render the figures created by this backend"
msgstr "Выберите как рендерить графики, созданные этим бэкендом"
-#: spyder/plugins/ipythonconsole.py:406
+#: spyder/plugins/ipythonconsole.py:423
msgid "Format:"
msgstr "Формат:"
-#: spyder/plugins/ipythonconsole.py:409
+#: spyder/plugins/ipythonconsole.py:427
msgid "Resolution:"
msgstr "Разрешение:"
-#: spyder/plugins/ipythonconsole.py:409
+#: spyder/plugins/ipythonconsole.py:427
msgid "dpi"
msgstr "dpi"
-#: spyder/plugins/ipythonconsole.py:411
+#: spyder/plugins/ipythonconsole.py:429
msgid "Only used when the format is PNG. Default is 72"
msgstr "Используется только для формата PNG. 72 по умолчанию"
-#: spyder/plugins/ipythonconsole.py:414
+#: spyder/plugins/ipythonconsole.py:432
msgid "Width:"
msgstr "Ширина:"
-#: spyder/plugins/ipythonconsole.py:414 spyder/plugins/ipythonconsole.py:418
+#: spyder/plugins/ipythonconsole.py:432 spyder/plugins/ipythonconsole.py:436
msgid "inches"
msgstr "дюймов"
-#: spyder/plugins/ipythonconsole.py:416
+#: spyder/plugins/ipythonconsole.py:434
msgid "Default is 6"
msgstr "6 по умолчанию"
-#: spyder/plugins/ipythonconsole.py:418
+#: spyder/plugins/ipythonconsole.py:436
msgid "Height:"
msgstr "Высота:"
-#: spyder/plugins/ipythonconsole.py:420
+#: spyder/plugins/ipythonconsole.py:438
msgid "Default is 4"
msgstr "4 по умолчанию"
-#: spyder/plugins/ipythonconsole.py:447
+#: spyder/plugins/ipythonconsole.py:440
+msgid "Use a tight layout for inline plots"
+msgstr "Использовать размещение tight для встраиваемых графиков"
+
+#: spyder/plugins/ipythonconsole.py:442
+msgid ""
+"Sets bbox_inches to \"tight\" when\n"
+"plotting inline with matplotlib.\n"
+"When enabled, can cause discrepancies\n"
+"between the image displayed inline and\n"
+"that created using savefig."
+msgstr ""
+"Устанавливает bbox_inches в\n"
+"\"tight\" при построении встроенного\n"
+"графика в matplotlib.\n"
+"Когда включен, может вызвать\n"
+"неполадки, если изображение\n"
+"встроенное и создано savefig."
+
+#: spyder/plugins/ipythonconsole.py:475
msgid ""
"You can run several lines of code when a console is started. Please "
"introduce each one separated by commas, for example:
import os, import "
@@ -2535,15 +2596,15 @@ msgstr ""
"Вы можете выполнить несколько строк кода при запуске консоли. Пожалуйста, "
"введите их через запятую, например:
import os, import sys"
-#: spyder/plugins/ipythonconsole.py:453
+#: spyder/plugins/ipythonconsole.py:481
msgid "Lines:"
msgstr "Строки:"
-#: spyder/plugins/ipythonconsole.py:462
+#: spyder/plugins/ipythonconsole.py:490
msgid "Run a file"
msgstr "Выполнить файл"
-#: spyder/plugins/ipythonconsole.py:463
+#: spyder/plugins/ipythonconsole.py:491
msgid ""
"You can also run a whole file at startup instead of just some lines (This is "
"similar to have a PYTHONSTARTUP file)."
@@ -2551,35 +2612,59 @@ msgstr ""
"При старте Вы также можете запустить весь файл вместо нескольких строк "
"(Подобно использованию файла PYTHONSTARTUP)."
-#: spyder/plugins/ipythonconsole.py:467
+#: spyder/plugins/ipythonconsole.py:495
msgid "Use the following file:"
msgstr "Использовать следующий файл:"
-#: spyder/plugins/ipythonconsole.py:481
+#: spyder/plugins/ipythonconsole.py:509
+msgid "Jedi completion"
+msgstr "Автодополнение Jedi"
+
+#: spyder/plugins/ipythonconsole.py:510
+msgid ""
+"Enable Jedi-based Tab completion in the IPython console; similar to "
+"the greedy completer, but without evaluating the code.
Warning: "
+"Slows down your console when working with large dataframes!"
+msgstr ""
+"Включить автодополнение в консоли IPython по Tab на основе Jedi; "
+"оно похоже на скупое автодополнение, но без выполнения кода."
+"
Предупреждение: Замедлится прокрутка консоли при работе с "
+"большими массивами данных!"
+
+#: spyder/plugins/ipythonconsole.py:517
+msgid "Use Jedi completion in the IPython console"
+msgstr "Использовать автодополнение Jedi в консоли IPython"
+
+#: spyder/plugins/ipythonconsole.py:530
msgid "Greedy completion"
msgstr "Скупое автодополнение"
-#: spyder/plugins/ipythonconsole.py:482
+#: spyder/plugins/ipythonconsole.py:531
msgid ""
"Enable Tab completion on elements of lists, results of function "
-"calls, etc, without assigning them to a variable.
For example, you "
-"can get completions on things like li[0].<Tab> or ins."
-"meth().<Tab>"
+"calls, etc, without assigning them to a variable, like li[0].<"
+"Tab> or ins.meth().<Tab>
Warning: Due to a "
+"bug, IPython's greedy completer requires a leading <Space> "
+"for some completions; e.g. np.sin(<Space>np.<Tab> "
+"works while np.sin(np.<Tab> doesn't."
msgstr ""
"Включает автодополнение по Tab для элементов списков, результатов "
-"вызова функций, и т.п. без присвоения их переменной.
Например, Вы "
-"можете сделать автодополнение для таких вещей, как li[0].<Tab>"
-"tt> или ins.meth().<Tab>"
+"вызова функций, и т.п. без присвоения их переменной, например "
+"li[0].<Tab> или ins.meth().<Tab> "
+"
Предупреждение: Из-за ошибки, скупое автодополнение в IPython "
+"требует ввод <Space> для некоторых автодополнений; например "
+"np.sin(<Space>np.<Tab> работает, в то время как np."
+"sin(np.<Tab> - нет."
-#: spyder/plugins/ipythonconsole.py:490
-msgid "Use the greedy completer"
-msgstr "Включить скупое автодополнение"
+#: spyder/plugins/ipythonconsole.py:543
+msgid "Use greedy completion in the IPython console"
+msgstr "Использовать скупое автодополнение в консоли IPython"
-#: spyder/plugins/ipythonconsole.py:501
+#: spyder/plugins/ipythonconsole.py:555
msgid "Autocall"
msgstr "Автовызов"
-#: spyder/plugins/ipythonconsole.py:502
+#: spyder/plugins/ipythonconsole.py:556
msgid ""
"Autocall makes IPython automatically call any callable object even if you "
"didn't type explicit parentheses.
For example, if you type str 43 "
@@ -2589,23 +2674,23 @@ msgstr ""
"скобок.
Например, если Вы введете str 43, будет выполнено "
"str(43) автоматически."
-#: spyder/plugins/ipythonconsole.py:509
+#: spyder/plugins/ipythonconsole.py:563
msgid "Smart"
msgstr "Умный"
-#: spyder/plugins/ipythonconsole.py:510
+#: spyder/plugins/ipythonconsole.py:564
msgid "Full"
msgstr "Все"
-#: spyder/plugins/ipythonconsole.py:511
+#: spyder/plugins/ipythonconsole.py:565
msgid "Off"
msgstr "Отключён"
-#: spyder/plugins/ipythonconsole.py:513
+#: spyder/plugins/ipythonconsole.py:567
msgid "Autocall: "
msgstr "Автовызов: "
-#: spyder/plugins/ipythonconsole.py:514
+#: spyder/plugins/ipythonconsole.py:568
msgid ""
"On %s mode, Autocall is not applied if there are no arguments after "
"the callable. On %s mode, all callable objects are automatically "
@@ -2615,11 +2700,11 @@ msgstr ""
"вызываемого. В режиме %s все вызываемые объекты вызываются (даже если "
"аргументы не переданы)."
-#: spyder/plugins/ipythonconsole.py:526
+#: spyder/plugins/ipythonconsole.py:580
msgid "Symbolic Mathematics"
msgstr "Символьная математика"
-#: spyder/plugins/ipythonconsole.py:527
+#: spyder/plugins/ipythonconsole.py:581
msgid ""
"Perfom symbolic operations in the console (e.g. integrals, derivatives, "
"vector calculus, etc) and get the outputs in a beautifully printed style (it "
@@ -2629,11 +2714,11 @@ msgstr ""
"векторное исчисление и др.) и выводит результат в красивом виде (требуется "
"модуль Sympy)."
-#: spyder/plugins/ipythonconsole.py:532
+#: spyder/plugins/ipythonconsole.py:586
msgid "Use symbolic math"
msgstr "Использовать символьную математику"
-#: spyder/plugins/ipythonconsole.py:533
+#: spyder/plugins/ipythonconsole.py:587
msgid ""
"This option loads the Sympy library to work with.
Please refer to its "
"documentation to learn how to use it."
@@ -2641,45 +2726,45 @@ msgstr ""
"Эта опция подгружает для работы библиотеку Sympy.
Пожалуйста ознакомьтесь "
"с документацией для её использования."
-#: spyder/plugins/ipythonconsole.py:543
+#: spyder/plugins/ipythonconsole.py:597
msgid "Prompts"
msgstr "Приглашения к вводу/выводу"
-#: spyder/plugins/ipythonconsole.py:544
+#: spyder/plugins/ipythonconsole.py:598
msgid "Modify how Input and Output prompts are shown in the console."
msgstr "Определите как показывать приглашения Ввода и Вывода в консоли."
-#: spyder/plugins/ipythonconsole.py:547
+#: spyder/plugins/ipythonconsole.py:601
msgid "Input prompt:"
msgstr "Строка ввода:"
-#: spyder/plugins/ipythonconsole.py:549
+#: spyder/plugins/ipythonconsole.py:603
msgid ""
"Default is
In [<span class=\"in-prompt-number\">%i</span>]:"
msgstr ""
"По умолчанию:
In [<span class=\"in-prompt-number\">%i</"
"span>]:"
-#: spyder/plugins/ipythonconsole.py:553
+#: spyder/plugins/ipythonconsole.py:607
msgid "Output prompt:"
msgstr "Строка вывода:"
-#: spyder/plugins/ipythonconsole.py:555
+#: spyder/plugins/ipythonconsole.py:609
msgid ""
"Default is
Out[<span class=\"out-prompt-number\">%i</span>]:"
msgstr ""
"По умолчанию:
Out [<span class=\"out-prompt-number\">%i</"
"span>]:"
-#: spyder/plugins/ipythonconsole.py:575
+#: spyder/plugins/ipythonconsole.py:629
msgid "Graphics"
msgstr "Графика"
-#: spyder/plugins/ipythonconsole.py:577
+#: spyder/plugins/ipythonconsole.py:631
msgid "Startup"
msgstr "Запуск"
-#: spyder/plugins/ipythonconsole.py:604
+#: spyder/plugins/ipythonconsole.py:658
msgid ""
"The directory {} is not writable and it is required to create IPython "
"consoles. Please make it writable."
@@ -2687,23 +2772,32 @@ msgstr ""
"Каталог {} защищен от записи. Для запуска консоли IPython, пожалуйста, "
"откройте доступ на запись."
-#: spyder/plugins/ipythonconsole.py:784
+#: spyder/plugins/ipythonconsole.py:831
msgid "Open an &IPython console"
msgstr "Открыть консоль &IPython"
-#: spyder/plugins/ipythonconsole.py:791
+#: spyder/plugins/ipythonconsole.py:838
msgid "Restart kernel"
msgstr "Перезапустить ядро"
-#: spyder/plugins/ipythonconsole.py:800
+#: spyder/plugins/ipythonconsole.py:847
msgid "Open a new IPython console connected to an existing kernel"
msgstr "Открыть новую консоль IPython, подключенную к существующему ядру"
-#: spyder/plugins/ipythonconsole.py:803
+#: spyder/plugins/ipythonconsole.py:850
msgid "Rename tab"
msgstr "Переименовать вкладку"
-#: spyder/plugins/ipythonconsole.py:928
+#: spyder/plugins/ipythonconsole.py:968
+msgid ""
+"
Please exit from debugging before trying to run a file in this "
+"console.\n"
+"
"
+msgstr ""
+"
Пожалуйста, выйдите из отладки пред запуском файла в консоли.\n"
+"
"
+
+#: spyder/plugins/ipythonconsole.py:988
msgid ""
"No IPython console is currently available to run %s.
Please "
"open a new one and try again."
@@ -2711,63 +2805,55 @@ msgstr ""
"Сейчас нет доступных консолей IPython для запуска %s."
"
Пожалуйста, откройте новую и попытайтесь снова."
-#: spyder/plugins/ipythonconsole.py:1023
+#: spyder/plugins/ipythonconsole.py:1096
msgid ""
-"Your Python environment or installation doesn't have the ipykernel "
-"and cloudpickle modules installed on it. Without these modules is "
-"not possible for Spyder to create a console for you.
You can install "
-"them by running in a system terminal:
pip install ipykernel "
-"cloudpickle
or
conda install ipykernel cloudpickle"
-"tt>"
-msgstr ""
-"В вашем Python окружении или инсталяции не установлены модули ipykernel"
-"tt> и cloudpickle. Без этих модулей Spyder не может создать консоль "
-"для Вас.
Вы можете установить их, запустив в терминале команду: "
-"
pip install ipykernel cloudpickle"
-"tt>
или
conda install ipykernel cloudpickle"
-
-#: spyder/plugins/ipythonconsole.py:1316
+"Your Python environment or installation doesn't have the spyder-kernels"
+"tt> module or the right version of it installed. Without this module is not "
+"possible for Spyder to create a console for you.
You can install it "
+"by running in a system terminal:
conda install spyder-kernels=0."
+"*
or
pip install spyder-kernels==0.*"
+msgstr ""
+"В вашем Python окружении или инсталяции отсутствует модуль spyder-"
+"kernels или установлена неправильная версия. Без этого модуля Spyder не "
+"может создать консоль для Вас.
Вы можете установить его, введя в "
+"системном терминале:
conda install spyder-kernels=0.*"
+"tt>
or
pip install spyder-kernels==0.*"
+
+#: spyder/plugins/ipythonconsole.py:1362
msgid "Do you want to close this console?"
msgstr "Вы уверены, что хотите закрыть эту консоль?"
-#: spyder/plugins/ipythonconsole.py:1322
+#: spyder/plugins/ipythonconsole.py:1368
msgid ""
"Do you want to close all other consoles connected to the same kernel as this "
"one?"
msgstr "Хотите закрыть все другие консоли, подключённые к тому же ядру?"
-#: spyder/plugins/ipythonconsole.py:1387
+#: spyder/plugins/ipythonconsole.py:1440
msgid ""
"It was not possible to restart the IPython console when switching to this "
-"project. The error was {0}"
+"project. The error was
{0}"
msgstr ""
-"Не удалось перезапустить консоль IPython при переключении в этот проект. "
-"Ошибка: {0}"
+"Не удалось перезапустить консоль IPython при переключении на этот проект. "
+"Ошибка:
{0}"
-#: spyder/plugins/ipythonconsole.py:1488
-msgid ""
-"This error was most probably caused by installing Spyder in a directory with "
-"non-ascii characters (i.e. characters with tildes, apostrophes or non-latin "
-"symbols).
To fix it, please reinstall Spyder in a different "
-"location."
-msgstr ""
-"Эта ошибка скорее всего произошла из-за установки Spyder в каталог, "
-"содержащий non-ascii символы (тильды, апострофы, не латинские символы и т."
-"п.).
Для исправления переустановите Spyder в другой каталог."
+#: spyder/plugins/ipythonconsole.py:1546 spyder/plugins/ipythonconsole.py:1556
+msgid "The error is:
{}"
+msgstr "Ошибка:
{}"
-#: spyder/plugins/ipythonconsole.py:1694
+#: spyder/plugins/ipythonconsole.py:1742
msgid "IPython"
msgstr "IPython"
-#: spyder/plugins/ipythonconsole.py:1695
+#: spyder/plugins/ipythonconsole.py:1743
msgid "Unable to connect to %s"
msgstr "Не удалось подключиться к %s"
-#: spyder/plugins/ipythonconsole.py:1765
+#: spyder/plugins/ipythonconsole.py:1819
msgid "Connection error"
msgstr "Ошибка соединения"
-#: spyder/plugins/ipythonconsole.py:1766
+#: spyder/plugins/ipythonconsole.py:1820
msgid ""
"Could not open ssh tunnel. The error was:\n"
"\n"
@@ -2791,33 +2877,38 @@ msgstr "Удалить"
msgid "Layout Display and Order"
msgstr "Показывать и Выбирать компоновку"
-#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:66
+#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:71
msgid "Python interpreter"
msgstr "Интепретатор Python"
-#: spyder/plugins/maininterpreter.py:68
+#: spyder/plugins/maininterpreter.py:73
msgid "Select the Python interpreter for all Spyder consoles"
msgstr ""
"Выберите исполняемый файл интерпретатора Python\n"
"для всех консолей Spyder"
-#: spyder/plugins/maininterpreter.py:71
+#: spyder/plugins/maininterpreter.py:76
msgid "Default (i.e. the same as Spyder's)"
msgstr "По умолчанию (тот же, что для Spyder)"
-#: spyder/plugins/maininterpreter.py:74
+#: spyder/plugins/maininterpreter.py:79
msgid "Use the following Python interpreter:"
msgstr "Использовать следующий интепретатор Python:"
-#: spyder/plugins/maininterpreter.py:77
+#: spyder/plugins/maininterpreter.py:82
msgid "Executables"
msgstr "Исполняемые файлы"
-#: spyder/plugins/maininterpreter.py:94
+#: spyder/plugins/maininterpreter.py:92
+#, fuzzy
+msgid "Recent custom interpreters"
+msgstr "Интепретатор Python"
+
+#: spyder/plugins/maininterpreter.py:107
msgid "User Module Reloader (UMR)"
msgstr "Перезагрузка модулей пользователя (UMR)"
-#: spyder/plugins/maininterpreter.py:95
+#: spyder/plugins/maininterpreter.py:108
msgid ""
"UMR forces Python to reload modules which were imported when executing a "
"file in a Python or IPython console with the runfile function."
@@ -2825,11 +2916,11 @@ msgstr ""
"UMR заставляет Python перезагружать модули, импортированные при выполнении "
"скрипта во внешней консоли функцией runfile."
-#: spyder/plugins/maininterpreter.py:100
+#: spyder/plugins/maininterpreter.py:113
msgid "Enable UMR"
msgstr "Включить UMR"
-#: spyder/plugins/maininterpreter.py:101
+#: spyder/plugins/maininterpreter.py:114
msgid ""
"This option will enable the User Module Reloader (UMR) in Python/IPython "
"consoles. UMR forces Python to reload deeply modules during import when "
@@ -2851,21 +2942,21 @@ msgstr ""
"должным образом (напр. можно установить атрибут Qt.WA_DeleteOnClose "
"для Вашего главного окна с помощью метода setAttribute)"
-#: spyder/plugins/maininterpreter.py:117
+#: spyder/plugins/maininterpreter.py:130
msgid "Show reloaded modules list"
msgstr "Показать список перезагруженных модулей"
-#: spyder/plugins/maininterpreter.py:118
+#: spyder/plugins/maininterpreter.py:131
msgid "Please note that these changes will be applied only to new consoles"
msgstr ""
"Обратите внимание, что эти изменения будут применяться только к новым "
"консолям"
-#: spyder/plugins/maininterpreter.py:122
+#: spyder/plugins/maininterpreter.py:135
msgid "Set UMR excluded (not reloaded) modules"
msgstr "Установить модули-исключения для UMR (не перезагружаемые)"
-#: spyder/plugins/maininterpreter.py:150
+#: spyder/plugins/maininterpreter.py:163
msgid ""
"You selected an invalid Python interpreter for the console so the previous "
"interpreter will stay. Please make sure to select a valid one."
@@ -2873,7 +2964,7 @@ msgstr ""
"Вы выбрали некорректный интерпретатор Python для консоли, поэтому был "
"оставлен предыдущий интерпретатор. Пожалуйста, выберите правильный."
-#: spyder/plugins/maininterpreter.py:175
+#: spyder/plugins/maininterpreter.py:184
msgid ""
"You selected a Python %d interpreter for the console but Spyder is "
"running on Python %d!.
Although this is possible, we recommend "
@@ -2887,16 +2978,16 @@ msgstr ""
"появления ложных предупреждений и ошибок, связанных с несовместимостями в "
"синтаксисе между этими двумя версиями Python."
-#: spyder/plugins/maininterpreter.py:186 spyder/plugins/maininterpreter.py:213
-#: spyder/plugins/maininterpreter.py:217
+#: spyder/plugins/maininterpreter.py:195 spyder/plugins/maininterpreter.py:222
+#: spyder/plugins/maininterpreter.py:226
msgid "UMR"
msgstr "UMR"
-#: spyder/plugins/maininterpreter.py:187
+#: spyder/plugins/maininterpreter.py:196
msgid "Set the list of excluded modules as this: numpy, scipy"
msgstr "Задайте список модулей-исключений вот так: numpy, scipy"
-#: spyder/plugins/maininterpreter.py:204
+#: spyder/plugins/maininterpreter.py:213
msgid ""
"You are working with Python 2, this means that you can not import a module "
"that contains non-ascii characters."
@@ -2904,7 +2995,7 @@ msgstr ""
"Вы работаете с Python 2, поэтому вы не можете ипортировать модули, "
"содержащие не-ascii символы."
-#: spyder/plugins/maininterpreter.py:214
+#: spyder/plugins/maininterpreter.py:223
msgid ""
"The following modules are not installed on your machine:\n"
"%s"
@@ -2912,7 +3003,7 @@ msgstr ""
"Следующие модули не установлены на Вашей машине:\n"
"%s"
-#: spyder/plugins/maininterpreter.py:218
+#: spyder/plugins/maininterpreter.py:227
msgid ""
"Please note that these changes will be applied only to new Python/IPython "
"consoles"
@@ -2928,40 +3019,40 @@ msgstr "Онлайн справка"
msgid "Outline"
msgstr "Структура"
-#: spyder/plugins/projects.py:83 spyder/widgets/projects/explorer.py:112
+#: spyder/plugins/projects.py:77 spyder/widgets/projects/explorer.py:112
#: spyder/widgets/projects/explorer.py:126
msgid "Project explorer"
msgstr "Менеджер проектов"
-#: spyder/plugins/projects.py:95
+#: spyder/plugins/projects.py:89
msgid "New Project..."
msgstr "Новый проект..."
-#: spyder/plugins/projects.py:98
+#: spyder/plugins/projects.py:92
msgid "Open Project..."
msgstr "Открыть проект..."
-#: spyder/plugins/projects.py:101
+#: spyder/plugins/projects.py:95
msgid "Close Project"
msgstr "Закрыть проект"
-#: spyder/plugins/projects.py:104
+#: spyder/plugins/projects.py:98
msgid "Delete Project"
msgstr "Удалить проект"
-#: spyder/plugins/projects.py:110
+#: spyder/plugins/projects.py:104
msgid "Project Preferences"
msgstr "Параметры проекта"
-#: spyder/plugins/projects.py:112
+#: spyder/plugins/projects.py:106
msgid "Recent Projects"
msgstr "Недавние проекты"
-#: spyder/plugins/projects.py:249
+#: spyder/plugins/projects.py:264
msgid "Open project"
msgstr "Открыть проект"
-#: spyder/plugins/projects.py:255
+#: spyder/plugins/projects.py:270
msgid "%s is not a Spyder project!"
msgstr "%s - не является проектом Spyder!"
@@ -3064,7 +3155,7 @@ msgstr "Рабочий каталог по умолчанию:"
#: spyder/plugins/runconfig.py:556
msgid "Run Settings dialog"
-msgstr "диалог Настроек Запуска"
+msgstr "Диалог Настроек Запуска"
#: spyder/plugins/shortcuts.py:65
msgid "Currently used to delete lines on editor/Cut a word"
@@ -3130,7 +3221,7 @@ msgid "Context"
msgstr "Контекст"
#: spyder/plugins/shortcuts.py:587
-#: spyder/widgets/variableexplorer/collectionseditor.py:128
+#: spyder/widgets/variableexplorer/collectionseditor.py:153
msgid "Name"
msgstr "Имя"
@@ -3157,7 +3248,7 @@ msgstr "Комбинации клавиш"
#: spyder/plugins/shortcuts.py:846
msgid "Search: "
-msgstr "Поиск:"
+msgstr "Поиск: "
#: spyder/plugins/shortcuts.py:847
msgid "Reset to default values"
@@ -3171,36 +3262,46 @@ msgstr "Восстановить комбинации клавиш"
msgid "Do you want to reset to default values?"
msgstr "Уверены, что хотите восстановить значения по умолчанию?"
-#: spyder/plugins/variableexplorer.py:25
+#: spyder/plugins/variableexplorer.py:24
+msgid "View and edit DataFrames and Series in the Variable Explorer"
+msgstr ""
+"Показ и редактирование структур DataFrame и Serie в Менеджере Переменных"
+
+#: spyder/plugins/variableexplorer.py:29
+msgid "View and edit two and three dimensional arrays in the Variable Explorer"
+msgstr ""
+"Просмотр и редактирование 2-х и 3-мерных массивов в Менеджере Переменных"
+
+#: spyder/plugins/variableexplorer.py:37
msgid "Filter"
msgstr "Фильтр"
-#: spyder/plugins/variableexplorer.py:27
-#: spyder/widgets/variableexplorer/namespacebrowser.py:200
+#: spyder/plugins/variableexplorer.py:39
+#: spyder/widgets/variableexplorer/namespacebrowser.py:203
msgid "Exclude private references"
msgstr "Исключить приватные ссылки"
-#: spyder/plugins/variableexplorer.py:28
-#: spyder/widgets/variableexplorer/namespacebrowser.py:215
+#: spyder/plugins/variableexplorer.py:40
+#: spyder/widgets/variableexplorer/namespacebrowser.py:218
msgid "Exclude capitalized references"
msgstr "Исключить ссылки с прописной буквы"
-#: spyder/plugins/variableexplorer.py:29
-#: spyder/widgets/variableexplorer/namespacebrowser.py:208
+#: spyder/plugins/variableexplorer.py:41
+#: spyder/widgets/variableexplorer/namespacebrowser.py:211
msgid "Exclude all-uppercase references"
msgstr "Исключить ссылки со всеми буквами в верхнем регистре"
-#: spyder/plugins/variableexplorer.py:30
-#: spyder/widgets/variableexplorer/namespacebrowser.py:223
+#: spyder/plugins/variableexplorer.py:42
+#: spyder/widgets/variableexplorer/namespacebrowser.py:226
msgid "Exclude unsupported data types"
msgstr "Исключить неподдерживаемые типы данных"
-#: spyder/plugins/variableexplorer.py:36
-#: spyder/widgets/variableexplorer/collectionseditor.py:702
+#: spyder/plugins/variableexplorer.py:48
+#: spyder/widgets/variableexplorer/collectionseditor.py:738
msgid "Show arrays min/max"
msgstr "Показывать min/max массивов"
-#: spyder/plugins/variableexplorer.py:178
+#: spyder/plugins/variableexplorer.py:202
msgid "Variable explorer"
msgstr "Менеджер переменных"
@@ -3241,12 +3342,12 @@ msgstr ""
msgid "Back"
msgstr "Назад"
-#: spyder/plugins/workingdirectory.py:132 spyder/widgets/explorer.py:1194
+#: spyder/plugins/workingdirectory.py:130 spyder/widgets/explorer.py:1199
#: spyder/widgets/variableexplorer/importwizard.py:539
msgid "Next"
msgstr "Далее"
-#: spyder/plugins/workingdirectory.py:143
+#: spyder/plugins/workingdirectory.py:141
msgid ""
"This is the working directory for newly\n"
"opened consoles (Python/IPython consoles and\n"
@@ -3260,31 +3361,39 @@ msgstr ""
"поиска в файлах и для новых файлов,\n"
"созданных в редакторе"
-#: spyder/plugins/workingdirectory.py:168
+#: spyder/plugins/workingdirectory.py:166
msgid "Browse a working directory"
msgstr "Просмотреть рабочий каталог"
-#: spyder/plugins/workingdirectory.py:175
+#: spyder/plugins/workingdirectory.py:173
msgid "Change to parent directory"
msgstr "Изменить на родительский каталог"
-#: spyder/plugins/workingdirectory.py:182 spyder/widgets/findinfiles.py:225
+#: spyder/plugins/workingdirectory.py:180 spyder/widgets/findinfiles.py:240
msgid "Current working directory"
msgstr "Текущий рабочий каталог"
-#: spyder/utils/codeanalysis.py:92
+#: spyder/utils/codeanalysis.py:94
msgid "Real-time code analysis on the Editor"
msgstr "Анализ кода в Редакторе в реальном времени"
-#: spyder/utils/codeanalysis.py:96
+#: spyder/utils/codeanalysis.py:98
msgid "Real-time code style analysis on the Editor"
msgstr "Анализ стиля кода в Редакторе в реальном времени"
-#: spyder/utils/environ.py:46
+#: spyder/utils/environ.py:48
msgid "Environment variables"
msgstr "Переменные среды"
-#: spyder/utils/environ.py:96
+#: spyder/utils/environ.py:57
+msgid ""
+"An error occurred while trying to show your environment variables. The error "
+"was
{0}"
+msgstr ""
+"Во время попытки показа переменных среды произошла ошибка. А именно:"
+"
{0}"
+
+#: spyder/utils/environ.py:108
msgid ""
"Module pywin32 was not found.
Please restart this Windows "
"session (not the computer) for changes to take effect."
@@ -3292,7 +3401,7 @@ msgstr ""
"Модуль pywin32 не найден.
Пожалуйста, перезапустите сессию "
"Windows (не компьютер), чтобы изменения вступили в силу."
-#: spyder/utils/environ.py:109
+#: spyder/utils/environ.py:121
msgid ""
"If you accept changes, this will modify the current user environment "
"variables directly in Windows registry. Use it with precautions, at "
@@ -3309,7 +3418,7 @@ msgstr ""
"перезапустите Spyder, если запускали его ярлыком Windows, или перезапустите "
"приложение из которого Вы его запускали, например Python(x,y) Home)"
-#: spyder/utils/help/sphinxify.py:217 spyder/utils/help/sphinxify.py:227
+#: spyder/utils/help/sphinxify.py:216 spyder/utils/help/sphinxify.py:226
msgid ""
"It was not possible to generate rich text help for this object.Please "
"see it in plain text."
@@ -3322,133 +3431,76 @@ msgstr ""
msgid "Editor's code completion, go-to-definition and help"
msgstr "Автодополнение кода редактора, переход к определению и справка"
-#: spyder/utils/iofuncs.py:408
-msgid "Supported files"
-msgstr "Поддерживаемые файлы"
-
-#: spyder/utils/iofuncs.py:410
-msgid "All files (*.*)"
-msgstr "Все файлы (*.*)"
-
-#: spyder/utils/iofuncs.py:420
-msgid "Spyder data files"
-msgstr "Файлы данных Spyder"
-
-#: spyder/utils/iofuncs.py:422
-#: spyder/widgets/variableexplorer/collectionseditor.py:1061
-msgid "NumPy arrays"
-msgstr "Массивы NumPy"
-
-#: spyder/utils/iofuncs.py:423
-msgid "NumPy zip arrays"
-msgstr "Сжатые массивы NumPy"
-
-#: spyder/utils/iofuncs.py:424
-msgid "Matlab files"
-msgstr "Файлы Matlab"
-
-#: spyder/utils/iofuncs.py:425
-msgid "CSV text files"
-msgstr "Текстовые файлы CSV"
-
-#: spyder/utils/iofuncs.py:427
-msgid "JPEG images"
-msgstr "Изображения JPEG"
-
-#: spyder/utils/iofuncs.py:428
-msgid "PNG images"
-msgstr "Изображения PNG"
-
-#: spyder/utils/iofuncs.py:429
-msgid "GIF images"
-msgstr "Изображения GIF"
-
-#: spyder/utils/iofuncs.py:430
-msgid "TIFF images"
-msgstr "Изображения TIFF"
-
-#: spyder/utils/iofuncs.py:431 spyder/utils/iofuncs.py:432
-msgid "Pickle files"
-msgstr "Архивы Pickle"
-
-#: spyder/utils/iofuncs.py:433
-msgid "JSON files"
-msgstr "Файлы JSON"
-
-#: spyder/utils/iofuncs.py:452 spyder/utils/iofuncs.py:459
-msgid "Unsupported file type '%s'"
-msgstr "Неподдерживаемый тип файла '%s'"
-
-#: spyder/utils/programs.py:287
+#: spyder/utils/programs.py:308
msgid "It was not possible to run this file in an external terminal"
msgstr "Невозможно запустить файл во внешнем терминале"
-#: spyder/utils/syntaxhighlighters.py:34
+#: spyder/utils/syntaxhighlighters.py:35
msgid "Syntax highlighting for Matlab, Julia and other file types"
msgstr "Подсветка синтаксиса для Matlab, Julia и других типов файлов"
-#: spyder/utils/syntaxhighlighters.py:43
+#: spyder/utils/syntaxhighlighters.py:44
msgid "Background:"
msgstr "Фон:"
-#: spyder/utils/syntaxhighlighters.py:44
+#: spyder/utils/syntaxhighlighters.py:45
#: spyder/widgets/sourcecode/codeeditor.py:107
msgid "Current line:"
msgstr "Текущая строка:"
-#: spyder/utils/syntaxhighlighters.py:45
+#: spyder/utils/syntaxhighlighters.py:46
msgid "Current cell:"
msgstr "Текущий блок:"
-#: spyder/utils/syntaxhighlighters.py:46
+#: spyder/utils/syntaxhighlighters.py:47
msgid "Occurrence:"
msgstr "Вхождения слова:"
-#: spyder/utils/syntaxhighlighters.py:47
+#: spyder/utils/syntaxhighlighters.py:48
msgid "Link:"
msgstr "Ссылка:"
-#: spyder/utils/syntaxhighlighters.py:48
+#: spyder/utils/syntaxhighlighters.py:49
msgid "Side areas:"
msgstr "Боковые панели:"
-#: spyder/utils/syntaxhighlighters.py:49
+#: spyder/utils/syntaxhighlighters.py:50
msgid "Matched
parens:"
msgstr "Парные
скобки:"
-#: spyder/utils/syntaxhighlighters.py:50
+#: spyder/utils/syntaxhighlighters.py:51
msgid "Unmatched
parens:"
msgstr "Скобки
без пары:"
-#: spyder/utils/syntaxhighlighters.py:51
+#: spyder/utils/syntaxhighlighters.py:52
msgid "Normal text:"
msgstr "Обычный текст:"
-#: spyder/utils/syntaxhighlighters.py:52
+#: spyder/utils/syntaxhighlighters.py:53
msgid "Keyword:"
msgstr "Ключевое слово:"
-#: spyder/utils/syntaxhighlighters.py:53
+#: spyder/utils/syntaxhighlighters.py:54
msgid "Builtin:"
msgstr "Встроенные:"
-#: spyder/utils/syntaxhighlighters.py:54
+#: spyder/utils/syntaxhighlighters.py:55
msgid "Definition:"
msgstr "Определение:"
-#: spyder/utils/syntaxhighlighters.py:55
+#: spyder/utils/syntaxhighlighters.py:56
msgid "Comment:"
msgstr "Комментарий:"
-#: spyder/utils/syntaxhighlighters.py:56
+#: spyder/utils/syntaxhighlighters.py:57
msgid "String:"
msgstr "Строка:"
-#: spyder/utils/syntaxhighlighters.py:57
+#: spyder/utils/syntaxhighlighters.py:58
msgid "Number:"
msgstr "Число:"
-#: spyder/utils/syntaxhighlighters.py:58
+#: spyder/utils/syntaxhighlighters.py:59
msgid "Instance:"
msgstr "Экземпляр класса:"
@@ -3505,45 +3557,45 @@ msgstr ""
msgid "Array dimensions not valid"
msgstr "Неверная размерность массива"
-#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2731
+#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2738
msgid "Zoom out"
msgstr "Уменьшить"
-#: spyder/widgets/browser.py:61 spyder/widgets/sourcecode/codeeditor.py:2727
+#: spyder/widgets/browser.py:61 spyder/widgets/sourcecode/codeeditor.py:2734
msgid "Zoom in"
msgstr "Увеличить"
-#: spyder/widgets/browser.py:213
+#: spyder/widgets/browser.py:216
msgid "Home"
msgstr "Домой"
-#: spyder/widgets/browser.py:249
+#: spyder/widgets/browser.py:252
msgid "Find text"
msgstr "Найти текст"
-#: spyder/widgets/browser.py:266
+#: spyder/widgets/browser.py:269
msgid "Address:"
msgstr "Адрес:"
-#: spyder/widgets/browser.py:302
+#: spyder/widgets/browser.py:305
msgid "Unable to load page"
msgstr "Не удалось загрузить страницу"
-#: spyder/widgets/comboboxes.py:164
+#: spyder/widgets/comboboxes.py:165
msgid "Press enter to validate this entry"
msgstr "Нажмите Enter для подтверждения этого поля"
-#: spyder/widgets/comboboxes.py:165
+#: spyder/widgets/comboboxes.py:166
msgid "This entry is incorrect"
msgstr "Это поле неверно"
-#: spyder/widgets/comboboxes.py:208
+#: spyder/widgets/comboboxes.py:209
msgid "Press enter to validate this path"
msgstr "Нажмите Enter для подтверждения этого пути"
#: spyder/widgets/dependencies.py:63
msgid " Required "
-msgstr " требуется"
+msgstr " Требуется "
#: spyder/widgets/dependencies.py:63
msgid "Module"
@@ -3551,7 +3603,7 @@ msgstr "Модуль"
#: spyder/widgets/dependencies.py:64
msgid " Installed "
-msgstr " установлен"
+msgstr " Установлено "
#: spyder/widgets/dependencies.py:64
msgid "Provided features"
@@ -3582,77 +3634,78 @@ msgstr ""
msgid "Copy to clipboard"
msgstr "Копировать в буфер обмена"
-#: spyder/widgets/editor.py:501
+#: spyder/widgets/editor.py:511
msgid "Find symbols in file..."
msgstr "Найти в файлe..."
-#: spyder/widgets/editor.py:504
+#: spyder/widgets/editor.py:514
msgid "Copy path to clipboard"
msgstr "Копировать путь в буфер обмена"
-#: spyder/widgets/editor.py:508
+#: spyder/widgets/editor.py:518
msgid "Close all to the right"
msgstr "Закрыть все правее"
-#: spyder/widgets/editor.py:510
+#: spyder/widgets/editor.py:520
msgid "Close all but this"
msgstr "Закрыть все кроме этой"
-#: spyder/widgets/editor.py:514 spyder/widgets/explorer.py:370
+#: spyder/widgets/editor.py:524 spyder/widgets/explorer.py:373
msgid "Show in Finder"
msgstr "Показывать в Поиске"
-#: spyder/widgets/editor.py:516 spyder/widgets/explorer.py:372
+#: spyder/widgets/editor.py:526 spyder/widgets/explorer.py:375
msgid "Show in external file explorer"
msgstr "Показать менеджер файлов"
-#: spyder/widgets/editor.py:1193
+#: spyder/widgets/editor.py:1201
msgid "Temporary file"
msgstr "Временный файл"
-#: spyder/widgets/editor.py:1279
+#: spyder/widgets/editor.py:1287
msgid "New window"
msgstr "Новое окно"
-#: spyder/widgets/editor.py:1280
+#: spyder/widgets/editor.py:1288
msgid "Create a new editor window"
msgstr "Создать новое окно редактора"
-#: spyder/widgets/editor.py:1283
+#: spyder/widgets/editor.py:1291
msgid "Split vertically"
msgstr "Разделить по вертикали"
-#: spyder/widgets/editor.py:1285
+#: spyder/widgets/editor.py:1293
msgid "Split vertically this editor window"
msgstr "Разделить окна редактора по вертикали"
-#: spyder/widgets/editor.py:1287
+#: spyder/widgets/editor.py:1295
msgid "Split horizontally"
msgstr "Разделить по горизонтали"
-#: spyder/widgets/editor.py:1289
+#: spyder/widgets/editor.py:1297
msgid "Split horizontally this editor window"
msgstr "Разделить окна редактора по горизонтали"
-#: spyder/widgets/editor.py:1291
+#: spyder/widgets/editor.py:1299
msgid "Close this panel"
msgstr "Закрыть эту панель"
-#: spyder/widgets/editor.py:1531
+#: spyder/widgets/editor.py:1534
msgid "%s has been modified.
Do you want to save changes?"
msgstr "%s был изменён.
Хотите сохранить изменения?"
-#: spyder/widgets/editor.py:1617 spyder/widgets/editor.py:1780
-msgid "Save"
-msgstr "Сохранить"
+#: spyder/widgets/editor.py:1620 spyder/widgets/editor.py:1783
+#: spyder/widgets/explorer.py:82
+msgid "Save Error"
+msgstr "Сохранить ошибку"
-#: spyder/widgets/editor.py:1618 spyder/widgets/editor.py:1781
-#: spyder/widgets/shell.py:267
+#: spyder/widgets/editor.py:1621 spyder/widgets/editor.py:1784
+#: spyder/widgets/explorer.py:83
msgid "Unable to save file '%s'
Error message:
%s"
msgstr ""
"Невозможно сохранить файл %s
Сообщение об ошибке:
%s"
-#: spyder/widgets/editor.py:1968
+#: spyder/widgets/editor.py:1971
msgid ""
"%s is unavailable (this file may have been removed, moved or renamed "
"outside Spyder).
Do you want to close it?"
@@ -3660,7 +3713,7 @@ msgstr ""
"%s недоступен (этот файл мог быть удален, перемещён или переименован "
"вне Spyder).
Хотите его закрыть?"
-#: spyder/widgets/editor.py:1991
+#: spyder/widgets/editor.py:1994
msgid ""
"%s has been modified outside Spyder.
Do you want to reload it and "
"lose all your changes?"
@@ -3668,7 +3721,7 @@ msgstr ""
"%s был изменён вне Spyder.
Хотите перегрузить его и потерять все "
"изменения?"
-#: spyder/widgets/editor.py:2101
+#: spyder/widgets/editor.py:2104
msgid ""
"All changes to %s will be lost.
Do you want to revert file from "
"disk?"
@@ -3676,11 +3729,11 @@ msgstr ""
"Все изменения для %s были потеряны.
Хотите перегрузить файл с "
"диска?"
-#: spyder/widgets/editor.py:2245
+#: spyder/widgets/editor.py:2250
msgid "Loading %s..."
msgstr "Загрузка %s..."
-#: spyder/widgets/editor.py:2257
+#: spyder/widgets/editor.py:2262
msgid ""
"%s contains mixed end-of-line characters.
Spyder will fix this "
"automatically."
@@ -3688,11 +3741,11 @@ msgstr ""
"%s содержит смешанные символы конца строки.
Spyder исправит это "
"автоматически."
-#: spyder/widgets/editor.py:2664
+#: spyder/widgets/editor.py:2672
msgid "Close window"
msgstr "Закрыть окно"
-#: spyder/widgets/editor.py:2666
+#: spyder/widgets/editor.py:2674
msgid "Close this window"
msgstr "Закрыть это окно"
@@ -3724,7 +3777,7 @@ msgstr "Перейти к позиции курсора"
msgid "Show absolute path"
msgstr "Показать полный путь"
-#: spyder/widgets/editortools.py:207 spyder/widgets/explorer.py:283
+#: spyder/widgets/editortools.py:207 spyder/widgets/explorer.py:286
msgid "Show all files"
msgstr "Показать все файлы"
@@ -3736,56 +3789,56 @@ msgstr "Показать специальные комментарии"
msgid "Show/hide outline explorer"
msgstr "Показать/скрыть менеджер структуры"
-#: spyder/widgets/explorer.py:279
+#: spyder/widgets/explorer.py:282
msgid "Edit filename filters..."
msgstr "Редактировать фильтры имён файлов..."
-#: spyder/widgets/explorer.py:293
+#: spyder/widgets/explorer.py:296
msgid "Edit filename filters"
msgstr "Редактировать фильтры имён файлов"
-#: spyder/widgets/explorer.py:294
+#: spyder/widgets/explorer.py:297
msgid "Name filters:"
msgstr "Фильтры имён:"
-#: spyder/widgets/explorer.py:313
+#: spyder/widgets/explorer.py:316
msgid "File..."
msgstr "Файл..."
-#: spyder/widgets/explorer.py:317
+#: spyder/widgets/explorer.py:320
msgid "Module..."
msgstr "Модуль..."
-#: spyder/widgets/explorer.py:321
+#: spyder/widgets/explorer.py:324
msgid "Folder..."
msgstr "Каталог..."
-#: spyder/widgets/explorer.py:325
+#: spyder/widgets/explorer.py:328
msgid "Package..."
msgstr "Пакет..."
-#: spyder/widgets/explorer.py:346
-#: spyder/widgets/variableexplorer/collectionseditor.py:677
+#: spyder/widgets/explorer.py:349
+#: spyder/widgets/variableexplorer/collectionseditor.py:713
msgid "Edit"
msgstr "Редактировать"
-#: spyder/widgets/explorer.py:348
+#: spyder/widgets/explorer.py:351
msgid "Move..."
msgstr "Переместить..."
-#: spyder/widgets/explorer.py:351
+#: spyder/widgets/explorer.py:354
msgid "Delete..."
msgstr "Удалить..."
-#: spyder/widgets/explorer.py:354
+#: spyder/widgets/explorer.py:357
msgid "Rename..."
msgstr "Переименовать..."
-#: spyder/widgets/explorer.py:357
+#: spyder/widgets/explorer.py:360
msgid "Open"
msgstr "Открыть"
-#: spyder/widgets/explorer.py:358 spyder/widgets/sourcecode/codeeditor.py:2699
+#: spyder/widgets/explorer.py:361 spyder/widgets/sourcecode/codeeditor.py:2706
msgid "Convert to Python script"
msgstr "Сохранить как скрипт Python"
@@ -3793,56 +3846,56 @@ msgstr "Сохранить как скрипт Python"
# - оставить без перевода
# - использовать кальку: "коммитить"
# - воспользоваться переводом из источников про Git (например, книга ProGit): "зафиксирвать изменения/индекс".
-#: spyder/widgets/explorer.py:399
+#: spyder/widgets/explorer.py:393
msgid "Commit"
msgstr "Зафиксировать"
-#: spyder/widgets/explorer.py:402
+#: spyder/widgets/explorer.py:396
msgid "Browse repository"
msgstr "Просмотр репозитария"
-#: spyder/widgets/explorer.py:413
+#: spyder/widgets/explorer.py:407
msgid "Open command prompt here"
msgstr "Открыть командную строку здесь"
-#: spyder/widgets/explorer.py:415
+#: spyder/widgets/explorer.py:409
msgid "Open terminal here"
msgstr "Открыть терминал здесь"
-#: spyder/widgets/explorer.py:416
+#: spyder/widgets/explorer.py:410
msgid "Open IPython console here"
msgstr "Открыть консоль IPython здесь"
-#: spyder/widgets/explorer.py:430
+#: spyder/widgets/explorer.py:424
msgid "New"
msgstr "Новый"
-#: spyder/widgets/explorer.py:438
+#: spyder/widgets/explorer.py:432
msgid "Import"
msgstr "Импортировать"
-#: spyder/widgets/explorer.py:584
+#: spyder/widgets/explorer.py:583
msgid "Do you really want to delete %s?"
msgstr "Вы точно хотите удалить %s?"
-#: spyder/widgets/explorer.py:602
+#: spyder/widgets/explorer.py:601
msgid "delete"
msgstr "удалить"
-#: spyder/widgets/explorer.py:603 spyder/widgets/projects/explorer.py:148
+#: spyder/widgets/explorer.py:602 spyder/widgets/projects/explorer.py:148
#: spyder/widgets/projects/explorer.py:256
msgid "Project Explorer"
msgstr "Менеджер проектов"
-#: spyder/widgets/explorer.py:604 spyder/widgets/projects/explorer.py:149
+#: spyder/widgets/explorer.py:603 spyder/widgets/projects/explorer.py:149
msgid "Unable to %s %s
Error message:
%s"
msgstr "Невозможно %s %s
Сообщение об ошибке:
%s"
-#: spyder/widgets/explorer.py:619
+#: spyder/widgets/explorer.py:618
msgid "File Explorer"
msgstr "Файловый менеджер"
-#: spyder/widgets/explorer.py:620
+#: spyder/widgets/explorer.py:619
msgid ""
"The current directory contains a project.
If you want to delete the "
"project, please go to Projects » Delete Project"
@@ -3850,11 +3903,11 @@ msgstr ""
"В текущий каталоге находится проект.
Если вы хотите удалить проект, "
"пожалуйста, воспользуйтесь меню Проекты » Удалить проект"
-#: spyder/widgets/explorer.py:637 spyder/widgets/sourcecode/codeeditor.py:2160
+#: spyder/widgets/explorer.py:636 spyder/widgets/sourcecode/codeeditor.py:2167
msgid "Conversion error"
msgstr "Ошибка преобразования"
-#: spyder/widgets/explorer.py:638 spyder/widgets/sourcecode/codeeditor.py:2161
+#: spyder/widgets/explorer.py:637 spyder/widgets/sourcecode/codeeditor.py:2168
msgid ""
"It was not possible to convert this notebook. The error is:\n"
"\n"
@@ -3862,18 +3915,18 @@ msgstr ""
"Не удалось сконвертировать этот блокнот. Ошибка:\n"
"\n"
-#: spyder/widgets/explorer.py:655 spyder/widgets/explorer.py:663
-#: spyder/widgets/explorer.py:674
-#: spyder/widgets/variableexplorer/collectionseditor.py:706
-#: spyder/widgets/variableexplorer/collectionseditor.py:952
+#: spyder/widgets/explorer.py:654 spyder/widgets/explorer.py:662
+#: spyder/widgets/explorer.py:676
+#: spyder/widgets/variableexplorer/collectionseditor.py:742
+#: spyder/widgets/variableexplorer/collectionseditor.py:988
msgid "Rename"
msgstr "Переименовать"
-#: spyder/widgets/explorer.py:656
+#: spyder/widgets/explorer.py:655
msgid "New name:"
msgstr "Новое имя:"
-#: spyder/widgets/explorer.py:664
+#: spyder/widgets/explorer.py:663
msgid ""
"Do you really want to rename %s and overwrite the existing file "
"%s?"
@@ -3881,81 +3934,83 @@ msgstr ""
"Вы действительно хотите переименовать %s или перезаписать "
"существующий файл %s?"
-#: spyder/widgets/explorer.py:675
+#: spyder/widgets/explorer.py:677
msgid "Unable to rename file %s
Error message:
%s"
msgstr ""
"Невозможно переименовать файл %s
Сообщение об ошибке:"
"
%s"
-#: spyder/widgets/explorer.py:722
+#: spyder/widgets/explorer.py:724
msgid "Unable to move %s
Error message:
%s"
msgstr ""
"Невозможно переместить файл %s
Сообщение об ошибке:
"
"%s"
-#: spyder/widgets/explorer.py:740
+#: spyder/widgets/explorer.py:742
msgid "Unable to create folder %s
Error message:
%s"
msgstr ""
"Невозможно создать каталог %s
Сообщение об ошибке:
%s"
-#: spyder/widgets/explorer.py:753 spyder/widgets/explorer.py:787
+#: spyder/widgets/explorer.py:755 spyder/widgets/explorer.py:789
msgid "Unable to create file %s
Error message:
%s"
msgstr ""
"Невозможно создать файл %s
Сообщение об ошибке:
%s"
-#: spyder/widgets/explorer.py:761
+#: spyder/widgets/explorer.py:763
msgid "New folder"
msgstr "Новый каталог"
-#: spyder/widgets/explorer.py:762
+#: spyder/widgets/explorer.py:764
msgid "Folder name:"
msgstr "Имя каталога:"
-#: spyder/widgets/explorer.py:767
+#: spyder/widgets/explorer.py:769
msgid "New package"
msgstr "Новый пакет"
-#: spyder/widgets/explorer.py:768
+#: spyder/widgets/explorer.py:770
msgid "Package name:"
msgstr "Имя пакета:"
-#: spyder/widgets/explorer.py:808
+#: spyder/widgets/explorer.py:810
msgid "New module"
msgstr "Новый модуль"
-#: spyder/widgets/explorer.py:823
+#: spyder/widgets/explorer.py:825
msgid ""
"For %s support, please install one of the
following tools:
%s"
msgstr ""
"Для поддержки %s, установите, пожалуйста,
один из следующих "
"инструментов:
%s"
-#: spyder/widgets/explorer.py:827
+#: spyder/widgets/explorer.py:829
msgid "Unable to find external program.
%s"
msgstr "Не удалось найти внешнюю программу.
%s"
-#: spyder/widgets/explorer.py:1048
+#: spyder/widgets/explorer.py:1049
msgid "Show current directory only"
msgstr "Показывать только текущий каталог"
-#: spyder/widgets/explorer.py:1158
+#: spyder/widgets/explorer.py:1163
msgid "You don't have the right permissions to open this directory"
msgstr "У Вас нет прав на открытие этой директории"
-#: spyder/widgets/explorer.py:1189
+#: spyder/widgets/explorer.py:1194
msgid "Show icons and text"
msgstr "Показывать иконки и текст"
-#: spyder/widgets/explorer.py:1191
+#: spyder/widgets/explorer.py:1196
#: spyder/widgets/variableexplorer/importwizard.py:535
msgid "Previous"
msgstr "Предыдущая"
-#: spyder/widgets/explorer.py:1197
+#: spyder/widgets/explorer.py:1202
msgid "Parent"
msgstr "Родительская"
#: spyder/widgets/fileswitcher.py:110
+#: spyder/plugins/pylint/widgets/pylintgui.py:364
+#: spyder/plugins/profiler/widgets/profilergui.py:296
msgid "unsaved file"
msgstr "несохранённый файл"
@@ -3967,284 +4022,410 @@ msgid ""
"g. @init
Press Ctrl+W to close current "
"tab.
"
msgstr ""
-"Нажмите Enter для перехода к файлу или Esc для отмены."
-"
Введите текст для фильтрации имен файлов.
Используйте :"
-"номер для перехода к строке, напр. main:42
"
-"b>
Используйте @имя для перехода к идентификатору, напр. "
-"@init
Нажмите Ctrl+W для закрытия текущей "
-"вкладки."
+"Нажмите Enter, чтобы изменить файлы или Esc для отмены."
+"
Введите имена файлов для фильтрации.
Используйте :номер"
+"b> для перехода к строке, напр. main:42
Используйте "
+"@symbol_text для перехода к символу, напр. @init
"
+"b>
Нажмите Ctrl+W для закрытия текущей вкладки.
"
#: spyder/widgets/fileswitcher.py:663
msgid "lines"
-msgstr " строк"
+msgstr "строк"
-#: spyder/widgets/findinfiles.py:124
+#: spyder/widgets/findinfiles.py:121
msgid "Unexpected error: see internal console"
msgstr "Неожиданная ошибка: смотрите во встроенной консоли"
-#: spyder/widgets/findinfiles.py:152
+#: spyder/widgets/findinfiles.py:158
msgid "invalid regular expression"
msgstr "неверное регулярное выражение"
-#: spyder/widgets/findinfiles.py:202
+#: spyder/widgets/findinfiles.py:217
msgid "permission denied errors were encountered"
msgstr "обнаружены ошибки отказа в доступе"
-#: spyder/widgets/findinfiles.py:217
+#: spyder/widgets/findinfiles.py:232
msgid "Search directory"
msgstr "Каталог поиска"
-#: spyder/widgets/findinfiles.py:230
+#: spyder/widgets/findinfiles.py:245
msgid "Project"
msgstr "Проект"
-#: spyder/widgets/findinfiles.py:231
+#: spyder/widgets/findinfiles.py:246
msgid ""
"Search in all files and directories present on the current project path (if "
"opened)"
msgstr "Искать во всех файлах и каталогах в текущем пути проекта (если открыт)"
-#: spyder/widgets/findinfiles.py:236
+#: spyder/widgets/findinfiles.py:251
msgid "File"
msgstr "Файл"
-#: spyder/widgets/findinfiles.py:237
+#: spyder/widgets/findinfiles.py:252
msgid "Search in current opened file"
msgstr "Искать в текущем открытом файле"
-#: spyder/widgets/findinfiles.py:242
+#: spyder/widgets/findinfiles.py:257
msgid "Select other directory"
msgstr "Выберите другой каталог"
-#: spyder/widgets/findinfiles.py:243
+#: spyder/widgets/findinfiles.py:258
msgid "Search in other folder present on the file system"
msgstr "Искать в другом каталоге файловой системы"
-#: spyder/widgets/findinfiles.py:247
+#: spyder/widgets/findinfiles.py:262
msgid "Clear the list of other directories"
msgstr "Очистить список дополнительных каталогов"
-#: spyder/widgets/findinfiles.py:318
+#: spyder/widgets/findinfiles.py:333
msgid "Clear other directories"
msgstr "Удалить другие каталоги"
-#: spyder/widgets/findinfiles.py:319
+#: spyder/widgets/findinfiles.py:334
msgid "Do you want to clear the list of other directories?"
msgstr "Вы уверены, что хотите очистить список дополнительных каталогов?"
-#: spyder/widgets/findinfiles.py:415
+#: spyder/widgets/findinfiles.py:404 spyder/widgets/findreplace.py:52
+msgid "Regular expression error"
+msgstr "Ошибка в регулярном выражении"
+
+#: spyder/widgets/findinfiles.py:427
msgid "Search pattern"
msgstr "Найти по шаблону"
-#: spyder/widgets/findinfiles.py:418 spyder/widgets/findinfiles.py:458
-#: spyder/widgets/findreplace.py:99
+#: spyder/widgets/findinfiles.py:430 spyder/widgets/findinfiles.py:470
+#: spyder/widgets/findreplace.py:100
msgid "Regular expression"
msgstr "Регулярное выражение"
-#: spyder/widgets/findinfiles.py:421 spyder/widgets/findreplace.py:105
+#: spyder/widgets/findinfiles.py:433 spyder/widgets/findreplace.py:106
msgid "Case Sensitive"
msgstr "С учетом регистра"
-#: spyder/widgets/findinfiles.py:432
+#: spyder/widgets/findinfiles.py:444
msgid "Search"
msgstr "Найти"
-#: spyder/widgets/findinfiles.py:435
+#: spyder/widgets/findinfiles.py:447
msgid "Start search"
msgstr "Начать поиск"
-#: spyder/widgets/findinfiles.py:442
+#: spyder/widgets/findinfiles.py:454
msgid "Stop search"
msgstr "Остановить поиск"
-#: spyder/widgets/findinfiles.py:452
-msgid "Excluded filenames pattern"
-msgstr "Шаблон имён исключаемых файлов"
+#: spyder/widgets/findinfiles.py:464
+msgid "Exclude pattern"
+msgstr "Шаблон исключений"
-#: spyder/widgets/findinfiles.py:461
+#: spyder/widgets/findinfiles.py:473
msgid "Exclude:"
msgstr "Исключить:"
-#: spyder/widgets/findinfiles.py:470
+#: spyder/widgets/findinfiles.py:482
msgid "Search in:"
msgstr "Искать в:"
-#: spyder/widgets/findinfiles.py:499
+#: spyder/widgets/findinfiles.py:511
msgid "Hide advanced options"
msgstr "Скрыть дополнительные опции"
-#: spyder/widgets/findinfiles.py:502
+#: spyder/widgets/findinfiles.py:514
msgid "Show advanced options"
msgstr "Показать дополнительные опции"
-#: spyder/widgets/findinfiles.py:759 spyder/widgets/findinfiles.py:843
+#: spyder/widgets/findinfiles.py:790 spyder/widgets/findinfiles.py:877
msgid "String not found"
msgstr "Строка не найдена"
-#: spyder/widgets/findinfiles.py:845
+#: spyder/widgets/findinfiles.py:879
msgid "matches in"
msgstr "совпадений в"
-#: spyder/widgets/findinfiles.py:846
+#: spyder/widgets/findinfiles.py:880
msgid "file"
msgstr "файл"
-#: spyder/widgets/findinfiles.py:878
+#: spyder/widgets/findinfiles.py:912
msgid " Scanning: {0}"
msgstr " Сканирование: {0}"
-#: spyder/widgets/findinfiles.py:880
+#: spyder/widgets/findinfiles.py:914
msgid " Searching for files in folder: {0}"
msgstr " Поиск файлов в директории: {0}"
-#: spyder/widgets/findinfiles.py:884
+#: spyder/widgets/findinfiles.py:918
msgid " Searching for files..."
msgstr " Поиск файлов..."
-#: spyder/widgets/findreplace.py:48
+#: spyder/widgets/findreplace.py:49
msgid "No matches"
msgstr "Нет совпадений"
-#: spyder/widgets/findreplace.py:49 spyder/widgets/findreplace.py:50
-#: spyder/widgets/findreplace.py:72
+#: spyder/widgets/findreplace.py:50 spyder/widgets/findreplace.py:51
+#: spyder/widgets/findreplace.py:73
msgid "Search string"
msgstr "Найти строку"
-#: spyder/widgets/findreplace.py:51
-msgid "Regular expression error"
-msgstr "Ошибка в регулярном выражении"
-
-#: spyder/widgets/findreplace.py:111
+#: spyder/widgets/findreplace.py:112
msgid "Whole words"
msgstr "Слова целиком"
-#: spyder/widgets/findreplace.py:117
+#: spyder/widgets/findreplace.py:118
msgid "Highlight matches"
msgstr "Подсвечивать найденные"
-#: spyder/widgets/findreplace.py:131
+#: spyder/widgets/findreplace.py:132
msgid "Replace with:"
msgstr "Заменить на:"
-#: spyder/widgets/findreplace.py:133
+#: spyder/widgets/findreplace.py:134
msgid "Replace string"
msgstr "Заменить строку"
-#: spyder/widgets/findreplace.py:137
+#: spyder/widgets/findreplace.py:138
msgid "Replace/find next"
msgstr "Заменить/найти далее"
-#: spyder/widgets/findreplace.py:142
+#: spyder/widgets/findreplace.py:143
msgid "Replace selection"
msgstr "Заменить выделенное"
-#: spyder/widgets/findreplace.py:150
+#: spyder/widgets/findreplace.py:151
msgid "Replace all"
msgstr "Заменить все"
-#: spyder/widgets/findreplace.py:577
+#: spyder/widgets/findreplace.py:583
msgid "of"
msgstr "из"
-#: spyder/widgets/findreplace.py:581
+#: spyder/widgets/findreplace.py:587
msgid "matches"
msgstr "совпадений"
-#: spyder/widgets/findreplace.py:584
+#: spyder/widgets/findreplace.py:590
msgid "no matches"
msgstr "нет совпадений"
-#: spyder/widgets/internalshell.py:262
+#: spyder/widgets/github/backend.py:151
+msgid "Invalid credentials"
+msgstr "Неверные учетные данные"
+
+#: spyder/widgets/github/backend.py:152
+msgid "Failed to create Github issue, invalid credentials..."
+msgstr ""
+"Не удалось создать сообщение о проблеме на Github, неверные учетные данные..."
+
+#: spyder/widgets/github/backend.py:159
+msgid "Failed to create issue"
+msgstr "Не удалось создать сообщение о проблеме"
+
+#: spyder/widgets/github/backend.py:160
+msgid "Failed to create Github issue. Error %d"
+msgstr "Не удалось создать сообщение о проблеме на Github. Ошибка %d"
+
+#: spyder/widgets/github/backend.py:167
+msgid "Issue created on Github"
+msgstr "Проблема создана на Github"
+
+#: spyder/widgets/github/backend.py:168
+msgid ""
+"Issue successfully created. Would you like to open the issue in your web "
+"browser?"
+msgstr ""
+"Сообщение о проблеме успешно создано. Хотите открыть его в Вашем браузере?"
+
+#: spyder/widgets/github/backend.py:195
+msgid "Failed to store password"
+msgstr "Не удалось сохранить пароль"
+
+#: spyder/widgets/github/backend.py:196
+msgid ""
+"It was not possible to securely save your password. You will be prompted for "
+"your Github credentials next time you want to report an issue."
+msgstr ""
+
+#: spyder/widgets/github/backend.py:212
+msgid "Failed to store token"
+msgstr "Не удалось сохранить токен"
+
+#: spyder/widgets/github/backend.py:213
+msgid ""
+"It was not possible to securely save your token. You will be prompted for "
+"your Github token next time you want to report an issue."
+msgstr ""
+
+#: spyder/widgets/github/backend.py:237
+msgid "Failed to retrieve password"
+msgstr "Не удалось получить пароль"
+
+#: spyder/widgets/github/backend.py:238
+msgid ""
+"It was not possible to retrieve your password. Please introduce it again."
+msgstr "Не удалось получить Ваш пароль. Пожалуйста, введите его снова."
+
+#: spyder/widgets/github/backend.py:249
+msgid "Failed to retrieve token"
+msgstr "Не удалось получить токен"
+
+#: spyder/widgets/github/backend.py:250
+msgid "It was not possible to retrieve your token. Please introduce it again."
+msgstr "Не удалось получить Ваш токен. Пожалуйста, введите его снова."
+
+#: spyder/widgets/github/gh_login.py:38
+msgid "Sign in to Github"
+msgstr "Войти на Github"
+
+#: spyder/widgets/github/gh_login.py:57
+msgid ""
+"For regular users, i.e. users without two-factor authentication "
+"enabled"
+msgstr ""
+"Для обычных пользователей, например пользователей без включенной "
+"двуфакторной авторизации"
+
+#: spyder/widgets/github/gh_login.py:62
+msgid "Username:"
+msgstr "Имя пользователя:"
+
+#: spyder/widgets/github/gh_login.py:69
+msgid "Password: "
+msgstr "Пароль: "
+
+#: spyder/widgets/github/gh_login.py:81
+msgid "Remember me"
+msgstr "Запомнить меня"
+
+#: spyder/widgets/github/gh_login.py:82
+msgid "Spyder will save your credentials safely"
+msgstr "Spyder сохранит Ваши учетные данные безопасно"
+
+#: spyder/widgets/github/gh_login.py:99
+msgid "Password Only"
+msgstr "Только пароль"
+
+#: spyder/widgets/github/gh_login.py:105
+msgid ""
+"For users with two-factor authentication enabled, or who prefer a per-"
+"app token authentication.
You can go here "
+"and click \"Generate token\" at the bottom to create a new token to use for "
+"this, with the appropriate permissions."
+msgstr ""
+
+#: spyder/widgets/github/gh_login.py:127
+msgid "Remember token"
+msgstr "Запомнить токен"
+
+#: spyder/widgets/github/gh_login.py:128
+msgid "Spyder will save your token safely"
+msgstr "Spyder сохранит Ваш токен безопасно"
+
+#: spyder/widgets/github/gh_login.py:145
+msgid "Access Token"
+msgstr "Токен доступа"
+
+#: spyder/widgets/github/gh_login.py:148
+msgid "Sign in"
+msgstr "Войти"
+
+#: spyder/widgets/internalshell.py:263
msgid "Help..."
msgstr "Справка..."
-#: spyder/widgets/internalshell.py:279
+#: spyder/widgets/internalshell.py:280
msgid "Shell special commands:"
msgstr "Специальные команды оболочки:"
-#: spyder/widgets/internalshell.py:280
+#: spyder/widgets/internalshell.py:281
msgid "Internal editor:"
msgstr "Встроенный редактор:"
-#: spyder/widgets/internalshell.py:281
+#: spyder/widgets/internalshell.py:282
msgid "External editor:"
msgstr "Внешний редактор:"
-#: spyder/widgets/internalshell.py:282
+#: spyder/widgets/internalshell.py:283
msgid "Run script:"
msgstr "Выполнить скрипт:"
-#: spyder/widgets/internalshell.py:283
+#: spyder/widgets/internalshell.py:284
msgid "Remove references:"
msgstr "Удалить ссылки:"
-#: spyder/widgets/internalshell.py:284
+#: spyder/widgets/internalshell.py:285
msgid "System commands:"
msgstr "Системные команды:"
-#: spyder/widgets/internalshell.py:285
+#: spyder/widgets/internalshell.py:286
msgid "Python help:"
msgstr "Справка Python:"
-#: spyder/widgets/internalshell.py:286
+#: spyder/widgets/internalshell.py:287
msgid "GUI-based editor:"
msgstr "Визуальный редактор:"
-#: spyder/widgets/ipythonconsole/client.py:272
+#: spyder/widgets/internalshell.py:418
+msgid ""
+"In order to use commands like \"raw_input\" or \"input\" run Spyder with the "
+"multithread option (--multithread) from a system terminal"
+msgstr ""
+
+#: spyder/widgets/ipythonconsole/client.py:308
msgid "An error ocurred while starting the kernel"
msgstr "При запуске ядра произошла ошибка"
-#: spyder/widgets/ipythonconsole/client.py:313
-#: spyder/widgets/ipythonconsole/client.py:369
-#: spyder/widgets/ipythonconsole/client.py:402
-#: spyder/widgets/ipythonconsole/shell.py:233
-#: spyder/widgets/variableexplorer/namespacebrowser.py:193
+#: spyder/widgets/ipythonconsole/client.py:352
+#: spyder/widgets/ipythonconsole/client.py:408
+#: spyder/widgets/ipythonconsole/client.py:441
+#: spyder/widgets/ipythonconsole/shell.py:234
+#: spyder/widgets/variableexplorer/namespacebrowser.py:196
msgid "Remove all variables"
msgstr "Удалить все переменные"
-#: spyder/widgets/ipythonconsole/client.py:322
+#: spyder/widgets/ipythonconsole/client.py:361
msgid "Show environment variables"
msgstr "Показать переменные среды"
-#: spyder/widgets/ipythonconsole/client.py:329
+#: spyder/widgets/ipythonconsole/client.py:368
msgid "Show sys.path contents"
msgstr "Показать содержимое sys.path"
-#: spyder/widgets/ipythonconsole/client.py:356
+#: spyder/widgets/ipythonconsole/client.py:395
msgid "Stop the current command"
msgstr "Остановить текущую команду"
-#: spyder/widgets/ipythonconsole/client.py:367
-#: spyder/widgets/variableexplorer/collectionseditor.py:699
-#: spyder/widgets/variableexplorer/collectionseditor.py:934
+#: spyder/widgets/ipythonconsole/client.py:406
+#: spyder/widgets/variableexplorer/collectionseditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:970
msgid "Remove"
msgstr "Удалить"
-#: spyder/widgets/ipythonconsole/client.py:390
+#: spyder/widgets/ipythonconsole/client.py:429
msgid "Inspect current object"
msgstr "Проверить текущий объект"
-#: spyder/widgets/ipythonconsole/client.py:396
+#: spyder/widgets/ipythonconsole/client.py:435
msgid "Clear line or block"
msgstr "Очистить строку или блок"
-#: spyder/widgets/ipythonconsole/client.py:409
+#: spyder/widgets/ipythonconsole/client.py:448
msgid "Clear console"
msgstr "Очистить консоль"
-#: spyder/widgets/ipythonconsole/client.py:462
+#: spyder/widgets/ipythonconsole/client.py:507
msgid "Are you sure you want to restart the kernel?"
msgstr "Вы уверены, что хотите перезапустить ядро?"
-#: spyder/widgets/ipythonconsole/client.py:464
+#: spyder/widgets/ipythonconsole/client.py:509
msgid "Restart kernel?"
msgstr "Перезапустить ядро?"
-#: spyder/widgets/ipythonconsole/client.py:476
+#: spyder/widgets/ipythonconsole/client.py:526
msgid "Error restarting kernel: %s\n"
msgstr "Ошибка при перезапуске ядра: %s\n"
-#: spyder/widgets/ipythonconsole/client.py:484
+#: spyder/widgets/ipythonconsole/client.py:534
msgid ""
"
Restarting kernel...\n"
"
"
@@ -4252,38 +4433,38 @@ msgstr ""
"
Перезапуск ядра...\n"
"
"
-#: spyder/widgets/ipythonconsole/client.py:488
+#: spyder/widgets/ipythonconsole/client.py:538
msgid "Cannot restart a kernel not started by Spyder\n"
msgstr "Не удается перезапусть ядро, запущенное не из Spyder\n"
-#: spyder/widgets/ipythonconsole/client.py:597
+#: spyder/widgets/ipythonconsole/client.py:649
msgid "Connecting to kernel..."
msgstr "Подключение к ядру..."
-#: spyder/widgets/ipythonconsole/help.py:128 spyder/widgets/mixins.py:712
+#: spyder/widgets/ipythonconsole/help.py:128 spyder/widgets/mixins.py:726
msgid "Arguments"
msgstr "Аргументы"
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:129
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:138
msgid "Loading this kind of data while debugging is not supported."
msgstr "Загрузка этого типа данных во время отладки не поддерживается."
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:148
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:157
msgid "Saving data while debugging is not supported."
msgstr "Сохранение данных во время отладки не поддерживается."
-#: spyder/widgets/ipythonconsole/shell.py:234
+#: spyder/widgets/ipythonconsole/shell.py:235
msgid ""
"All user-defined variables will be removed. Are you sure you want to proceed?"
msgstr ""
"Все пользовательские переменные будут удалены.
Вы уверены, что хотите "
"продолжить?"
-#: spyder/widgets/ipythonconsole/shell.py:240
+#: spyder/widgets/ipythonconsole/shell.py:241
msgid "Don't show again."
msgstr "Не показывать снова."
-#: spyder/widgets/ipythonconsole/shell.py:264
+#: spyder/widgets/ipythonconsole/shell.py:266
msgid ""
"
Removing all variables...\n"
"
"
@@ -4291,15 +4472,15 @@ msgstr ""
"
Удаление всех переменных...\n"
"
"
-#: spyder/widgets/ipythonconsole/shell.py:430
-msgid "Changing backend to Qt for Mayavi"
-msgstr "Изменить бэкенд для Mayavi на Qt"
+#: spyder/widgets/ipythonconsole/shell.py:432
+msgid "Changing backend to Qt4 for Mayavi"
+msgstr "Смена бэкенда для Mayavi на Qt4"
-#: spyder/widgets/ipythonconsole/shell.py:475
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel died, restarting"
msgstr "Ядро остановилось, перезапуск"
-#: spyder/widgets/ipythonconsole/shell.py:475
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel restarting"
msgstr "Перезапуск ядра"
@@ -4327,43 +4508,44 @@ msgstr "Свернуть выделенное"
msgid "Expand selection"
msgstr "Развернуть выделенное"
-#: spyder/widgets/pathmanager.py:97
+#: spyder/widgets/pathmanager.py:98
msgid "Move to top"
msgstr "Переместить вверх"
-#: spyder/widgets/pathmanager.py:103
+#: spyder/widgets/pathmanager.py:104
msgid "Move up"
msgstr "Переместить выше"
-#: spyder/widgets/pathmanager.py:109
+#: spyder/widgets/pathmanager.py:110
msgid "Move down"
msgstr "Переместить ниже"
-#: spyder/widgets/pathmanager.py:115
+#: spyder/widgets/pathmanager.py:116
msgid "Move to bottom"
msgstr "Переместить вниз"
-#: spyder/widgets/pathmanager.py:126 spyder/widgets/pathmanager.py:267
+#: spyder/widgets/pathmanager.py:127 spyder/widgets/pathmanager.py:270
+#: spyder/widgets/pathmanager.py:282
msgid "Add path"
msgstr "Добавить путь"
-#: spyder/widgets/pathmanager.py:131 spyder/widgets/pathmanager.py:246
+#: spyder/widgets/pathmanager.py:132 spyder/widgets/pathmanager.py:247
msgid "Remove path"
msgstr "Удалить путь"
-#: spyder/widgets/pathmanager.py:141
+#: spyder/widgets/pathmanager.py:142
msgid "Synchronize..."
msgstr "Синхронизация..."
-#: spyder/widgets/pathmanager.py:143
+#: spyder/widgets/pathmanager.py:144
msgid "Synchronize Spyder's path list with PYTHONPATH environment variable"
msgstr "Синхронизировать список путей Spyder с переменной среды PYTHONPATH"
-#: spyder/widgets/pathmanager.py:155
+#: spyder/widgets/pathmanager.py:156
msgid "Synchronize"
msgstr "Синхронизировать"
-#: spyder/widgets/pathmanager.py:156
+#: spyder/widgets/pathmanager.py:157
msgid ""
"This will synchronize Spyder's path list with PYTHONPATH environment "
"variable for current user, allowing you to run your Python modules outside "
@@ -4375,11 +4557,19 @@ msgstr ""
"без необходимости настраивать sys.path.
Хотите очистить содержимое "
"PYTHONPATH перед добавлением списка путей Spyder?"
-#: spyder/widgets/pathmanager.py:247
+#: spyder/widgets/pathmanager.py:248
msgid "Do you really want to remove selected path?"
msgstr "Вы действительно хотите удалить выбранный путь?"
-#: spyder/widgets/pathmanager.py:268
+#: spyder/widgets/pathmanager.py:271
+msgid ""
+"You are using Python 2 and the path selected has Unicode characters. The new "
+"path will not be added."
+msgstr ""
+"Вы используете Python 2, а в выбранном путь есть символы Unicode. Новый путь "
+"не будет добавлен."
+
+#: spyder/widgets/pathmanager.py:283
msgid ""
"This directory is already included in Spyder path list.
Do you want to "
"move it to the top of the list?"
@@ -4507,7 +4697,7 @@ msgstr "Создать"
msgid "Create new project"
msgstr "Создать новый проект"
-#: spyder/widgets/projects/type/__init__.py:216
+#: spyder/widgets/projects/type/__init__.py:223
msgid "Empty project"
msgstr "Пустой проект"
@@ -4519,77 +4709,106 @@ msgstr "Проект Python"
msgid "Python package"
msgstr "Пакет Python"
-#: spyder/widgets/pydocgui.py:110
+#: spyder/widgets/pydocgui.py:117
msgid "Module or package:"
msgstr "Модуль или пакет:"
-#: spyder/widgets/reporterror.py:121
-msgid "Spyder internal error"
-msgstr "Внутренняя ошибка Spyder"
-
-#: spyder/widgets/reporterror.py:129
-msgid ""
-"Spyder has encountered an internal problem
\n"
-" Before reporting it, please consult our comprehensive \n"
-" Troubleshooting Guide \n"
-" which should help solve most issues, and search for \n"
-" known bugs matching your error \n"
-" message or problem description for a quicker solution.\n"
-"
\n"
-" If you don't find anything, please enter a detailed step-by-"
-"step \n"
-" description (in English) of what led up to the problem "
-"below. \n"
-" Issue reports without a clear way to reproduce them will be \n"
-" closed.
\n"
-" Thanks for helping us making Spyder better for everyone!\n"
-" "
-msgstr ""
-"Spyder обнаружил внутреннюю ошибку
\n"
-" Перед её публикацией, пожалуйста, ознакомьтесь с нашим "
-"подробным \n"
-" Мастером устранения ошибок, \n"
-" который поможет решить большинство проблем, и найти \n"
-" известных ошибок сравнивая Ваше "
-"сообщение \n"
-" об ошибке или описание проблемы для ускорения поиска решения.\n"
-"
\n"
-" Если Вы ничего не найдете, пожалуйста, введите ниже "
-"развернутое \n"
-" (шаг за шагом) описание (на английском) что привело к "
-"проблеме. \n"
-" Отчеты об ошибках без четкого пути их воспроизводства \n"
-" будут закрыты.
\n"
-" Спасибо, что помогаете нам сделать Spyder лучше для каждого!\n"
-" "
-
-#: spyder/widgets/reporterror.py:163
-msgid "Hide all future errors this session"
+#: spyder/widgets/reporterror.py:128
+msgid "Issue reporter"
+msgstr "Мастер сообщений о проблеме"
+
+#: spyder/widgets/reporterror.py:136
+msgid "Please fill the following information"
+msgstr "Пожалуйста, заполните следующую информацию"
+
+#: spyder/widgets/reporterror.py:138
+msgid "Spyder has encountered an internal problem!"
+msgstr "В Spyder произошла внутренняя ошибка!"
+
+#: spyder/widgets/reporterror.py:140
+msgid ""
+"{title}
Before reporting this problem, please consult our "
+"comprehensive Troubleshooting Guide "
+"which should help solve most issues, and search for known bugs matching your error message or problem "
+"description for a quicker solution."
+msgstr ""
+"{title}
Перед тем как создать сообщение о проблеме, пожалуйста"
+"i> ознакомьтесь со всеобъемлющим Troubleshooting Guide, который должен помочь с "
+"большинством ошибок, и произведите поиск по "
+"известным ошибкам сравнив со своим для быстрого решения."
+
+#: spyder/widgets/reporterror.py:158 spyder/widgets/reporterror.py:190
+msgid "{} more characters to go..."
+msgstr "ещё {} символов для начала..."
+
+#: spyder/widgets/reporterror.py:162
+msgid "Title: {}"
+msgstr "Заголовок: {}"
+
+#: spyder/widgets/reporterror.py:168
+msgid "Steps to reproduce: {}"
+msgstr "Как воспроизвести: {}"
+
+#: spyder/widgets/reporterror.py:169
+msgid ""
+"Please enter a detailed step-by-step description (in English) of what led up "
+"to the problem below. Issue reports without a clear way to reproduce them "
+"will be closed."
+msgstr ""
+"Пожалуйста введите ниже детальное пошаговое описание (на английском), что "
+"привело к проблеме. Сообщение о проблеме без точного пути воспроизводства "
+"будет закрыто."
+
+#: spyder/widgets/reporterror.py:194
+msgid "Hide all future errors during this session"
msgstr "Спрятать будущие ошибки в этой сессии"
-#: spyder/widgets/reporterror.py:171
+#: spyder/widgets/reporterror.py:201
msgid "Submit to Github"
msgstr "Отправить на Github"
-#: spyder/widgets/reporterror.py:175 spyder/widgets/reporterror.py:227
+#: spyder/widgets/reporterror.py:205 spyder/widgets/reporterror.py:312
msgid "Show details"
msgstr "Показать подробности"
-#: spyder/widgets/reporterror.py:178
+#: spyder/widgets/reporterror.py:210
+#: spyder/widgets/variableexplorer/arrayeditor.py:740
+#: spyder/widgets/variableexplorer/collectionseditor.py:1397
+#: spyder/widgets/variableexplorer/dataframeeditor.py:756
+#: spyder/widgets/variableexplorer/texteditor.py:72
msgid "Close"
msgstr "Закрыть"
-#: spyder/widgets/reporterror.py:235
+#: spyder/widgets/reporterror.py:286
+msgid ""
+"An error occurred while trying to send the issue to Github automatically. "
+"Would you like to open it manually?
If so, please make sure to paste "
+"your clipboard into the issue report box that will appear in a new browser "
+"tab before clicking Submit on that page."
+msgstr ""
+"Во время автоматической попытки отправить сообщение о проблеме на Github "
+"произошла ошибка. Можете ли Вы создать его вручную?
Если это так, "
+"убедитесь, что вставили содержимое буфера обмена в поле сообщения, которое "
+"откроется в новой вкладке браузера, перед тем как нажать Submit на "
+"этой странице."
+
+#: spyder/widgets/reporterror.py:320
msgid "Hide details"
msgstr "Скрыть подробности"
-#: spyder/widgets/reporterror.py:243
+#: spyder/widgets/reporterror.py:329 spyder/widgets/reporterror.py:337
msgid "more characters to go..."
msgstr "символов ещё для начала..."
-#: spyder/widgets/reporterror.py:245
-msgid "Submission enabled; thanks!"
-msgstr "Отправка включена; благодарим!"
+#: spyder/widgets/reporterror.py:331
+msgid "Description complete; thanks!"
+msgstr "Описание заполнена; спасибо!"
+
+#: spyder/widgets/reporterror.py:339
+msgid "Title complete; thanks!"
+msgstr "Заголовок заполнен; спасибо!"
#: spyder/widgets/shell.py:131
msgid "Save history log..."
@@ -4636,27 +4855,27 @@ msgstr "Перейти к строке:"
msgid "Line count:"
msgstr "Количество строк:"
-#: spyder/widgets/sourcecode/codeeditor.py:1327
+#: spyder/widgets/sourcecode/codeeditor.py:1334
msgid "Breakpoint"
msgstr "Точка останова"
-#: spyder/widgets/sourcecode/codeeditor.py:1328
+#: spyder/widgets/sourcecode/codeeditor.py:1335
msgid "Condition:"
msgstr "Условие:"
-#: spyder/widgets/sourcecode/codeeditor.py:1733
+#: spyder/widgets/sourcecode/codeeditor.py:1740
msgid "Code analysis"
msgstr "Анализ кода"
-#: spyder/widgets/sourcecode/codeeditor.py:1787
+#: spyder/widgets/sourcecode/codeeditor.py:1794
msgid "To do"
msgstr "Список задач"
-#: spyder/widgets/sourcecode/codeeditor.py:2147
+#: spyder/widgets/sourcecode/codeeditor.py:2154
msgid "Removal error"
msgstr "Ошибка удаления"
-#: spyder/widgets/sourcecode/codeeditor.py:2148
+#: spyder/widgets/sourcecode/codeeditor.py:2155
msgid ""
"It was not possible to remove outputs from this notebook. The error is:\n"
"\n"
@@ -4664,15 +4883,15 @@ msgstr ""
"Невозможно удалить результаты из блокнота. Ошибка:\n"
"\n"
-#: spyder/widgets/sourcecode/codeeditor.py:2696
+#: spyder/widgets/sourcecode/codeeditor.py:2703
msgid "Clear all ouput"
msgstr "Очистить вывод"
-#: spyder/widgets/sourcecode/codeeditor.py:2702
+#: spyder/widgets/sourcecode/codeeditor.py:2709
msgid "Go to definition"
msgstr "Перейти к определению"
-#: spyder/widgets/sourcecode/codeeditor.py:2735
+#: spyder/widgets/sourcecode/codeeditor.py:2742
msgid "Zoom reset"
msgstr "Восстановить масштаб"
@@ -4728,98 +4947,98 @@ msgstr "Обзор вкладок"
msgid "Close current tab"
msgstr "Закрыть текущую вкладку"
-#: spyder/widgets/variableexplorer/arrayeditor.py:511
+#: spyder/widgets/variableexplorer/arrayeditor.py:509
msgid "It was not possible to copy values for this array"
msgstr "Не удалось скопировать значения этого массива"
-#: spyder/widgets/variableexplorer/arrayeditor.py:546
-#: spyder/widgets/variableexplorer/arrayeditor.py:579
-#: spyder/widgets/variableexplorer/dataframeeditor.py:703
-#: spyder/widgets/variableexplorer/dataframeeditor.py:748
+#: spyder/widgets/variableexplorer/arrayeditor.py:545
+#: spyder/widgets/variableexplorer/arrayeditor.py:578
+#: spyder/widgets/variableexplorer/dataframeeditor.py:728
+#: spyder/widgets/variableexplorer/dataframeeditor.py:787
msgid "Format"
msgstr "Форматировать"
-#: spyder/widgets/variableexplorer/arrayeditor.py:551
-#: spyder/widgets/variableexplorer/dataframeeditor.py:707
+#: spyder/widgets/variableexplorer/arrayeditor.py:550
+#: spyder/widgets/variableexplorer/dataframeeditor.py:732
msgid "Resize"
msgstr "Изменить размер"
-#: spyder/widgets/variableexplorer/arrayeditor.py:554
-#: spyder/widgets/variableexplorer/dataframeeditor.py:711
+#: spyder/widgets/variableexplorer/arrayeditor.py:553
+#: spyder/widgets/variableexplorer/dataframeeditor.py:736
msgid "Background color"
msgstr "Цвет фона"
-#: spyder/widgets/variableexplorer/arrayeditor.py:580
-#: spyder/widgets/variableexplorer/dataframeeditor.py:749
+#: spyder/widgets/variableexplorer/arrayeditor.py:579
+#: spyder/widgets/variableexplorer/dataframeeditor.py:788
msgid "Float formatting"
msgstr "Форматирование чисел"
-#: spyder/widgets/variableexplorer/arrayeditor.py:588
+#: spyder/widgets/variableexplorer/arrayeditor.py:587
msgid "Format (%s) is incorrect"
msgstr "Формат (%s) неверный"
-#: spyder/widgets/variableexplorer/arrayeditor.py:624
+#: spyder/widgets/variableexplorer/arrayeditor.py:625
msgid "Arrays with more than 3 dimensions are not supported"
msgstr "Массивы с размерностью более 3 не поддерживаются"
-#: spyder/widgets/variableexplorer/arrayeditor.py:628
+#: spyder/widgets/variableexplorer/arrayeditor.py:629
msgid "The 'xlabels' argument length do no match array column number"
msgstr "Длина аргумента 'xlabels' не соответствует числу столбцов массива"
-#: spyder/widgets/variableexplorer/arrayeditor.py:632
+#: spyder/widgets/variableexplorer/arrayeditor.py:633
msgid "The 'ylabels' argument length do no match array row number"
msgstr "Длина аргумента 'ylabels' не соответствует числу строк массива"
-#: spyder/widgets/variableexplorer/arrayeditor.py:639
+#: spyder/widgets/variableexplorer/arrayeditor.py:640
msgid "%s arrays"
msgstr "%s массивы"
-#: spyder/widgets/variableexplorer/arrayeditor.py:640
+#: spyder/widgets/variableexplorer/arrayeditor.py:641
msgid "%s are currently not supported"
msgstr "%s на данный момент не поддерживается"
-#: spyder/widgets/variableexplorer/arrayeditor.py:647
+#: spyder/widgets/variableexplorer/arrayeditor.py:648
msgid "NumPy array"
msgstr "Массив NumPy"
-#: spyder/widgets/variableexplorer/arrayeditor.py:649
-#: spyder/widgets/variableexplorer/arrayeditor.py:806
+#: spyder/widgets/variableexplorer/arrayeditor.py:650
+#: spyder/widgets/variableexplorer/arrayeditor.py:828
msgid "Array editor"
msgstr "Редактор массивов"
-#: spyder/widgets/variableexplorer/arrayeditor.py:651
+#: spyder/widgets/variableexplorer/arrayeditor.py:652
msgid "read only"
msgstr "только чтение"
-#: spyder/widgets/variableexplorer/arrayeditor.py:681
+#: spyder/widgets/variableexplorer/arrayeditor.py:685
msgid "Record array fields:"
msgstr "Заполнить поля массива:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Data"
msgstr "Данные"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Mask"
msgstr "Маска"
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Masked data"
msgstr "Скрытые данные"
-#: spyder/widgets/variableexplorer/arrayeditor.py:704
+#: spyder/widgets/variableexplorer/arrayeditor.py:708
msgid "Axis:"
msgstr "Оси:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:709
+#: spyder/widgets/variableexplorer/arrayeditor.py:713
msgid "Index:"
msgstr "Индекс:"
-#: spyder/widgets/variableexplorer/arrayeditor.py:722
+#: spyder/widgets/variableexplorer/arrayeditor.py:726
msgid "Warning: changes are applied separately"
msgstr "Предупреждение: изменения применяются раздельно"
-#: spyder/widgets/variableexplorer/arrayeditor.py:723
+#: spyder/widgets/variableexplorer/arrayeditor.py:727
msgid ""
"For performance reasons, changes applied to masked array won't be reflected "
"in array's data (and vice-versa)."
@@ -4827,47 +5046,54 @@ msgstr ""
"По соображениям производительности, изменения принятые для скрытых массивов "
"не будут отражены в данных массивов (и наоборот)."
-#: spyder/widgets/variableexplorer/collectionseditor.py:126
+#: spyder/widgets/variableexplorer/arrayeditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:1392
+#: spyder/widgets/variableexplorer/dataframeeditor.py:751
+#: spyder/widgets/variableexplorer/texteditor.py:67
+msgid "Save and Close"
+msgstr "Сохранить и закрыть"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:151
msgid "Index"
msgstr "Индекс"
-#: spyder/widgets/variableexplorer/collectionseditor.py:131
+#: spyder/widgets/variableexplorer/collectionseditor.py:156
msgid "Tuple"
msgstr "Кортеж"
-#: spyder/widgets/variableexplorer/collectionseditor.py:134
+#: spyder/widgets/variableexplorer/collectionseditor.py:159
msgid "List"
msgstr "Список"
-#: spyder/widgets/variableexplorer/collectionseditor.py:137
+#: spyder/widgets/variableexplorer/collectionseditor.py:162
msgid "Dictionary"
msgstr "Словарь"
-#: spyder/widgets/variableexplorer/collectionseditor.py:139
+#: spyder/widgets/variableexplorer/collectionseditor.py:164
msgid "Key"
msgstr "Ключ"
-#: spyder/widgets/variableexplorer/collectionseditor.py:144
+#: spyder/widgets/variableexplorer/collectionseditor.py:169
msgid "Attribute"
msgstr "Атрибут"
-#: spyder/widgets/variableexplorer/collectionseditor.py:148
+#: spyder/widgets/variableexplorer/collectionseditor.py:173
msgid "elements"
msgstr "элементов"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Size"
msgstr "Размер"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Type"
msgstr "Тип"
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Value"
msgstr "Значение"
-#: spyder/widgets/variableexplorer/collectionseditor.py:417
+#: spyder/widgets/variableexplorer/collectionseditor.py:450
msgid ""
"Opening this variable can be slow\n"
"\n"
@@ -4877,7 +5103,7 @@ msgstr ""
"\n"
"Желаете продолжить?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:428
+#: spyder/widgets/variableexplorer/collectionseditor.py:461
msgid ""
"Spyder was unable to retrieve the value of this variable from the console."
"
The error mesage was:
%s"
@@ -4885,150 +5111,166 @@ msgstr ""
"Spyder не смог извлечь значение этой переменной из консоли. "
"
Сообщение об ошибке:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:608
+#: spyder/widgets/variableexplorer/collectionseditor.py:643
msgid "Edit item"
msgstr "Редактировать элемент"
-#: spyder/widgets/variableexplorer/collectionseditor.py:609
+#: spyder/widgets/variableexplorer/collectionseditor.py:644
msgid "Unable to assign data to item.
Error message:
%s"
msgstr ""
"Невозможно назначить данные элементу.
Сообщение об ошибке:
"
"%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:669
+#: spyder/widgets/variableexplorer/collectionseditor.py:705
msgid "Resize rows to contents"
msgstr "Размер строк по содержимому"
-#: spyder/widgets/variableexplorer/collectionseditor.py:680
-#: spyder/widgets/variableexplorer/collectionseditor.py:1030
-#: spyder/widgets/variableexplorer/collectionseditor.py:1047
+#: spyder/widgets/variableexplorer/collectionseditor.py:716
+#: spyder/widgets/variableexplorer/collectionseditor.py:1066
+#: spyder/widgets/variableexplorer/collectionseditor.py:1083
msgid "Plot"
msgstr "График"
-#: spyder/widgets/variableexplorer/collectionseditor.py:684
+#: spyder/widgets/variableexplorer/collectionseditor.py:720
msgid "Histogram"
msgstr "Гистограмма"
-#: spyder/widgets/variableexplorer/collectionseditor.py:688
+#: spyder/widgets/variableexplorer/collectionseditor.py:724
msgid "Show image"
msgstr "Показать изображение"
-#: spyder/widgets/variableexplorer/collectionseditor.py:692
-#: spyder/widgets/variableexplorer/collectionseditor.py:1055
+#: spyder/widgets/variableexplorer/collectionseditor.py:728
+#: spyder/widgets/variableexplorer/collectionseditor.py:1091
msgid "Save array"
msgstr "Сохранить массив"
-#: spyder/widgets/variableexplorer/collectionseditor.py:696
-#: spyder/widgets/variableexplorer/collectionseditor.py:994
-#: spyder/widgets/variableexplorer/collectionseditor.py:1002
+#: spyder/widgets/variableexplorer/collectionseditor.py:732
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Insert"
msgstr "Вставить"
-#: spyder/widgets/variableexplorer/collectionseditor.py:709
-#: spyder/widgets/variableexplorer/collectionseditor.py:955
+#: spyder/widgets/variableexplorer/collectionseditor.py:745
+#: spyder/widgets/variableexplorer/collectionseditor.py:991
msgid "Duplicate"
msgstr "Создать копию"
-#: spyder/widgets/variableexplorer/collectionseditor.py:932
+#: spyder/widgets/variableexplorer/collectionseditor.py:968
msgid "Do you want to remove the selected item?"
msgstr "Вы хотите удалить выбранный элемент?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:933
+#: spyder/widgets/variableexplorer/collectionseditor.py:969
msgid "Do you want to remove all selected items?"
msgstr "Вы хотите удалить все выбранные элементы?"
-#: spyder/widgets/variableexplorer/collectionseditor.py:953
+#: spyder/widgets/variableexplorer/collectionseditor.py:989
msgid "New variable name:"
msgstr "Новое имя переменной:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:956
+#: spyder/widgets/variableexplorer/collectionseditor.py:992
msgid "Variable name:"
msgstr "Имя переменной:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:994
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
msgid "Key:"
msgstr "Ключ:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1002
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Value:"
msgstr "Значение:"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1018
+#: spyder/widgets/variableexplorer/collectionseditor.py:1054
msgid "Import error"
msgstr "Ошибка импорта"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1019
+#: spyder/widgets/variableexplorer/collectionseditor.py:1055
msgid "Please install matplotlib or guiqwt."
msgstr "Пожалуйста, установите matplotlib или guiqwt."
-#: spyder/widgets/variableexplorer/collectionseditor.py:1031
+#: spyder/widgets/variableexplorer/collectionseditor.py:1067
msgid "Unable to plot data.
Error message:
%s"
msgstr ""
"Не удалось построить график по данным.
Сообщение об ошибке:
"
"%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1048
+#: spyder/widgets/variableexplorer/collectionseditor.py:1084
msgid "Unable to show image.
Error message:
%s"
msgstr ""
"Не удалось показать изображение.
Сообщение об ошибке:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1071
+#: spyder/widgets/variableexplorer/collectionseditor.py:1097
+msgid "NumPy arrays"
+msgstr "Массивы NumPy"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1107
msgid "Unable to save array
Error message:
%s"
msgstr "Не удалось сохранить массив
Сообщение об ошибке:
%s"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1096
+#: spyder/widgets/variableexplorer/collectionseditor.py:1132
msgid "It was not possible to copy this array"
msgstr "Не удалось скопировать этот массив"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1121
+#: spyder/widgets/variableexplorer/collectionseditor.py:1144
+msgid "It was not possible to copy this dataframe"
+msgstr "Не удалось скопировать этот массив данных"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1166
msgid "Clipboard contents"
msgstr "Содержимое буфера обмена"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1136
+#: spyder/widgets/variableexplorer/collectionseditor.py:1181
msgid "Import from clipboard"
msgstr "Импортировать из буфера обмена"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1138
+#: spyder/widgets/variableexplorer/collectionseditor.py:1183
msgid "Empty clipboard"
msgstr "Очистить буфер обмена"
-#: spyder/widgets/variableexplorer/collectionseditor.py:1139
+#: spyder/widgets/variableexplorer/collectionseditor.py:1184
msgid "Nothing to be imported from clipboard."
msgstr "Нечего импортировать из буфера обмена."
-#: spyder/widgets/variableexplorer/dataframeeditor.py:597
+#: spyder/widgets/variableexplorer/dataframeeditor.py:321
+msgid ""
+"It is not possible to display this value because\n"
+"an error ocurred while trying to do it"
+msgstr ""
+"Невозможно отобразить это значения\n"
+"потому что в процессе произошла ошибка"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To bool"
msgstr "В булево"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:597
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To complex"
msgstr "В комплексное"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:598
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To float"
msgstr "В вещественное"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:598
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To int"
msgstr "В целое"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:599
+#: spyder/widgets/variableexplorer/dataframeeditor.py:623
msgid "To str"
msgstr "В строку"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:683
+#: spyder/widgets/variableexplorer/dataframeeditor.py:707
msgid "%s editor"
msgstr "%s редактор"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:717
+#: spyder/widgets/variableexplorer/dataframeeditor.py:742
msgid "Column min/max"
msgstr "Min/max столбца"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:757
+#: spyder/widgets/variableexplorer/dataframeeditor.py:796
msgid "Format ({}) is incorrect"
msgstr "Формат ({}) неверный"
-#: spyder/widgets/variableexplorer/dataframeeditor.py:761
+#: spyder/widgets/variableexplorer/dataframeeditor.py:800
msgid "Format ({}) should start with '%'"
msgstr "Формат ({}) должен начинаться с '%'"
@@ -5056,11 +5298,11 @@ msgstr "Разделитель столбцов:"
#: spyder/widgets/variableexplorer/importwizard.py:144
msgid "Tab"
-msgstr "табуляция"
+msgstr "Табуляция"
#: spyder/widgets/variableexplorer/importwizard.py:147
msgid "Whitespace"
-msgstr "пробельный символ"
+msgstr "Пробельный символ"
#: spyder/widgets/variableexplorer/importwizard.py:150
#: spyder/widgets/variableexplorer/importwizard.py:168
@@ -5140,35 +5382,36 @@ msgstr ""
"Невозможно перейти к следующему шагу
Пожалуйста, проверьте "
"введенные данные.
Сообщение об ошибке:
%s"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:181
-#: spyder/widgets/variableexplorer/namespacebrowser.py:385
+#: spyder/widgets/variableexplorer/namespacebrowser.py:184
+#: spyder/widgets/variableexplorer/namespacebrowser.py:397
msgid "Import data"
msgstr "Импортировать данные"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:184
-#: spyder/widgets/variableexplorer/namespacebrowser.py:465
-#: spyder/widgets/variableexplorer/namespacebrowser.py:479
+#: spyder/widgets/variableexplorer/namespacebrowser.py:187
+#: spyder/widgets/variableexplorer/namespacebrowser.py:477
+#: spyder/widgets/variableexplorer/namespacebrowser.py:491
+#: spyder/plugins/profiler/widgets/profilergui.py:121
msgid "Save data"
msgstr "Сохранить данные"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:189
+#: spyder/widgets/variableexplorer/namespacebrowser.py:192
msgid "Save data as..."
msgstr "Сохранить данные как..."
-#: spyder/widgets/variableexplorer/namespacebrowser.py:201
+#: spyder/widgets/variableexplorer/namespacebrowser.py:204
msgid "Exclude references which name starts with an underscore"
msgstr "Исключить ссылки, имена которых начинаются с подчёркивания"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:209
+#: spyder/widgets/variableexplorer/namespacebrowser.py:212
msgid "Exclude references which name is uppercase"
msgstr "Исключить ссылки с именем в верхнем регистре"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:216
+#: spyder/widgets/variableexplorer/namespacebrowser.py:219
msgid "Exclude references which name starts with an uppercase character"
msgstr ""
"Исключить ссылки, имена которых начинаются с символа в верхнем регистре"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:224
+#: spyder/widgets/variableexplorer/namespacebrowser.py:227
msgid ""
"Exclude references to unsupported data types (i.e. which won't be handled/"
"saved correctly)"
@@ -5176,7 +5419,15 @@ msgstr ""
"Исключить ссылки на неподдерживаемые типы данных (т.е. которые не будут "
"правильно обработаны/сохранены)"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:405
+#: spyder/widgets/variableexplorer/namespacebrowser.py:306
+msgid ""
+"The object you are trying to modify is too big to be sent back to the "
+"kernel. Therefore, your modifications won't take place."
+msgstr ""
+"Объект, который Вы пытаетесь изменить слишком велик, чтобы отправить его "
+"обратно в ядро. Поэтому Ваши изменения не могут быть приняты."
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:417
msgid ""
"Unsupported file extension '%s'
Would you like to import it "
"anyway (by selecting a known file format)?"
@@ -5184,39 +5435,29 @@ msgstr ""
"Неподдерживаемое расширение файла '%s'
Хотите его "
"импортировать (выбрав известный формат файла)?"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:413
+#: spyder/widgets/variableexplorer/namespacebrowser.py:425
msgid "Open file as:"
msgstr "Открыть файл как:"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:447
+#: spyder/widgets/variableexplorer/namespacebrowser.py:459
msgid "Unable to load '%s'
Error message:
%s"
msgstr "Не удалось загрузить '%s'
Сообщение об ошибке:
%s"
-#: spyder/widgets/variableexplorer/namespacebrowser.py:480
+#: spyder/widgets/variableexplorer/namespacebrowser.py:492
msgid "Unable to save current workspace
Error message:
%s"
msgstr ""
"Невозможно сохранить текущую рабочую область
Сообщение об "
"ошибке:
%s"
-#: spyder/widgets/variableexplorer/texteditor.py:74
+#: spyder/widgets/variableexplorer/texteditor.py:84
msgid "Text editor"
msgstr "Текстовый редактор"
-#: spyder/widgets/variableexplorer/utils.py:31
-msgid "View and edit DataFrames and Series in the Variable Explorer"
-msgstr ""
-"Показ и редактирование структур DataFrame и Serie в Менеджере Переменных"
-
-#: spyder/widgets/variableexplorer/utils.py:36
-msgid "View and edit two and three dimensional arrays in the Variable Explorer"
-msgstr ""
-"Просмотр и редактирование 2-х и 3-мерных массивов в Менеджере Переменных"
-
-#: spyder/workers/updates.py:90 spyder/workers/updates.py:92
+#: spyder/workers/updates.py:128 spyder/workers/updates.py:130
msgid "Unable to retrieve information."
msgstr "Невозможно получить информацию."
-#: spyder/workers/updates.py:94
+#: spyder/workers/updates.py:132
msgid ""
"Unable to connect to the internet.
Make sure the connection is "
"working properly."
@@ -5224,10 +5465,153 @@ msgstr ""
"Не удалось подключиться к интернету.
Убедитесь, что соединение "
"работает должным образом."
-#: spyder/workers/updates.py:97
+#: spyder/workers/updates.py:135
msgid "Unable to check for updates."
msgstr "Не удалось проверить обновления."
+#~ msgid "ViTables"
+#~ msgstr "ViTables"
+
+#~ msgid ""
+#~ "Update LANGUAGE_CODES (inside config/base.py) if a new translation has "
+#~ "been added to Spyder"
+#~ msgstr ""
+#~ "Обновите LANGUAGE_CODES (в файле config/base.py) если добавили новый "
+#~ "перевод в Spyder"
+
+#~ msgid ""
+#~ "Please enter the connection info of the kernel you want to connect to. "
+#~ "For that you can either select its JSON connection file using the "
+#~ "Browse button, or write directly its id, in case it's a local "
+#~ "kernel (for example kernel-3764.json or just 3764)."
+#~ msgstr ""
+#~ "Пожалуйста, введите информацию о соединении для ядра, к которому "
+#~ "пытаетесь подключиться. Для этого либо выберите JSON-файл соединения "
+#~ "кнопкой Обзор, либо, если ядро локальное, введите его id (напр. "
+#~ "kernel-3764.json или просто 3764)."
+
+#~ msgid "Connection info:"
+#~ msgstr "Информация о соединении:"
+
+#~ msgid "Ssh key"
+#~ msgstr "Ключ ssh"
+
+#~ msgid "Password"
+#~ msgstr "Пароль"
+
+#~ msgid "Select ssh key"
+#~ msgstr "Выберите ключ ssh"
+
+#~ msgid "PyQt4 Reference Guide"
+#~ msgstr "Справочное руководство по PyQt4"
+
+#~ msgid "PyQt4 API Reference"
+#~ msgstr "Справка по API PyQt4"
+
+#~ msgid "Qt examples"
+#~ msgstr "Примеры Qt"
+
+#~ msgid "Use the greedy completer"
+#~ msgstr "Включить скупое автодополнение"
+
+#~ msgid ""
+#~ "This error was most probably caused by installing Spyder in a directory "
+#~ "with non-ascii characters (i.e. characters with tildes, apostrophes or "
+#~ "non-latin symbols).
To fix it, please reinstall Spyder in a "
+#~ "different location."
+#~ msgstr ""
+#~ "Эта ошибка скорее всего произошла из-за установки Spyder в каталог, "
+#~ "содержащий non-ascii символы (тильды, апострофы, не латинские символы и т."
+#~ "п.).
Для исправления переустановите Spyder в другой каталог."
+
+#~ msgid "Supported files"
+#~ msgstr "Поддерживаемые файлы"
+
+#~ msgid "All files (*.*)"
+#~ msgstr "Все файлы (*.*)"
+
+#~ msgid "Spyder data files"
+#~ msgstr "Файлы данных Spyder"
+
+#~ msgid "NumPy zip arrays"
+#~ msgstr "Сжатые массивы NumPy"
+
+#~ msgid "Matlab files"
+#~ msgstr "Файлы Matlab"
+
+#~ msgid "CSV text files"
+#~ msgstr "Текстовые файлы CSV"
+
+#~ msgid "JPEG images"
+#~ msgstr "Изображения JPEG"
+
+#~ msgid "PNG images"
+#~ msgstr "Изображения PNG"
+
+#~ msgid "GIF images"
+#~ msgstr "Изображения GIF"
+
+#~ msgid "TIFF images"
+#~ msgstr "Изображения TIFF"
+
+#~ msgid "Pickle files"
+#~ msgstr "Архивы Pickle"
+
+#~ msgid "JSON files"
+#~ msgstr "Файлы JSON"
+
+#~ msgid "Unsupported file type '%s'"
+#~ msgstr "Неподдерживаемый тип файла '%s'"
+
+#~ msgid "Save"
+#~ msgstr "Сохранить"
+
+#~ msgid "Spyder internal error"
+#~ msgstr "Внутренняя ошибка Spyder"
+
+#~ msgid ""
+#~ "Spyder has encountered an internal problem
\n"
+#~ " Before reporting it, please consult our "
+#~ "comprehensive \n"
+#~ " Troubleshooting Guide \n"
+#~ " which should help solve most issues, and search for \n"
+#~ " known bugs matching your "
+#~ "error \n"
+#~ " message or problem description for a quicker solution.\n"
+#~ "
\n"
+#~ " If you don't find anything, please enter a detailed step-by-"
+#~ "step \n"
+#~ " description (in English) of what led up to the problem "
+#~ "below. \n"
+#~ " Issue reports without a clear way to reproduce them will "
+#~ "be \n"
+#~ " closed.
\n"
+#~ " Thanks for helping us making Spyder better for everyone!\n"
+#~ " "
+#~ msgstr ""
+#~ "Spyder обнаружил внутреннюю ошибку
\n"
+#~ " Перед её публикацией, пожалуйста, ознакомьтесь с "
+#~ "нашим подробным \n"
+#~ " Мастером устранения ошибок, \n"
+#~ " который поможет решить большинство проблем, и найти \n"
+#~ " известных ошибок сравнивая "
+#~ "Ваше сообщение \n"
+#~ " об ошибке или описание проблемы для ускорения поиска "
+#~ "решения.\n"
+#~ "
\n"
+#~ " Если Вы ничего не найдете, пожалуйста, введите ниже "
+#~ "развернутое \n"
+#~ " (шаг за шагом) описание (на английском) что привело к "
+#~ "проблеме. \n"
+#~ " Отчеты об ошибках без четкого пути их воспроизводства \n"
+#~ " будут закрыты.
\n"
+#~ " Спасибо, что помогаете нам сделать Spyder лучше для "
+#~ "каждого!\n"
+#~ " "
+
+#~ msgid "Submission enabled; thanks!"
+#~ msgstr "Отправка включена; благодарим!"
+
#~ msgid "Pop up internal console when internal errors appear"
#~ msgstr "Переходить во встроенную консоль при появлении внутренних ошибок"
@@ -5510,9 +5894,6 @@ msgstr "Не удалось проверить обновления."
#~ msgid "the global working directory"
#~ msgstr "глобальный рабочий каталог"
-#~ msgid "Files are created in:"
-#~ msgstr "Файлы создаются в:"
-
#~ msgid "Change to file base directory"
#~ msgstr "Изменить на каталог файла"
@@ -5657,6 +6038,275 @@ msgstr "Не удалось проверить обновления."
#~ msgid "Refresh periodically"
#~ msgstr "Обновлять периодически"
+#: spyder/plugins/breakpoints/plugin.py:45
+msgid "Breakpoints"
+msgstr "Точки останова"
+
+#: spyder/plugins/breakpoints/plugin.py:80
+msgid "List breakpoints"
+msgstr "Список точек останова"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "Condition"
+msgstr "Условие"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "File"
+msgstr "Файл"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "Line"
+msgstr "Строка"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:201
+msgid "Clear this breakpoint"
+msgstr "Убрать эту точку останова"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:206
+msgid "Edit this breakpoint"
+msgstr "Редактировать эту точку останова"
+
+#: spyder/plugins/pylint/plugin.py:36
+msgid "Save file before analyzing it"
+msgstr "Сохранить файл перед его анализом"
+
+#: spyder/plugins/pylint/plugin.py:40
+msgid "The following option will be applied at next startup."
+msgstr "Следующая опция будет применена при следующем запуске."
+
+#: spyder/plugins/pylint/plugin.py:43
+msgid "History: "
+msgstr "История:"
+
+#: spyder/plugins/pylint/plugin.py:44
+msgid " results"
+msgstr " результаты"
+
+#: spyder/plugins/pylint/plugin.py:47 spyder/plugins/profiler/plugin.py:33
+msgid "Results"
+msgstr "Результаты"
+
+#: spyder/plugins/pylint/plugin.py:48
+msgid "Results are stored here:"
+msgstr "Результаты хранятся здесь:"
+
+#: spyder/plugins/pylint/plugin.py:98
+#: spyder/plugins/pylint/widgets/pylintgui.py:83
+msgid "Static code analysis"
+msgstr "Статический анализ кода"
+
+#: spyder/plugins/pylint/plugin.py:133
+msgid "Run static code analysis"
+msgstr "Запустить статический анализ кода"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:117
+msgid "Results for "
+msgstr "Результаты для"
+
+# Соглашения, Конвенции
+#: spyder/plugins/pylint/widgets/pylintgui.py:122
+msgid "Convention"
+msgstr "Договорённости"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:124
+msgid "Refactor"
+msgstr "Рефакторинг"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:206
+msgid "Analyze"
+msgstr "Анализ"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:207
+msgid "Run analysis"
+msgstr "Запустить анализ"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:212
+msgid "Stop current analysis"
+msgstr "Остановить текущий анализ"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:218
+#: spyder/plugins/pylint/widgets/pylintgui.py:288
+msgid "Select Python file"
+msgstr "Выбрать файл Python"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:224
+#: spyder/plugins/profiler/widgets/profilergui.py:102
+msgid "Output"
+msgstr "Вывод"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:226
+msgid "Complete output"
+msgstr "Детальный вывод:"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:260
+msgid "Pylint script was not found. Please add \"%s\" to PATH."
+msgstr "Скрипт pylint не найден. Пожалуйста добавьте \"%s\" в PATH."
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:263
+msgid "Please install pylint:"
+msgstr "Пожалуйста, установите pylint:"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:326
+msgid "Pylint output"
+msgstr "Вывод pylint"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:465
+msgid "Source code has not been rated yet."
+msgstr "Исходный код еще не был оценен."
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:471
+msgid "Analysis did not succeed (see output for more details)."
+msgstr "Анализ не удался (смотрите подробности в выводе)."
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:484
+msgid "Global evaluation:"
+msgstr "Общая оценка:"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:488
+msgid "previous run:"
+msgstr "предыдущий запуск:"
+
+#: spyder/plugins/profiler/plugin.py:34
+msgid ""
+"Profiler plugin results (the output of python's profile/cProfile)\n"
+"are stored here:"
+msgstr ""
+"Результаты Профайлера (вывод profile/cProfile python'а)\n"
+"хранятся здесь:"
+
+#: spyder/plugins/profiler/plugin.py:75
+msgid "Profiler"
+msgstr "Профайлер"
+
+#: spyder/plugins/profiler/plugin.py:104
+#: spyder/plugins/profiler/widgets/profilergui.py:81
+msgid "Profile"
+msgstr "Профилировать"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:82
+msgid "Run profiler"
+msgstr "Запустить профайлер"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:88
+msgid "Stop current profiling"
+msgstr "Остановить текущее профилирование"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:96
+#: spyder/plugins/profiler/widgets/profilergui.py:219
+msgid "Select Python script"
+msgstr "Выбрать скрипт Python"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:104
+msgid "Show program's output"
+msgstr "Показать вывод программы"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:113
+msgid "Collapse one level up"
+msgstr "Свернуть на один уровень вверх"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:118
+msgid "Expand one level down"
+msgstr "Раскрыть на один уровень вниз"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:124
+msgid "Save profiling data"
+msgstr "Сохранить данные профилирования"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:126
+msgid "Load data"
+msgstr "Загрузить данные"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:129
+msgid "Load profiling data for comparison"
+msgstr "Загрузить данные профилирования для сравнения"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:131
+msgid "Clear comparison"
+msgstr "Очистить сравнение"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:171
+msgid "Please install"
+msgstr "Пожалуйста, установите"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:172
+msgid "the Python profiler modules"
+msgstr "модули профайлера Python"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:179
+msgid "Save profiler result"
+msgstr "Сохранить результаты профилирования"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:182
+#: spyder/plugins/profiler/widgets/profilergui.py:188
+msgid "Profiler result"
+msgstr "Результаты профилирования"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:187
+msgid "Select script to compare"
+msgstr "Выберите скрипт для сравнения"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:227
+#: spyder/plugins/profiler/widgets/profilergui.py:232
+msgid "Profiler output"
+msgstr "Вывод профайлера"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:251
+msgid "Profiling, please wait..."
+msgstr "Профилирование, пожалуйста, подождите..."
+
+#: spyder/plugins/profiler/widgets/profilergui.py:343
+msgid "Sorting data, please wait..."
+msgstr "Сортировка данных, пожалуйста, подождите..."
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Function/Module"
+msgstr "Функция/Модуль"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Total Time"
+msgstr "Общее время"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Diff"
+msgstr "Различие"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Calls"
+msgstr "Вызовы"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Local Time"
+msgstr "Локальное время"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:391
+msgid "File:line"
+msgstr "Файл:строка"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:565
+msgid "Function or module name"
+msgstr "Функция/Модуль"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:569
+msgid "Time in function (including sub-functions)"
+msgstr "Время в функции (включая подфункции)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:578
+msgid "Local time in function (not in sub-functions)"
+msgstr "Локальное время в функции (исключая подфункции)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:588
+msgid "Total number of calls (including recursion)"
+msgstr "Общее число вызовов (включая рекурсию)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:598
+msgid "File:line where function is defined"
+msgstr "Файл:строка, где функция определена"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:603
+msgid "recursion"
+msgstr "рекурсия"
+
#~ msgid "Python(x,y)"
#~ msgstr "Python(x,y)"
@@ -5994,9 +6644,6 @@ msgstr "Не удалось проверить обновления."
#~ msgid "Save session and quit..."
#~ msgstr "Сохранить сессию и выйти..."
-#~ msgid "Breakpoints"
-#~ msgstr "Точки останова"
-
#~ msgid "Exit"
#~ msgstr "Выход"
diff --git a/spyder/locale/spyder.pot b/spyder/locale/spyder.pot
index 51ec55de43f..aa3c7fc4b14 100644
--- a/spyder/locale/spyder.pot
+++ b/spyder/locale/spyder.pot
@@ -1,11 +1,18 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR ORGANIZATION
-# FIRST AUTHOR , YEAR.
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+#
+# Spyder's gettext translation template file
+#
+
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
-"POT-Creation-Date: 2018-02-19 11:56+-05\n"
+"POT-Creation-Date: 2018-11-13 11:49+-05\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -15,264 +22,248 @@ msgstr ""
"Generated-By: pygettext.py 1.5\n"
-#: spyder/app/mainwindow.py:134
+#: spyder/app/mainwindow.py:139
msgid "Initializing..."
msgstr ""
-#: spyder/app/mainwindow.py:238
+#: spyder/app/mainwindow.py:252
msgid "Python2 documentation"
msgstr ""
-#: spyder/app/mainwindow.py:240
+#: spyder/app/mainwindow.py:254
msgid "Python3 documentation"
msgstr ""
-#: spyder/app/mainwindow.py:242
+#: spyder/app/mainwindow.py:256
msgid "Numpy and Scipy documentation"
msgstr ""
-#: spyder/app/mainwindow.py:244
+#: spyder/app/mainwindow.py:258
msgid "Matplotlib documentation"
msgstr ""
-#: spyder/app/mainwindow.py:247
-msgid "PyQt4 Reference Guide"
-msgstr ""
-
-#: spyder/app/mainwindow.py:250
-msgid "PyQt4 API Reference"
-msgstr ""
-
-#: spyder/app/mainwindow.py:253
+#: spyder/app/mainwindow.py:261
msgid "PyQt5 Reference Guide"
msgstr ""
-#: spyder/app/mainwindow.py:256
+#: spyder/app/mainwindow.py:264
msgid "PyQt5 API Reference"
msgstr ""
-#: spyder/app/mainwindow.py:258
+#: spyder/app/mainwindow.py:266
msgid "WinPython"
msgstr ""
-#: spyder/app/mainwindow.py:518
+#: spyder/app/mainwindow.py:525
msgid "An error occurred while creating a socket needed by Spyder. Please, try to run as an Administrator from cmd.exe the following command and then restart your computer:
netsh winsock reset
"
msgstr ""
-#: spyder/app/mainwindow.py:550
+#: spyder/app/mainwindow.py:557
msgid "Close current pane"
msgstr ""
-#: spyder/app/mainwindow.py:555
+#: spyder/app/mainwindow.py:562
msgid "Lock panes"
msgstr ""
-#: spyder/app/mainwindow.py:562
+#: spyder/app/mainwindow.py:569
msgid "Use next layout"
msgstr ""
-#: spyder/app/mainwindow.py:566
+#: spyder/app/mainwindow.py:573
msgid "Use previous layout"
msgstr ""
-#: spyder/app/mainwindow.py:576 spyder/widgets/editor.py:497
+#: spyder/app/mainwindow.py:583 spyder/widgets/editor.py:507
msgid "File switcher..."
msgstr ""
-#: spyder/app/mainwindow.py:578
+#: spyder/app/mainwindow.py:585
msgid "Fast switch between files"
msgstr ""
-#: spyder/app/mainwindow.py:584
+#: spyder/app/mainwindow.py:591
msgid "Symbol finder..."
msgstr ""
-#: spyder/app/mainwindow.py:586
+#: spyder/app/mainwindow.py:593
msgid "Fast symbol search in file"
msgstr ""
-#: spyder/app/mainwindow.py:605 spyder/widgets/sourcecode/codeeditor.py:2673
+#: spyder/app/mainwindow.py:612 spyder/widgets/sourcecode/codeeditor.py:2680
msgid "Undo"
msgstr ""
-#: spyder/app/mainwindow.py:607 spyder/widgets/sourcecode/codeeditor.py:2676
+#: spyder/app/mainwindow.py:614 spyder/widgets/sourcecode/codeeditor.py:2683
msgid "Redo"
msgstr ""
-#: spyder/app/mainwindow.py:609 spyder/widgets/shell.py:123
-#: spyder/widgets/sourcecode/codeeditor.py:2682
-#: spyder/widgets/variableexplorer/arrayeditor.py:467
-#: spyder/widgets/variableexplorer/collectionseditor.py:674
-#: spyder/widgets/variableexplorer/dataframeeditor.py:592
+#: spyder/app/mainwindow.py:616 spyder/widgets/shell.py:123
+#: spyder/widgets/sourcecode/codeeditor.py:2689
+#: spyder/widgets/variableexplorer/arrayeditor.py:465
+#: spyder/widgets/variableexplorer/collectionseditor.py:710
+#: spyder/widgets/variableexplorer/dataframeeditor.py:616
msgid "Copy"
msgstr ""
-#: spyder/app/mainwindow.py:611 spyder/widgets/shell.py:119
-#: spyder/widgets/sourcecode/codeeditor.py:2679
+#: spyder/app/mainwindow.py:618 spyder/widgets/shell.py:119
+#: spyder/widgets/sourcecode/codeeditor.py:2686
msgid "Cut"
msgstr ""
-#: spyder/app/mainwindow.py:613 spyder/widgets/shell.py:127
-#: spyder/widgets/sourcecode/codeeditor.py:2685
-#: spyder/widgets/variableexplorer/collectionseditor.py:671
+#: spyder/app/mainwindow.py:620 spyder/widgets/shell.py:127
+#: spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/widgets/variableexplorer/collectionseditor.py:707
msgid "Paste"
msgstr ""
-#: spyder/app/mainwindow.py:616 spyder/widgets/shell.py:140
-#: spyder/widgets/sourcecode/codeeditor.py:2688
+#: spyder/app/mainwindow.py:623 spyder/widgets/shell.py:140
+#: spyder/widgets/sourcecode/codeeditor.py:2695
msgid "Select All"
msgstr ""
-#: spyder/app/mainwindow.py:626 spyder/plugins/editor.py:1422
+#: spyder/app/mainwindow.py:633 spyder/plugins/editor.py:1421
msgid "&File"
msgstr ""
-#: spyder/app/mainwindow.py:627 spyder/plugins/editor.py:1410
+#: spyder/app/mainwindow.py:634 spyder/plugins/editor.py:1409
msgid "File toolbar"
msgstr ""
-#: spyder/app/mainwindow.py:631 spyder/plugins/editor.py:1423
+#: spyder/app/mainwindow.py:638 spyder/plugins/editor.py:1422
msgid "&Edit"
msgstr ""
-#: spyder/app/mainwindow.py:632 spyder/plugins/editor.py:1420
+#: spyder/app/mainwindow.py:639 spyder/plugins/editor.py:1419
msgid "Edit toolbar"
msgstr ""
-#: spyder/app/mainwindow.py:636 spyder/plugins/editor.py:1424
+#: spyder/app/mainwindow.py:643 spyder/plugins/editor.py:1423
msgid "&Search"
msgstr ""
-#: spyder/app/mainwindow.py:637 spyder/plugins/editor.py:1412
+#: spyder/app/mainwindow.py:644 spyder/plugins/editor.py:1411
msgid "Search toolbar"
msgstr ""
-#: spyder/app/mainwindow.py:641 spyder/plugins/editor.py:1425
+#: spyder/app/mainwindow.py:648 spyder/plugins/editor.py:1424
msgid "Sour&ce"
msgstr ""
-#: spyder/app/mainwindow.py:642 spyder/plugins/editor.py:1414
+#: spyder/app/mainwindow.py:649 spyder/plugins/editor.py:1413
msgid "Source toolbar"
msgstr ""
-#: spyder/app/mainwindow.py:646 spyder/plugins/editor.py:803
-#: spyder/plugins/editor.py:1426
+#: spyder/app/mainwindow.py:653 spyder/plugins/editor.py:803
+#: spyder/plugins/editor.py:1425
msgid "&Run"
msgstr ""
-#: spyder/app/mainwindow.py:647 spyder/plugins/editor.py:1416
+#: spyder/app/mainwindow.py:654 spyder/plugins/editor.py:1415
msgid "Run toolbar"
msgstr ""
-#: spyder/app/mainwindow.py:651 spyder/plugins/editor.py:762
+#: spyder/app/mainwindow.py:658 spyder/plugins/editor.py:762
msgid "&Debug"
msgstr ""
-#: spyder/app/mainwindow.py:652 spyder/plugins/editor.py:1418
+#: spyder/app/mainwindow.py:659 spyder/plugins/editor.py:1417
msgid "Debug toolbar"
msgstr ""
-#: spyder/app/mainwindow.py:656
+#: spyder/app/mainwindow.py:663
msgid "C&onsoles"
msgstr ""
-#: spyder/app/mainwindow.py:659
+#: spyder/app/mainwindow.py:666
msgid "&Projects"
msgstr ""
-#: spyder/app/mainwindow.py:662 spyder/plugins/editor.py:1427
+#: spyder/app/mainwindow.py:669 spyder/plugins/editor.py:1426
msgid "&Tools"
msgstr ""
-#: spyder/app/mainwindow.py:665 spyder/plugins/editor.py:1428
+#: spyder/app/mainwindow.py:672 spyder/plugins/editor.py:1427
msgid "&View"
msgstr ""
-#: spyder/app/mainwindow.py:668 spyder/plugins/editor.py:1429
+#: spyder/app/mainwindow.py:675 spyder/plugins/editor.py:1428
msgid "&Help"
msgstr ""
-#: spyder/app/mainwindow.py:673
+#: spyder/app/mainwindow.py:680
msgid "Welcome to Spyder!"
msgstr ""
-#: spyder/app/mainwindow.py:678
+#: spyder/app/mainwindow.py:685
msgid "Pre&ferences"
msgstr ""
-#: spyder/app/mainwindow.py:685 spyder/widgets/pathmanager.py:53
+#: spyder/app/mainwindow.py:692 spyder/widgets/pathmanager.py:54
msgid "PYTHONPATH manager"
msgstr ""
-#: spyder/app/mainwindow.py:688
+#: spyder/app/mainwindow.py:695
msgid "Python Path Manager"
msgstr ""
-#: spyder/app/mainwindow.py:691
+#: spyder/app/mainwindow.py:698
msgid "Update module names list"
msgstr ""
-#: spyder/app/mainwindow.py:694
+#: spyder/app/mainwindow.py:701
msgid "Refresh list of module names available in PYTHONPATH"
msgstr ""
-#: spyder/app/mainwindow.py:697
+#: spyder/app/mainwindow.py:704
msgid "Reset Spyder to factory defaults"
msgstr ""
-#: spyder/app/mainwindow.py:702
+#: spyder/app/mainwindow.py:709
msgid "Current user environment variables..."
msgstr ""
-#: spyder/app/mainwindow.py:704
+#: spyder/app/mainwindow.py:711
msgid "Show and edit current user environment variables in Windows registry (i.e. for all sessions)"
msgstr ""
-#: spyder/app/mainwindow.py:713 spyder/app/mainwindow.py:1137
+#: spyder/app/mainwindow.py:720 spyder/app/mainwindow.py:1115
msgid "External Tools"
msgstr ""
-#: spyder/app/mainwindow.py:716
+#: spyder/app/mainwindow.py:723
msgid "WinPython control panel"
msgstr ""
-#: spyder/app/mainwindow.py:725
+#: spyder/app/mainwindow.py:733
msgid "Qt Designer"
msgstr ""
-#: spyder/app/mainwindow.py:730
+#: spyder/app/mainwindow.py:737
msgid "Qt Linguist"
msgstr ""
-#: spyder/app/mainwindow.py:736
-msgid "Qt examples"
-msgstr ""
-
-#: spyder/app/mainwindow.py:756
+#: spyder/app/mainwindow.py:758
msgid "guidata examples"
msgstr ""
-#: spyder/app/mainwindow.py:767
+#: spyder/app/mainwindow.py:769
msgid "guiqwt examples"
msgstr ""
-#: spyder/app/mainwindow.py:772
+#: spyder/app/mainwindow.py:774
msgid "Sift"
msgstr ""
-#: spyder/app/mainwindow.py:782
-msgid "ViTables"
-msgstr ""
-
-#: spyder/app/mainwindow.py:796
+#: spyder/app/mainwindow.py:792
msgid "Fullscreen mode"
msgstr ""
-#: spyder/app/mainwindow.py:808
+#: spyder/app/mainwindow.py:804
msgid "Main toolbar"
msgstr ""
-#: spyder/app/mainwindow.py:817
+#: spyder/app/mainwindow.py:813
msgid ""
"Spyder Internal Console\n"
"\n"
@@ -285,270 +276,282 @@ msgid ""
"\n"
msgstr ""
-#: spyder/app/mainwindow.py:834
+#: spyder/app/mainwindow.py:830
msgid "Loading help..."
msgstr ""
-#: spyder/app/mainwindow.py:841
+#: spyder/app/mainwindow.py:837
msgid "Loading outline explorer..."
msgstr ""
-#: spyder/app/mainwindow.py:847
+#: spyder/app/mainwindow.py:843
msgid "Loading editor..."
msgstr ""
-#: spyder/app/mainwindow.py:853 spyder/plugins/console.py:141
-#: spyder/widgets/ipythonconsole/client.py:414
+#: spyder/app/mainwindow.py:849 spyder/plugins/console.py:141
+#: spyder/widgets/ipythonconsole/client.py:453
msgid "&Quit"
msgstr ""
-#: spyder/app/mainwindow.py:855 spyder/plugins/console.py:143
+#: spyder/app/mainwindow.py:851 spyder/plugins/console.py:143
msgid "Quit"
msgstr ""
-#: spyder/app/mainwindow.py:859
+#: spyder/app/mainwindow.py:855
msgid "&Restart"
msgstr ""
-#: spyder/app/mainwindow.py:861
+#: spyder/app/mainwindow.py:857
msgid "Restart"
msgstr ""
-#: spyder/app/mainwindow.py:875
+#: spyder/app/mainwindow.py:871
msgid "Loading file explorer..."
msgstr ""
-#: spyder/app/mainwindow.py:882
+#: spyder/app/mainwindow.py:878
msgid "Loading history plugin..."
msgstr ""
-#: spyder/app/mainwindow.py:893
+#: spyder/app/mainwindow.py:889
msgid "Loading online help..."
msgstr ""
-#: spyder/app/mainwindow.py:898
+#: spyder/app/mainwindow.py:894
msgid "Loading project explorer..."
msgstr ""
-#: spyder/app/mainwindow.py:911
+#: spyder/app/mainwindow.py:907
msgid "Loading namespace browser..."
msgstr ""
-#: spyder/app/mainwindow.py:917
+#: spyder/app/mainwindow.py:913
msgid "Loading IPython console..."
msgstr ""
-#: spyder/app/mainwindow.py:922
+#: spyder/app/mainwindow.py:918
msgid "Setting up main window..."
msgstr ""
-#: spyder/app/mainwindow.py:926
+#: spyder/app/mainwindow.py:922
msgid "Troubleshooting..."
msgstr ""
-#: spyder/app/mainwindow.py:928
+#: spyder/app/mainwindow.py:924
msgid "Dependencies..."
msgstr ""
-#: spyder/app/mainwindow.py:932
+#: spyder/app/mainwindow.py:928
msgid "Report issue..."
msgstr ""
-#: spyder/app/mainwindow.py:936
+#: spyder/app/mainwindow.py:932
msgid "Spyder support..."
msgstr ""
-#: spyder/app/mainwindow.py:939
+#: spyder/app/mainwindow.py:935
msgid "Check for updates..."
msgstr ""
-#: spyder/app/mainwindow.py:962
+#: spyder/app/mainwindow.py:940
msgid "Spyder documentation"
msgstr ""
-#: spyder/app/mainwindow.py:970
+#: spyder/app/mainwindow.py:948
msgid "Spyder tutorial"
msgstr ""
-#: spyder/app/mainwindow.py:975
+#: spyder/app/mainwindow.py:953
msgid "Shortcuts Summary"
msgstr ""
-#: spyder/app/mainwindow.py:981
+#: spyder/app/mainwindow.py:959
msgid "Interactive tours"
msgstr ""
-#: spyder/app/mainwindow.py:1008
+#: spyder/app/mainwindow.py:986
msgid "Python documentation"
msgstr ""
-#: spyder/app/mainwindow.py:1014
+#: spyder/app/mainwindow.py:992
msgid "IPython documentation"
msgstr ""
-#: spyder/app/mainwindow.py:1015
+#: spyder/app/mainwindow.py:993
msgid "Intro to IPython"
msgstr ""
-#: spyder/app/mainwindow.py:1017
+#: spyder/app/mainwindow.py:995
msgid "Quick reference"
msgstr ""
-#: spyder/app/mainwindow.py:1019
+#: spyder/app/mainwindow.py:997
msgid "Console help"
msgstr ""
-#: spyder/app/mainwindow.py:1049
+#: spyder/app/mainwindow.py:1027
msgid "Installed Python modules"
msgstr ""
-#: spyder/app/mainwindow.py:1053
+#: spyder/app/mainwindow.py:1031
msgid "Online documentation"
msgstr ""
-#: spyder/app/mainwindow.py:1066
+#: spyder/app/mainwindow.py:1044
msgid "Qt documentation"
msgstr ""
-#: spyder/app/mainwindow.py:1072
+#: spyder/app/mainwindow.py:1050
msgid "About %s..."
msgstr ""
-#: spyder/app/mainwindow.py:1103
+#: spyder/app/mainwindow.py:1081
msgid "Panes"
msgstr ""
-#: spyder/app/mainwindow.py:1105
+#: spyder/app/mainwindow.py:1083
msgid "Toolbars"
msgstr ""
-#: spyder/app/mainwindow.py:1106
+#: spyder/app/mainwindow.py:1084
msgid "Window layouts"
msgstr ""
-#: spyder/app/mainwindow.py:1115 spyder/app/mainwindow.py:1943
-#: spyder/app/mainwindow.py:1944
+#: spyder/app/mainwindow.py:1093 spyder/app/mainwindow.py:1920
+#: spyder/app/mainwindow.py:1921
msgid "Show toolbars"
msgstr ""
-#: spyder/app/mainwindow.py:1130
+#: spyder/app/mainwindow.py:1108
msgid "Attached console window (debugging)"
msgstr ""
-#: spyder/app/mainwindow.py:1322 spyder/plugins/projects.py:254
-#: spyder/widgets/explorer.py:721 spyder/widgets/explorer.py:826
-#: spyder/widgets/variableexplorer/arrayeditor.py:587
-#: spyder/widgets/variableexplorer/collectionseditor.py:427
-#: spyder/widgets/variableexplorer/dataframeeditor.py:758
-#: spyder/widgets/variableexplorer/dataframeeditor.py:762
-#: spyder/widgets/variableexplorer/namespacebrowser.py:299
+#: spyder/app/mainwindow.py:1298 spyder/app/mainwindow.py:1988
+#: spyder/plugins/configdialog.py:1154 spyder/plugins/projects.py:269
+#: spyder/widgets/explorer.py:723 spyder/widgets/explorer.py:828
+#: spyder/widgets/reporterror.py:285
+#: spyder/widgets/variableexplorer/arrayeditor.py:586
+#: spyder/widgets/variableexplorer/collectionseditor.py:460
+#: spyder/widgets/variableexplorer/dataframeeditor.py:797
+#: spyder/plugins/profiler/widgets/profilergui.py:295
+#: spyder/widgets/variableexplorer/namespacebrowser.py:311
+#: spyder/plugins/pylint/widgets/pylintgui.py:128
+#: spyder/plugins/pylint/widgets/pylintgui.py:363
+#: spyder/plugins/pylint/widgets/pylintgui.py:391
msgid "Error"
msgstr ""
-#: spyder/app/mainwindow.py:1323
+#: spyder/app/mainwindow.py:1299
msgid "You have missing dependencies!
%s
Please install them to avoid this message.
Note: Spyder could work without some of these dependencies, however to have a smooth experience when using Spyder we strongly recommend you to install all the listed missing dependencies.
Failing to install these dependencies might result in bugs. Please be sure that any found bugs are not the direct result of missing dependencies, prior to reporting a new issue."
msgstr ""
-#: spyder/app/mainwindow.py:1779
+#: spyder/app/mainwindow.py:1756
msgid "Spyder Default Layout"
msgstr ""
-#: spyder/app/mainwindow.py:1797
+#: spyder/app/mainwindow.py:1774
msgid "Save current layout"
msgstr ""
-#: spyder/app/mainwindow.py:1801
+#: spyder/app/mainwindow.py:1778
msgid "Layout preferences"
msgstr ""
-#: spyder/app/mainwindow.py:1805
+#: spyder/app/mainwindow.py:1782
msgid "Reset to spyder default"
msgstr ""
-#: spyder/app/mainwindow.py:1825 spyder/app/mainwindow.py:1847
-#: spyder/app/mainwindow.py:1913 spyder/app/mainwindow.py:1921
-#: spyder/app/mainwindow.py:2799 spyder/plugins/configdialog.py:1345
-#: spyder/plugins/ipythonconsole.py:131 spyder/plugins/ipythonconsole.py:927
-#: spyder/plugins/ipythonconsole.py:1386 spyder/plugins/maininterpreter.py:149
-#: spyder/plugins/maininterpreter.py:174 spyder/plugins/maininterpreter.py:203
-#: spyder/utils/environ.py:95 spyder/utils/environ.py:108
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:131
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:149
-#: spyder/widgets/variableexplorer/arrayeditor.py:510
-#: spyder/widgets/variableexplorer/collectionseditor.py:416
-#: spyder/widgets/variableexplorer/collectionseditor.py:1095
+#: spyder/app/mainwindow.py:1802 spyder/app/mainwindow.py:1824
+#: spyder/app/mainwindow.py:1890 spyder/app/mainwindow.py:1898
+#: spyder/app/mainwindow.py:2843 spyder/plugins/configdialog.py:1415
+#: spyder/plugins/ipythonconsole.py:134 spyder/plugins/ipythonconsole.py:987
+#: spyder/plugins/ipythonconsole.py:1439 spyder/plugins/maininterpreter.py:162
+#: spyder/plugins/maininterpreter.py:183 spyder/plugins/maininterpreter.py:212
+#: spyder/utils/environ.py:56 spyder/utils/environ.py:107
+#: spyder/utils/environ.py:120
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:140
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:158
+#: spyder/widgets/variableexplorer/arrayeditor.py:508
+#: spyder/widgets/variableexplorer/collectionseditor.py:449
+#: spyder/plugins/pylint/widgets/pylintgui.py:126
+#: spyder/widgets/variableexplorer/collectionseditor.py:1143
+#: spyder/widgets/variableexplorer/namespacebrowser.py:305
msgid "Warning"
msgstr ""
-#: spyder/app/mainwindow.py:1826
+#: spyder/app/mainwindow.py:1803
msgid ""
"Window layout will be reset to default settings: this affects window position, size and dockwidgets.\n"
"Do you want to continue?"
msgstr ""
-#: spyder/app/mainwindow.py:1848
+#: spyder/app/mainwindow.py:1825
msgid "Layout %s will be overwritten. Do you want to continue?"
msgstr ""
-#: spyder/app/mainwindow.py:1914
+#: spyder/app/mainwindow.py:1891
msgid "Error opening the custom layout. Please close Spyder and try again. If the issue persists, then you must use 'Reset to Spyder default' from the layout menu."
msgstr ""
-#: spyder/app/mainwindow.py:1922
+#: spyder/app/mainwindow.py:1899
msgid "Quick switch layout #%s has not yet been defined."
msgstr ""
-#: spyder/app/mainwindow.py:1940 spyder/app/mainwindow.py:1941
+#: spyder/app/mainwindow.py:1917 spyder/app/mainwindow.py:1918
msgid "Hide toolbars"
msgstr ""
-#: spyder/app/mainwindow.py:2256 spyder/app/mainwindow.py:2257
+#: spyder/app/mainwindow.py:1989
+msgid "{} is no longer a valid Spyder project! Since it is the current active project, it will be closed automatically."
+msgstr ""
+
+#: spyder/app/mainwindow.py:2252 spyder/app/mainwindow.py:2253
msgid "Maximize current pane"
msgstr ""
-#: spyder/app/mainwindow.py:2260
+#: spyder/app/mainwindow.py:2256
msgid "Restore current pane"
msgstr ""
-#: spyder/app/mainwindow.py:2261
+#: spyder/app/mainwindow.py:2257
msgid "Restore pane to its original size"
msgstr ""
-#: spyder/app/mainwindow.py:2359
+#: spyder/app/mainwindow.py:2439
msgid "About %s"
msgstr ""
-#: spyder/app/mainwindow.py:2538 spyder/plugins/editor.py:168
+#: spyder/app/mainwindow.py:2579 spyder/plugins/editor.py:168
#: spyder/plugins/runconfig.py:354 spyder/plugins/runconfig.py:476
-#: spyder/utils/programs.py:286 spyder/widgets/explorer.py:344
+#: spyder/utils/programs.py:307 spyder/widgets/explorer.py:347
msgid "Run"
msgstr ""
-#: spyder/app/mainwindow.py:2539
+#: spyder/app/mainwindow.py:2580
msgid "Running an external system terminal is not supported on platform %s."
msgstr ""
-#: spyder/app/mainwindow.py:2800
+#: spyder/app/mainwindow.py:2844
msgid "Spyder will restart and reset to default settings:
Do you want to continue?"
msgstr ""
-#: spyder/app/mainwindow.py:2928 spyder/widgets/helperwidgets.py:254
+#: spyder/app/mainwindow.py:2973 spyder/widgets/helperwidgets.py:254
msgid "Spyder updates"
msgstr ""
-#: spyder/app/mainwindow.py:2929 spyder/plugins/configdialog.py:835
+#: spyder/app/mainwindow.py:2974 spyder/plugins/configdialog.py:888
msgid "Check for updates on startup"
msgstr ""
-#: spyder/app/mainwindow.py:2948
+#: spyder/app/mainwindow.py:2993
msgid "
IMPORTANT NOTE: It seems that you are using Spyder with Anaconda/Miniconda. Please don't use pip
to update it as that will probably break your installation.
Instead, please wait until new conda packages are available and use conda
to perform the update.
"
msgstr ""
-#: spyder/app/mainwindow.py:2958
+#: spyder/app/mainwindow.py:3003
msgid "Spyder %s is available!
Please use your package manager to update Spyder or go to our Releases page to download this new version.
If you are not sure how to proceed to update Spyder please refer to our Installation instructions."
msgstr ""
-#: spyder/app/mainwindow.py:2971
+#: spyder/app/mainwindow.py:3016
msgid "Spyder is up to date."
msgstr ""
@@ -626,8 +629,8 @@ msgstr ""
msgid "In this pane you can view and edit the variables generated during the execution of a program, or those entered directly in one of Spyder consoles.
As you can see, the Variable Explorer is showing the variables generated during the last step of this tour. By doing a double-click on any of them, a new window will be opened, where you can inspect and modify their contents."
msgstr ""
-#: spyder/app/tour.py:179 spyder/plugins/help.py:484
-#: spyder/plugins/help.py:937 spyder/widgets/internalshell.py:270
+#: spyder/app/tour.py:179 spyder/plugins/help.py:482
+#: spyder/plugins/help.py:931 spyder/widgets/internalshell.py:271
msgid "Help"
msgstr ""
@@ -671,7 +674,7 @@ msgstr ""
msgid "New features in version 3.0"
msgstr ""
-#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:446
+#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:474
msgid "Run code"
msgstr ""
@@ -679,392 +682,397 @@ msgstr ""
msgid "Go to step: "
msgstr ""
-#: spyder/config/base.py:269
-msgid "Update LANGUAGE_CODES (inside config/base.py) if a new translation has been added to Spyder"
-msgstr ""
-
-#: spyder/config/utils.py:24
+#: spyder/config/utils.py:24 spyder/plugins/pylint/widgets/pylintgui.py:289
msgid "Python files"
msgstr ""
-#: spyder/config/utils.py:25
+#: spyder/config/utils.py:26
msgid "Cython/Pyrex files"
msgstr ""
-#: spyder/config/utils.py:26
+#: spyder/config/utils.py:27
msgid "C files"
msgstr ""
-#: spyder/config/utils.py:27
+#: spyder/config/utils.py:28
msgid "C++ files"
msgstr ""
-#: spyder/config/utils.py:28
+#: spyder/config/utils.py:29
msgid "OpenCL files"
msgstr ""
-#: spyder/config/utils.py:29
+#: spyder/config/utils.py:30
msgid "Fortran files"
msgstr ""
-#: spyder/config/utils.py:30
+#: spyder/config/utils.py:31
msgid "IDL files"
msgstr ""
-#: spyder/config/utils.py:31
+#: spyder/config/utils.py:32
msgid "MATLAB files"
msgstr ""
-#: spyder/config/utils.py:32
+#: spyder/config/utils.py:33
msgid "Julia files"
msgstr ""
-#: spyder/config/utils.py:33
+#: spyder/config/utils.py:34
msgid "Yaml files"
msgstr ""
-#: spyder/config/utils.py:34
+#: spyder/config/utils.py:35
msgid "Patch and diff files"
msgstr ""
-#: spyder/config/utils.py:35
+#: spyder/config/utils.py:36
msgid "Batch files"
msgstr ""
-#: spyder/config/utils.py:36 spyder/utils/iofuncs.py:426
+#: spyder/config/utils.py:37
msgid "Text files"
msgstr ""
-#: spyder/config/utils.py:37
+#: spyder/config/utils.py:38
msgid "reStructuredText files"
msgstr ""
-#: spyder/config/utils.py:38
+#: spyder/config/utils.py:39
msgid "gettext files"
msgstr ""
-#: spyder/config/utils.py:39
+#: spyder/config/utils.py:40
msgid "NSIS files"
msgstr ""
-#: spyder/config/utils.py:40
+#: spyder/config/utils.py:41
msgid "Web page files"
msgstr ""
-#: spyder/config/utils.py:41
+#: spyder/config/utils.py:42
msgid "XML files"
msgstr ""
-#: spyder/config/utils.py:42
+#: spyder/config/utils.py:43
msgid "Javascript files"
msgstr ""
-#: spyder/config/utils.py:43
+#: spyder/config/utils.py:44
msgid "Json files"
msgstr ""
-#: spyder/config/utils.py:44
+#: spyder/config/utils.py:45
msgid "IPython notebooks"
msgstr ""
-#: spyder/config/utils.py:45
+#: spyder/config/utils.py:46
msgid "Enaml files"
msgstr ""
-#: spyder/config/utils.py:46
+#: spyder/config/utils.py:47
msgid "Configuration files"
msgstr ""
-#: spyder/config/utils.py:48
+#: spyder/config/utils.py:49
msgid "Markdown files"
msgstr ""
-#: spyder/config/utils.py:52 spyder/widgets/explorer.py:794
+#: spyder/config/utils.py:53 spyder/widgets/explorer.py:796
msgid "All files"
msgstr ""
-#: spyder/config/utils.py:134
+#: spyder/config/utils.py:138
msgid "Supported text files"
msgstr ""
-#: spyder/plugins/__init__.py:511 spyder/plugins/editor.py:105
-#: spyder/plugins/editor.py:568 spyder/plugins/editor.py:1816
-#: spyder/plugins/help.py:117 spyder/plugins/help.py:385
-#: spyder/widgets/editor.py:534 spyder/widgets/sourcecode/codeeditor.py:98
-#: spyder/widgets/sourcecode/codeeditor.py:3222
+#: spyder/plugins/__init__.py:512 spyder/plugins/editor.py:105
+#: spyder/plugins/editor.py:568 spyder/plugins/editor.py:1830
+#: spyder/plugins/help.py:117 spyder/plugins/help.py:383
+#: spyder/widgets/editor.py:544 spyder/widgets/sourcecode/codeeditor.py:98
+#: spyder/widgets/sourcecode/codeeditor.py:3229
msgid "Editor"
msgstr ""
-#: spyder/plugins/configdialog.py:144
+#: spyder/plugins/configdialog.py:146
msgid "Reset to defaults"
msgstr ""
-#: spyder/plugins/configdialog.py:156
+#: spyder/plugins/configdialog.py:158
msgid "Preferences"
msgstr ""
-#: spyder/plugins/configdialog.py:508
+#: spyder/plugins/configdialog.py:514
msgid "Invalid directory path"
msgstr ""
-#: spyder/plugins/configdialog.py:511 spyder/plugins/configdialog.py:526
+#: spyder/plugins/configdialog.py:517 spyder/plugins/configdialog.py:532
#: spyder/plugins/runconfig.py:220 spyder/plugins/runconfig.py:268
-#: spyder/plugins/workingdirectory.py:240 spyder/widgets/explorer.py:705
-#: spyder/widgets/findinfiles.py:332 spyder/widgets/pathmanager.py:258
+#: spyder/plugins/workingdirectory.py:241 spyder/widgets/explorer.py:707
+#: spyder/widgets/findinfiles.py:347 spyder/widgets/pathmanager.py:259
#: spyder/widgets/projects/projectdialog.py:155
msgid "Select directory"
msgstr ""
-#: spyder/plugins/configdialog.py:538
+#: spyder/plugins/configdialog.py:544 spyder/plugins/configdialog.py:704
msgid "Invalid file path"
msgstr ""
-#: spyder/plugins/configdialog.py:541 spyder/plugins/configdialog.py:558
+#: spyder/plugins/configdialog.py:547 spyder/plugins/configdialog.py:564
+#: spyder/plugins/configdialog.py:707
msgid "Select file"
msgstr ""
-#: spyder/plugins/configdialog.py:557
+#: spyder/plugins/configdialog.py:563
msgid "All files (*)"
msgstr ""
-#: spyder/plugins/configdialog.py:630
+#: spyder/plugins/configdialog.py:636
msgid "Bold"
msgstr ""
-#: spyder/plugins/configdialog.py:633
+#: spyder/plugins/configdialog.py:639
msgid "Italic"
msgstr ""
-#: spyder/plugins/configdialog.py:687
+#: spyder/plugins/configdialog.py:728
msgid "Font: "
msgstr ""
-#: spyder/plugins/configdialog.py:693
+#: spyder/plugins/configdialog.py:734
msgid "Size: "
msgstr ""
-#: spyder/plugins/configdialog.py:712
+#: spyder/plugins/configdialog.py:753
msgid "Font style"
msgstr ""
-#: spyder/plugins/configdialog.py:789
+#: spyder/plugins/configdialog.py:830
msgid "Spyder needs to restart to change the following setting:"
msgstr ""
-#: spyder/plugins/configdialog.py:792
+#: spyder/plugins/configdialog.py:833
msgid "Spyder needs to restart to change the following settings:"
msgstr ""
-#: spyder/plugins/configdialog.py:794
+#: spyder/plugins/configdialog.py:835
msgid "Do you wish to restart now?"
msgstr ""
-#: spyder/plugins/configdialog.py:800
+#: spyder/plugins/configdialog.py:841
msgid "Information"
msgstr ""
-#: spyder/plugins/configdialog.py:814 spyder/plugins/configdialog.py:821
+#: spyder/plugins/configdialog.py:855 spyder/plugins/configdialog.py:862
#: spyder/widgets/projects/configdialog.py:74
msgid "General"
msgstr ""
-#: spyder/plugins/configdialog.py:824
-msgid "Language"
+#: spyder/plugins/configdialog.py:866
+msgid "Language:"
+msgstr ""
+
+#: spyder/plugins/configdialog.py:874
+msgid "Rendering engine:"
msgstr ""
-#: spyder/plugins/configdialog.py:827
+#: spyder/plugins/configdialog.py:879
msgid "Use a single instance"
msgstr ""
-#: spyder/plugins/configdialog.py:829
+#: spyder/plugins/configdialog.py:881
msgid "Set this to open external
Python files in an already running instance (Requires a restart)"
msgstr ""
-#: spyder/plugins/configdialog.py:832
+#: spyder/plugins/configdialog.py:885
msgid "Prompt when exiting"
msgstr ""
-#: spyder/plugins/configdialog.py:833
+#: spyder/plugins/configdialog.py:886
msgid "Show internal Spyder errors to report them to Github"
msgstr ""
-#: spyder/plugins/configdialog.py:852 spyder/plugins/editor.py:114
-#: spyder/plugins/ipythonconsole.py:290
+#: spyder/plugins/configdialog.py:914 spyder/plugins/editor.py:114
+#: spyder/plugins/ipythonconsole.py:301
#: spyder/widgets/projects/configdialog.py:81
msgid "Interface"
msgstr ""
-#: spyder/plugins/configdialog.py:860
+#: spyder/plugins/configdialog.py:922
msgid "Qt windows style"
msgstr ""
-#: spyder/plugins/configdialog.py:866
+#: spyder/plugins/configdialog.py:928
msgid "Icon theme"
msgstr ""
-#: spyder/plugins/configdialog.py:870
+#: spyder/plugins/configdialog.py:932
msgid "Vertical title bars in panes"
msgstr ""
-#: spyder/plugins/configdialog.py:872
+#: spyder/plugins/configdialog.py:934
msgid "Vertical tabs in panes"
msgstr ""
-#: spyder/plugins/configdialog.py:874
+#: spyder/plugins/configdialog.py:936
msgid "Animated toolbars and panes"
msgstr ""
-#: spyder/plugins/configdialog.py:876
+#: spyder/plugins/configdialog.py:938
msgid "Tear off menus"
msgstr ""
-#: spyder/plugins/configdialog.py:877
+#: spyder/plugins/configdialog.py:939
msgid "Set this to detach any
menu from the main window"
msgstr ""
-#: spyder/plugins/configdialog.py:879
+#: spyder/plugins/configdialog.py:941
msgid "Custom margin for panes:"
msgstr ""
-#: spyder/plugins/configdialog.py:881
+#: spyder/plugins/configdialog.py:943
msgid "pixels"
msgstr ""
-#: spyder/plugins/configdialog.py:888
+#: spyder/plugins/configdialog.py:950
msgid "Cursor blinking:"
msgstr ""
-#: spyder/plugins/configdialog.py:890
+#: spyder/plugins/configdialog.py:952
msgid "ms"
msgstr ""
-#: spyder/plugins/configdialog.py:929
+#: spyder/plugins/configdialog.py:991
msgid "Status bar"
msgstr ""
-#: spyder/plugins/configdialog.py:930
+#: spyder/plugins/configdialog.py:992
msgid "Show status bar"
msgstr ""
-#: spyder/plugins/configdialog.py:932
+#: spyder/plugins/configdialog.py:994
msgid "Show memory usage every"
msgstr ""
-#: spyder/plugins/configdialog.py:934 spyder/plugins/configdialog.py:943
+#: spyder/plugins/configdialog.py:996 spyder/plugins/configdialog.py:1005
#: spyder/plugins/editor.py:139 spyder/plugins/editor.py:283
msgid " ms"
msgstr ""
-#: spyder/plugins/configdialog.py:941
+#: spyder/plugins/configdialog.py:1003
msgid "Show CPU usage every"
msgstr ""
-#: spyder/plugins/configdialog.py:974
+#: spyder/plugins/configdialog.py:1036
msgid "Screen resolution"
msgstr ""
-#: spyder/plugins/configdialog.py:976
+#: spyder/plugins/configdialog.py:1038
msgid "Configuration for high DPI screens
Please see {0}<> for more information about these options (in English)."
msgstr ""
-#: spyder/plugins/configdialog.py:986
+#: spyder/plugins/configdialog.py:1048
msgid "Normal"
msgstr ""
-#: spyder/plugins/configdialog.py:990
+#: spyder/plugins/configdialog.py:1052
msgid "Enable auto high DPI scaling"
msgstr ""
-#: spyder/plugins/configdialog.py:993
+#: spyder/plugins/configdialog.py:1055
msgid "Set this for high DPI displays"
msgstr ""
-#: spyder/plugins/configdialog.py:997
+#: spyder/plugins/configdialog.py:1059
msgid "Set a custom high DPI scaling"
msgstr ""
-#: spyder/plugins/configdialog.py:1000
+#: spyder/plugins/configdialog.py:1062
msgid "Set this for high DPI displays when auto scaling does not work"
msgstr ""
-#: spyder/plugins/configdialog.py:1006
+#: spyder/plugins/configdialog.py:1068
msgid "Enter values for different screens separated by semicolons ';', float values are supported"
msgstr ""
-#: spyder/plugins/configdialog.py:1033
+#: spyder/plugins/configdialog.py:1095
msgid "Plain text font"
msgstr ""
-#: spyder/plugins/configdialog.py:1039
+#: spyder/plugins/configdialog.py:1101
msgid "Rich text font"
msgstr ""
-#: spyder/plugins/configdialog.py:1042
+#: spyder/plugins/configdialog.py:1104
msgid "Fonts"
msgstr ""
-#: spyder/plugins/configdialog.py:1056
+#: spyder/plugins/configdialog.py:1118
msgid "Appearance"
msgstr ""
-#: spyder/plugins/configdialog.py:1058 spyder/plugins/ipythonconsole.py:579
+#: spyder/plugins/configdialog.py:1120 spyder/plugins/ipythonconsole.py:633
msgid "Advanced Settings"
msgstr ""
-#: spyder/plugins/configdialog.py:1094
+#: spyder/plugins/configdialog.py:1155
+msgid "We're sorry but the following error occurred while trying to set your selected language:
{}"
+msgstr ""
+
+#: spyder/plugins/configdialog.py:1164
msgid "Syntax coloring"
msgstr ""
-#: spyder/plugins/configdialog.py:1107
+#: spyder/plugins/configdialog.py:1177
msgid "Here you can select the color scheme used in the Editor and all other Spyder plugins.
You can also edit the color schemes provided by Spyder or create your own ones by using the options provided below.
"
msgstr ""
-#: spyder/plugins/configdialog.py:1112
+#: spyder/plugins/configdialog.py:1182
msgid "Edit selected"
msgstr ""
-#: spyder/plugins/configdialog.py:1113
+#: spyder/plugins/configdialog.py:1183
msgid "Create new scheme"
msgstr ""
-#: spyder/plugins/configdialog.py:1114 spyder/widgets/explorer.py:583
+#: spyder/plugins/configdialog.py:1184 spyder/widgets/explorer.py:582
#: spyder/widgets/projects/explorer.py:243 spyder/widgets/shell.py:136
msgid "Delete"
msgstr ""
-#: spyder/plugins/configdialog.py:1117
+#: spyder/plugins/configdialog.py:1187
msgid "Reset"
msgstr ""
-#: spyder/plugins/configdialog.py:1124
+#: spyder/plugins/configdialog.py:1194
msgid "Scheme:"
msgstr ""
-#: spyder/plugins/configdialog.py:1155
+#: spyder/plugins/configdialog.py:1225
msgid "Manage color schemes"
msgstr ""
-#: spyder/plugins/configdialog.py:1346
+#: spyder/plugins/configdialog.py:1416
msgid "Are you sure you want to delete this scheme?"
msgstr ""
-#: spyder/plugins/configdialog.py:1463
+#: spyder/plugins/configdialog.py:1533
msgid "Text"
msgstr ""
-#: spyder/plugins/configdialog.py:1465
+#: spyder/plugins/configdialog.py:1535
msgid "Highlight"
msgstr ""
-#: spyder/plugins/configdialog.py:1467
+#: spyder/plugins/configdialog.py:1537
msgid "Background"
msgstr ""
-#: spyder/plugins/configdialog.py:1471
+#: spyder/plugins/configdialog.py:1541
msgid "Scheme name:"
msgstr ""
-#: spyder/plugins/configdialog.py:1478
+#: spyder/plugins/configdialog.py:1548
msgid "Color scheme editor"
msgstr ""
@@ -1100,7 +1108,7 @@ msgstr ""
msgid "Buffer..."
msgstr ""
-#: spyder/plugins/console.py:163 spyder/plugins/history.py:43
+#: spyder/plugins/console.py:163 spyder/plugins/history.py:45
msgid "Set maximum line count"
msgstr ""
@@ -1113,13 +1121,13 @@ msgid "Set external editor executable path"
msgstr ""
#: spyder/plugins/console.py:170 spyder/plugins/editor.py:149
-#: spyder/plugins/help.py:152 spyder/plugins/help.py:360
-#: spyder/plugins/history.py:46 spyder/plugins/history.py:157
+#: spyder/plugins/help.py:152 spyder/plugins/help.py:358
+#: spyder/plugins/history.py:48 spyder/plugins/history.py:159
msgid "Wrap lines"
msgstr ""
#: spyder/plugins/console.py:173 spyder/plugins/editor.py:185
-#: spyder/plugins/ipythonconsole.py:300
+#: spyder/plugins/ipythonconsole.py:311
msgid "Display balloon tips"
msgstr ""
@@ -1139,7 +1147,8 @@ msgstr ""
msgid "Run Python script"
msgstr ""
-#: spyder/plugins/console.py:266 spyder/widgets/explorer.py:809
+#: spyder/plugins/console.py:266 spyder/widgets/explorer.py:811
+#: spyder/plugins/profiler/widgets/profilergui.py:220
msgid "Python scripts"
msgstr ""
@@ -1172,8 +1181,8 @@ msgid "Show tab bar"
msgstr ""
#: spyder/plugins/editor.py:122 spyder/plugins/editor.py:199
-#: spyder/plugins/help.py:151 spyder/plugins/history.py:45
-#: spyder/plugins/ipythonconsole.py:332
+#: spyder/plugins/help.py:151 spyder/plugins/history.py:47
+#: spyder/plugins/ipythonconsole.py:349
msgid "Source code"
msgstr ""
@@ -1373,8 +1382,8 @@ msgstr ""
msgid "Fix automatically and show warning message box"
msgstr ""
-#: spyder/plugins/editor.py:357 spyder/plugins/ipythonconsole.py:573
-#: spyder/plugins/variableexplorer.py:35
+#: spyder/plugins/editor.py:357 spyder/plugins/ipythonconsole.py:627
+#: spyder/plugins/variableexplorer.py:47
msgid "Display"
msgstr ""
@@ -1390,8 +1399,8 @@ msgstr ""
msgid "&New file..."
msgstr ""
-#: spyder/plugins/editor.py:645 spyder/widgets/explorer.py:786
-#: spyder/widgets/explorer.py:793
+#: spyder/plugins/editor.py:645 spyder/widgets/explorer.py:788
+#: spyder/widgets/explorer.py:795
msgid "New file"
msgstr ""
@@ -1407,8 +1416,8 @@ msgstr ""
msgid "&Open..."
msgstr ""
-#: spyder/plugins/editor.py:662 spyder/plugins/editor.py:1867
-#: spyder/plugins/editor.py:1873
+#: spyder/plugins/editor.py:662 spyder/plugins/editor.py:1881
+#: spyder/plugins/editor.py:1887
msgid "Open file"
msgstr ""
@@ -1424,7 +1433,7 @@ msgstr ""
msgid "&Save"
msgstr ""
-#: spyder/plugins/editor.py:673 spyder/widgets/editor.py:1672
+#: spyder/plugins/editor.py:673 spyder/widgets/editor.py:1675
msgid "Save file"
msgstr ""
@@ -1505,6 +1514,7 @@ msgid "Set/Edit conditional breakpoint"
msgstr ""
#: spyder/plugins/editor.py:755
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:180
msgid "Clear breakpoints in all files"
msgstr ""
@@ -1548,8 +1558,10 @@ msgstr ""
msgid "Run until current function or method returns"
msgstr ""
-#: spyder/plugins/editor.py:796 spyder/widgets/findinfiles.py:438
-#: spyder/widgets/ipythonconsole/client.py:354
+#: spyder/plugins/editor.py:796 spyder/widgets/findinfiles.py:450
+#: spyder/widgets/ipythonconsole/client.py:393
+#: spyder/plugins/profiler/widgets/profilergui.py:87
+#: spyder/plugins/pylint/widgets/pylintgui.py:211
msgid "Stop"
msgstr ""
@@ -1577,7 +1589,7 @@ msgstr ""
msgid "Run again last file"
msgstr ""
-#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2720
+#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2727
msgid "Run &selection or current line"
msgstr ""
@@ -1585,7 +1597,7 @@ msgstr ""
msgid "Run selection or current line"
msgstr ""
-#: spyder/plugins/editor.py:836 spyder/widgets/sourcecode/codeeditor.py:2708
+#: spyder/plugins/editor.py:836 spyder/widgets/sourcecode/codeeditor.py:2715
msgid "Run cell"
msgstr ""
@@ -1595,7 +1607,7 @@ msgid ""
"[Use #%% to create cells]"
msgstr ""
-#: spyder/plugins/editor.py:845 spyder/widgets/sourcecode/codeeditor.py:2712
+#: spyder/plugins/editor.py:845 spyder/widgets/sourcecode/codeeditor.py:2719
msgid "Run cell and advance"
msgstr ""
@@ -1603,7 +1615,7 @@ msgstr ""
msgid "Run current cell and go to the next one (Shift+Enter)"
msgstr ""
-#: spyder/plugins/editor.py:854 spyder/widgets/sourcecode/codeeditor.py:2716
+#: spyder/plugins/editor.py:854 spyder/widgets/sourcecode/codeeditor.py:2723
msgid "Re-run last cell"
msgstr ""
@@ -1667,11 +1679,11 @@ msgstr ""
msgid "Go to next cursor position"
msgstr ""
-#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Comment"
msgstr ""
-#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Uncomment"
msgstr ""
@@ -1775,8 +1787,8 @@ msgstr ""
msgid "Clear recent files list"
msgstr ""
-#: spyder/plugins/editor.py:1009 spyder/plugins/projects.py:107
-#: spyder/widgets/findinfiles.py:246
+#: spyder/plugins/editor.py:1009 spyder/plugins/projects.py:101
+#: spyder/widgets/findinfiles.py:261
msgid "Clear this list"
msgstr ""
@@ -1784,39 +1796,39 @@ msgstr ""
msgid "Open &recent"
msgstr ""
-#: spyder/plugins/editor.py:1675
+#: spyder/plugins/editor.py:1674
msgid "Spyder Editor"
msgstr ""
-#: spyder/plugins/editor.py:1676
+#: spyder/plugins/editor.py:1675
msgid "This is a temporary script file."
msgstr ""
-#: spyder/plugins/editor.py:1745
+#: spyder/plugins/editor.py:1758
msgid "untitled"
msgstr ""
-#: spyder/plugins/editor.py:1817
+#: spyder/plugins/editor.py:1831
msgid "Maximum number of recent files"
msgstr ""
-#: spyder/plugins/editor.py:1963
+#: spyder/plugins/editor.py:1977
msgid "Printing..."
msgstr ""
-#: spyder/plugins/explorer.py:54
+#: spyder/plugins/explorer.py:55
msgid "File explorer"
msgstr ""
-#: spyder/plugins/findinfiles.py:120 spyder/widgets/findinfiles.py:913
+#: spyder/plugins/findinfiles.py:117 spyder/widgets/findinfiles.py:949
msgid "Find in files"
msgstr ""
-#: spyder/plugins/findinfiles.py:145
+#: spyder/plugins/findinfiles.py:141
msgid "&Find in files"
msgstr ""
-#: spyder/plugins/findinfiles.py:150
+#: spyder/plugins/findinfiles.py:146
msgid "Search text in multiple files"
msgstr ""
@@ -1862,305 +1874,324 @@ msgstr ""
msgid "No further documentation available"
msgstr ""
-#: spyder/plugins/help.py:307 spyder/plugins/help.py:347
+#: spyder/plugins/help.py:307 spyder/plugins/help.py:345
msgid "No documentation available"
msgstr ""
-#: spyder/plugins/help.py:378
+#: spyder/plugins/help.py:376
msgid "Source"
msgstr ""
-#: spyder/plugins/help.py:385 spyder/plugins/runconfig.py:170
-#: spyder/plugins/runconfig.py:486 spyder/widgets/ipythonconsole/client.py:288
+#: spyder/plugins/help.py:383 spyder/plugins/runconfig.py:170
+#: spyder/plugins/runconfig.py:486 spyder/widgets/ipythonconsole/client.py:327
msgid "Console"
msgstr ""
-#: spyder/plugins/help.py:393
+#: spyder/plugins/help.py:391
msgid "Object"
msgstr ""
-#: spyder/plugins/help.py:407
+#: spyder/plugins/help.py:405
msgid "Plain Text"
msgstr ""
-#: spyder/plugins/help.py:411
+#: spyder/plugins/help.py:409
msgid "Show Source"
msgstr ""
-#: spyder/plugins/help.py:415
+#: spyder/plugins/help.py:413
msgid "Rich Text"
msgstr ""
-#: spyder/plugins/help.py:425
+#: spyder/plugins/help.py:423
msgid "Automatic import"
msgstr ""
-#: spyder/plugins/help.py:437 spyder/plugins/history.py:106
-#: spyder/widgets/editor.py:728 spyder/widgets/explorer.py:1200
-#: spyder/widgets/ipythonconsole/client.py:378
-#: spyder/widgets/variableexplorer/namespacebrowser.py:148
+#: spyder/plugins/help.py:435 spyder/plugins/history.py:108
+#: spyder/widgets/editor.py:738 spyder/widgets/explorer.py:1205
+#: spyder/widgets/ipythonconsole/client.py:417
+#: spyder/widgets/variableexplorer/namespacebrowser.py:151
msgid "Options"
msgstr ""
-#: spyder/plugins/help.py:696
+#: spyder/plugins/help.py:692
msgid "Here you can get help of any object by pressing %s in front of it, either on the Editor or the Console.%sHelp can also be shown automatically after writing a left parenthesis next to an object. You can activate this behavior in %s."
msgstr ""
-#: spyder/plugins/help.py:702
+#: spyder/plugins/help.py:698
msgid "Preferences > Help"
msgstr ""
-#: spyder/plugins/help.py:709
+#: spyder/plugins/help.py:705
msgid "Usage"
msgstr ""
-#: spyder/plugins/help.py:710
+#: spyder/plugins/help.py:706
msgid "New to Spyder? Read our"
msgstr ""
-#: spyder/plugins/help.py:711
+#: spyder/plugins/help.py:707
msgid "tutorial"
msgstr ""
-#: spyder/plugins/help.py:718
+#: spyder/plugins/help.py:714
msgid "Please consider installing Sphinx to get documentation rendered in rich text."
msgstr ""
-#: spyder/plugins/help.py:891
+#: spyder/plugins/help.py:885
msgid "Lock"
msgstr ""
-#: spyder/plugins/help.py:891
+#: spyder/plugins/help.py:885
msgid "Unlock"
msgstr ""
-#: spyder/plugins/help.py:938
+#: spyder/plugins/help.py:932
msgid "The following error occured when calling Sphinx %s.
Incompatible Sphinx version or doc string decoding failed.
Error message:
%s"
msgstr ""
-#: spyder/plugins/help.py:982
+#: spyder/plugins/help.py:976
msgid "No source code available."
msgstr ""
-#: spyder/plugins/history.py:39
+#: spyder/plugins/history.py:39 spyder/plugins/pylint/plugin.py:35
msgid "Settings"
msgstr ""
-#: spyder/plugins/history.py:41
+#: spyder/plugins/history.py:43
msgid " entries"
msgstr ""
-#: spyder/plugins/history.py:41
+#: spyder/plugins/history.py:43
msgid "History depth: "
msgstr ""
-#: spyder/plugins/history.py:48
+#: spyder/plugins/history.py:50
msgid "Scroll automatically to last entry"
msgstr ""
-#: spyder/plugins/history.py:126
+#: spyder/plugins/history.py:128
msgid "History log"
msgstr ""
-#: spyder/plugins/history.py:153
+#: spyder/plugins/history.py:153 spyder/plugins/pylint/plugin.py:115
msgid "History..."
msgstr ""
-#: spyder/plugins/history.py:155
+#: spyder/plugins/history.py:155 spyder/plugins/pylint/plugin.py:117
msgid "Set history maximum entries"
msgstr ""
-#: spyder/plugins/history.py:260
+#: spyder/plugins/history.py:260 spyder/plugins/pylint/plugin.py:39
+#: spyder/plugins/pylint/plugin.py:160
msgid "History"
msgstr ""
-#: spyder/plugins/history.py:261
+#: spyder/plugins/history.py:261 spyder/plugins/pylint/plugin.py:161
msgid "Maximum entries"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:65
+#: spyder/plugins/ipythonconsole.py:64
msgid "Symbolic mathematics in the IPython Console"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:69
+#: spyder/plugins/ipythonconsole.py:68
msgid "Run Cython files in the IPython Console"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:73
+#: spyder/plugins/ipythonconsole.py:72
msgid "Integrate the IPython console"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:77
+#: spyder/plugins/ipythonconsole.py:76
msgid "IPython interactive python environment"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:128
+#: spyder/plugins/ipythonconsole.py:80
+msgid "Display 2D graphics in the IPython Console"
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:131
msgid "The authenticity of host %s can't be established. Are you sure you want to continue connecting?"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:140
+#: spyder/plugins/ipythonconsole.py:143
msgid "The authenticity of the host can't be established"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:147
+#: spyder/plugins/ipythonconsole.py:150
msgid "Tunnel '%s' failed to start"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:152
+#: spyder/plugins/ipythonconsole.py:155
msgid "Could not connect to remote host"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:169 spyder/plugins/ipythonconsole.py:799
+#: spyder/plugins/ipythonconsole.py:172 spyder/plugins/ipythonconsole.py:846
msgid "Connect to an existing kernel"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:171
-msgid "Please enter the connection info of the kernel you want to connect to. For that you can either select its JSON connection file using the Browse button, or write directly its id, in case it's a local kernel (for example kernel-3764.json or just 3764)."
+#: spyder/plugins/ipythonconsole.py:174
+msgid "Please select the JSON connection file (e.g. kernel-3764.json) or enter the 4-digit ID (e.g. 3764) of the existing kernel to connect to, and enter the SSH host name and credentials if a remote kernel."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:182
-msgid "Connection info:"
+#: spyder/plugins/ipythonconsole.py:183
+msgid "Kernel ID/Connection file:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:184
-msgid "Path to connection file or kernel id"
+#: spyder/plugins/ipythonconsole.py:185
+msgid "ID number or path to connection file"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:186 spyder/plugins/ipythonconsole.py:203
+#: spyder/plugins/ipythonconsole.py:187 spyder/plugins/ipythonconsole.py:216
msgid "Browse"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:195
-msgid "This is a remote kernel"
+#: spyder/plugins/ipythonconsole.py:196
+msgid "This is a remote kernel (via SSH)"
msgstr ""
#: spyder/plugins/ipythonconsole.py:199
-msgid "username@hostname:port"
+msgid "Note: If connecting to a remote kernel, only the SSH keyfile or the Password field need to be completed, unless the keyfile is protected with a passphrase."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:202
-msgid "Path to ssh key file"
+#: spyder/plugins/ipythonconsole.py:207
+msgid "username@hostname:port"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:211
-msgid "Password or ssh key passphrase"
+#: spyder/plugins/ipythonconsole.py:210
+msgid "Remote user password or SSH keyfile passphrase"
msgstr ""
#: spyder/plugins/ipythonconsole.py:215
-msgid "Host name"
+msgid "Path to SSH keyfile (optional)"
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:224
+msgid "Host name:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:216
-msgid "Ssh key"
+#: spyder/plugins/ipythonconsole.py:225
+msgid "Password:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:217
-msgid "Password"
+#: spyder/plugins/ipythonconsole.py:226
+msgid "SSH keyfile:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:246
-msgid "Open connection file"
+#: spyder/plugins/ipythonconsole.py:257
+msgid "Select kernel connection file"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:251
-msgid "Select ssh key"
+#: spyder/plugins/ipythonconsole.py:262
+msgid "Select SSH keyfile"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:284 spyder/plugins/ipythonconsole.py:734
+#: spyder/plugins/ipythonconsole.py:295 spyder/plugins/ipythonconsole.py:780
msgid "IPython console"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:291
+#: spyder/plugins/ipythonconsole.py:302
msgid "Display initial banner"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:292
+#: spyder/plugins/ipythonconsole.py:303
msgid ""
"This option lets you hide the message shown at\n"
"the top of the console when it's opened."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:294
+#: spyder/plugins/ipythonconsole.py:305
msgid "Use a pager to display additional text inside the console"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:296
+#: spyder/plugins/ipythonconsole.py:307
msgid ""
"Useful if you don't want to fill the console with long help or completion texts.\n"
"Note: Use the Q key to get out of the pager."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:301
+#: spyder/plugins/ipythonconsole.py:312
msgid "Ask for confirmation before closing"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:304
+#: spyder/plugins/ipythonconsole.py:315
msgid "Ask for confirmation before removing all user-defined variables"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:307
+#: spyder/plugins/ipythonconsole.py:318
msgid ""
"This option lets you hide the warning message shown\n"
"when resetting the namespace from Spyder."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:309
-#: spyder/widgets/ipythonconsole/client.py:317
+#: spyder/plugins/ipythonconsole.py:320
+#: spyder/widgets/ipythonconsole/client.py:356
msgid "Show elapsed time"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:320
+#: spyder/plugins/ipythonconsole.py:322
+msgid "Ask for confirmation before restarting"
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:324
+msgid ""
+"This option lets you hide the warning message shown\n"
+"when restarting the kernel."
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:337
msgid "Completion Type"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:321
+#: spyder/plugins/ipythonconsole.py:338
msgid "Decide what type of completion to use"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Graphical"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Plain"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:323
+#: spyder/plugins/ipythonconsole.py:340
msgid "Terminal"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:324
+#: spyder/plugins/ipythonconsole.py:341
msgid "Completion:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:334
+#: spyder/plugins/ipythonconsole.py:351
msgid " lines"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:334
+#: spyder/plugins/ipythonconsole.py:351
msgid "Buffer: "
msgstr ""
-#: spyder/plugins/ipythonconsole.py:336
+#: spyder/plugins/ipythonconsole.py:353
msgid ""
"Set the maximum number of lines of text shown in the\n"
"console before truncation. Specifying -1 disables it\n"
"(not recommended!)"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:345
+#: spyder/plugins/ipythonconsole.py:362
msgid "Support for graphics (Matplotlib)"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:346
+#: spyder/plugins/ipythonconsole.py:363
msgid "Activate support"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:347
+#: spyder/plugins/ipythonconsole.py:364
msgid "Automatically load Pylab and NumPy modules"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:350
+#: spyder/plugins/ipythonconsole.py:367
msgid ""
"This lets you load graphics support without importing \n"
"the commands to do plots. Useful to work with other\n"
@@ -2168,239 +2199,270 @@ msgid ""
"GUIs with Spyder."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:365
+#: spyder/plugins/ipythonconsole.py:382
msgid "Inline"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:366
+#: spyder/plugins/ipythonconsole.py:383
msgid "Automatic"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:367
+#: spyder/plugins/ipythonconsole.py:384
msgid "Graphics backend"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:368
+#: spyder/plugins/ipythonconsole.py:385
msgid "Decide how graphics are going to be displayed in the console. If unsure, please select %s to put graphics inside the console or %s to interact with them (through zooming and panning) in a separate window."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:388
+#: spyder/plugins/ipythonconsole.py:405
msgid "Backend:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:390
+#: spyder/plugins/ipythonconsole.py:407
msgid "This option will be applied the next time a console is opened."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:401
+#: spyder/plugins/ipythonconsole.py:418
msgid "Inline backend"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:402
+#: spyder/plugins/ipythonconsole.py:419
msgid "Decide how to render the figures created by this backend"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:406
+#: spyder/plugins/ipythonconsole.py:423
msgid "Format:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:409
+#: spyder/plugins/ipythonconsole.py:427
msgid "Resolution:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:409
+#: spyder/plugins/ipythonconsole.py:427
msgid "dpi"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:411
+#: spyder/plugins/ipythonconsole.py:429
msgid "Only used when the format is PNG. Default is 72"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:414
+#: spyder/plugins/ipythonconsole.py:432
msgid "Width:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:414 spyder/plugins/ipythonconsole.py:418
+#: spyder/plugins/ipythonconsole.py:432 spyder/plugins/ipythonconsole.py:436
msgid "inches"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:416
+#: spyder/plugins/ipythonconsole.py:434
msgid "Default is 6"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:418
+#: spyder/plugins/ipythonconsole.py:436
msgid "Height:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:420
+#: spyder/plugins/ipythonconsole.py:438
msgid "Default is 4"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:447
+#: spyder/plugins/ipythonconsole.py:440
+msgid "Use a tight layout for inline plots"
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:442
+msgid ""
+"Sets bbox_inches to \"tight\" when\n"
+"plotting inline with matplotlib.\n"
+"When enabled, can cause discrepancies\n"
+"between the image displayed inline and\n"
+"that created using savefig."
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:475
msgid "You can run several lines of code when a console is started. Please introduce each one separated by commas, for example:
import os, import sys"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:453
+#: spyder/plugins/ipythonconsole.py:481
msgid "Lines:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:462
+#: spyder/plugins/ipythonconsole.py:490
msgid "Run a file"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:463
+#: spyder/plugins/ipythonconsole.py:491
msgid "You can also run a whole file at startup instead of just some lines (This is similar to have a PYTHONSTARTUP file)."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:467
+#: spyder/plugins/ipythonconsole.py:495
msgid "Use the following file:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:481
+#: spyder/plugins/ipythonconsole.py:509
+msgid "Jedi completion"
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:510
+msgid "Enable Jedi-based Tab completion in the IPython console; similar to the greedy completer, but without evaluating the code.
Warning: Slows down your console when working with large dataframes!"
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:517
+msgid "Use Jedi completion in the IPython console"
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:530
msgid "Greedy completion"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:482
-msgid "Enable Tab completion on elements of lists, results of function calls, etc, without assigning them to a variable.
For example, you can get completions on things like li[0].<Tab> or ins.meth().<Tab>"
+#: spyder/plugins/ipythonconsole.py:531
+msgid "Enable Tab completion on elements of lists, results of function calls, etc, without assigning them to a variable, like li[0].<Tab> or ins.meth().<Tab>
Warning: Due to a bug, IPython's greedy completer requires a leading <Space> for some completions; e.g. np.sin(<Space>np.<Tab> works while np.sin(np.<Tab> doesn't."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:490
-msgid "Use the greedy completer"
+#: spyder/plugins/ipythonconsole.py:543
+msgid "Use greedy completion in the IPython console"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:501
+#: spyder/plugins/ipythonconsole.py:555
msgid "Autocall"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:502
+#: spyder/plugins/ipythonconsole.py:556
msgid "Autocall makes IPython automatically call any callable object even if you didn't type explicit parentheses.
For example, if you type str 43 it becomes str(43) automatically."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:509
+#: spyder/plugins/ipythonconsole.py:563
msgid "Smart"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:510
+#: spyder/plugins/ipythonconsole.py:564
msgid "Full"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:511
+#: spyder/plugins/ipythonconsole.py:565
msgid "Off"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:513
+#: spyder/plugins/ipythonconsole.py:567
msgid "Autocall: "
msgstr ""
-#: spyder/plugins/ipythonconsole.py:514
+#: spyder/plugins/ipythonconsole.py:568
msgid "On %s mode, Autocall is not applied if there are no arguments after the callable. On %s mode, all callable objects are automatically called (even if no arguments are present)."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:526
+#: spyder/plugins/ipythonconsole.py:580
msgid "Symbolic Mathematics"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:527
+#: spyder/plugins/ipythonconsole.py:581
msgid "Perfom symbolic operations in the console (e.g. integrals, derivatives, vector calculus, etc) and get the outputs in a beautifully printed style (it requires the Sympy module)."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:532
+#: spyder/plugins/ipythonconsole.py:586
msgid "Use symbolic math"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:533
+#: spyder/plugins/ipythonconsole.py:587
msgid "This option loads the Sympy library to work with.
Please refer to its documentation to learn how to use it."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:543
+#: spyder/plugins/ipythonconsole.py:597
msgid "Prompts"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:544
+#: spyder/plugins/ipythonconsole.py:598
msgid "Modify how Input and Output prompts are shown in the console."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:547
+#: spyder/plugins/ipythonconsole.py:601
msgid "Input prompt:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:549
+#: spyder/plugins/ipythonconsole.py:603
msgid "Default is
In [<span class=\"in-prompt-number\">%i</span>]:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:553
+#: spyder/plugins/ipythonconsole.py:607
msgid "Output prompt:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:555
+#: spyder/plugins/ipythonconsole.py:609
msgid "Default is
Out[<span class=\"out-prompt-number\">%i</span>]:"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:575
+#: spyder/plugins/ipythonconsole.py:629
msgid "Graphics"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:577
+#: spyder/plugins/ipythonconsole.py:631
msgid "Startup"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:604
+#: spyder/plugins/ipythonconsole.py:658
msgid "The directory {} is not writable and it is required to create IPython consoles. Please make it writable."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:784
+#: spyder/plugins/ipythonconsole.py:831
msgid "Open an &IPython console"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:791
+#: spyder/plugins/ipythonconsole.py:838
msgid "Restart kernel"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:800
+#: spyder/plugins/ipythonconsole.py:847
msgid "Open a new IPython console connected to an existing kernel"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:803
+#: spyder/plugins/ipythonconsole.py:850
msgid "Rename tab"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:928
+#: spyder/plugins/ipythonconsole.py:968
+msgid ""
+"
Please exit from debugging before trying to run a file in this console.\n"
+"
"
+msgstr ""
+
+#: spyder/plugins/ipythonconsole.py:988
msgid "No IPython console is currently available to run %s.
Please open a new one and try again."
msgstr ""
-#: spyder/plugins/ipythonconsole.py:1023
-msgid "Your Python environment or installation doesn't have the ipykernel and cloudpickle modules installed on it. Without these modules is not possible for Spyder to create a console for you.
You can install them by running in a system terminal:
pip install ipykernel cloudpickle
or
conda install ipykernel cloudpickle"
+#: spyder/plugins/ipythonconsole.py:1096
+msgid "Your Python environment or installation doesn't have the spyder-kernels module or the right version of it installed. Without this module is not possible for Spyder to create a console for you.
You can install it by running in a system terminal:
conda install spyder-kernels=0.*
or
pip install spyder-kernels==0.*"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:1316
+#: spyder/plugins/ipythonconsole.py:1362
msgid "Do you want to close this console?"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:1322
+#: spyder/plugins/ipythonconsole.py:1368
msgid "Do you want to close all other consoles connected to the same kernel as this one?"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:1387
-msgid "It was not possible to restart the IPython console when switching to this project. The error was {0}"
+#: spyder/plugins/ipythonconsole.py:1440
+msgid "It was not possible to restart the IPython console when switching to this project. The error was
{0}"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:1488
-msgid "This error was most probably caused by installing Spyder in a directory with non-ascii characters (i.e. characters with tildes, apostrophes or non-latin symbols).
To fix it, please reinstall Spyder in a different location."
+#: spyder/plugins/ipythonconsole.py:1546 spyder/plugins/ipythonconsole.py:1556
+msgid "The error is:
{}"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:1694
+#: spyder/plugins/ipythonconsole.py:1742
msgid "IPython"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:1695
+#: spyder/plugins/ipythonconsole.py:1743
msgid "Unable to connect to %s"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:1765
+#: spyder/plugins/ipythonconsole.py:1819
msgid "Connection error"
msgstr ""
-#: spyder/plugins/ipythonconsole.py:1766
+#: spyder/plugins/ipythonconsole.py:1820
msgid ""
"Could not open ssh tunnel. The error was:\n"
"\n"
@@ -2422,82 +2484,86 @@ msgstr ""
msgid "Layout Display and Order"
msgstr ""
-#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:66
+#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:71
msgid "Python interpreter"
msgstr ""
-#: spyder/plugins/maininterpreter.py:68
+#: spyder/plugins/maininterpreter.py:73
msgid "Select the Python interpreter for all Spyder consoles"
msgstr ""
-#: spyder/plugins/maininterpreter.py:71
+#: spyder/plugins/maininterpreter.py:76
msgid "Default (i.e. the same as Spyder's)"
msgstr ""
-#: spyder/plugins/maininterpreter.py:74
+#: spyder/plugins/maininterpreter.py:79
msgid "Use the following Python interpreter:"
msgstr ""
-#: spyder/plugins/maininterpreter.py:77
+#: spyder/plugins/maininterpreter.py:82
msgid "Executables"
msgstr ""
-#: spyder/plugins/maininterpreter.py:94
+#: spyder/plugins/maininterpreter.py:92
+msgid "Recent custom interpreters"
+msgstr ""
+
+#: spyder/plugins/maininterpreter.py:107
msgid "User Module Reloader (UMR)"
msgstr ""
-#: spyder/plugins/maininterpreter.py:95
+#: spyder/plugins/maininterpreter.py:108
msgid "UMR forces Python to reload modules which were imported when executing a file in a Python or IPython console with the runfile function."
msgstr ""
-#: spyder/plugins/maininterpreter.py:100
+#: spyder/plugins/maininterpreter.py:113
msgid "Enable UMR"
msgstr ""
-#: spyder/plugins/maininterpreter.py:101
+#: spyder/plugins/maininterpreter.py:114
msgid "This option will enable the User Module Reloader (UMR) in Python/IPython consoles. UMR forces Python to reload deeply modules during import when running a Python script using the Spyder's builtin function runfile.
1. UMR may require to restart the console in which it will be called (otherwise only newly imported modules will be reloaded when executing files).
2. If errors occur when re-running a PyQt-based program, please check that the Qt objects are properly destroyed (e.g. you may have to use the attribute Qt.WA_DeleteOnClose on your main window, using the setAttribute method)"
msgstr ""
-#: spyder/plugins/maininterpreter.py:117
+#: spyder/plugins/maininterpreter.py:130
msgid "Show reloaded modules list"
msgstr ""
-#: spyder/plugins/maininterpreter.py:118
+#: spyder/plugins/maininterpreter.py:131
msgid "Please note that these changes will be applied only to new consoles"
msgstr ""
-#: spyder/plugins/maininterpreter.py:122
+#: spyder/plugins/maininterpreter.py:135
msgid "Set UMR excluded (not reloaded) modules"
msgstr ""
-#: spyder/plugins/maininterpreter.py:150
+#: spyder/plugins/maininterpreter.py:163
msgid "You selected an invalid Python interpreter for the console so the previous interpreter will stay. Please make sure to select a valid one."
msgstr ""
-#: spyder/plugins/maininterpreter.py:175
+#: spyder/plugins/maininterpreter.py:184
msgid "You selected a Python %d interpreter for the console but Spyder is running on Python %d!.
Although this is possible, we recommend you to install and run Spyder directly with your selected interpreter, to avoid seeing false warnings and errors due to the incompatible syntax between these two Python versions."
msgstr ""
-#: spyder/plugins/maininterpreter.py:186 spyder/plugins/maininterpreter.py:213
-#: spyder/plugins/maininterpreter.py:217
+#: spyder/plugins/maininterpreter.py:195 spyder/plugins/maininterpreter.py:222
+#: spyder/plugins/maininterpreter.py:226
msgid "UMR"
msgstr ""
-#: spyder/plugins/maininterpreter.py:187
+#: spyder/plugins/maininterpreter.py:196
msgid "Set the list of excluded modules as this: numpy, scipy"
msgstr ""
-#: spyder/plugins/maininterpreter.py:204
+#: spyder/plugins/maininterpreter.py:213
msgid "You are working with Python 2, this means that you can not import a module that contains non-ascii characters."
msgstr ""
-#: spyder/plugins/maininterpreter.py:214
+#: spyder/plugins/maininterpreter.py:223
msgid ""
"The following modules are not installed on your machine:\n"
"%s"
msgstr ""
-#: spyder/plugins/maininterpreter.py:218
+#: spyder/plugins/maininterpreter.py:227
msgid "Please note that these changes will be applied only to new Python/IPython consoles"
msgstr ""
@@ -2509,40 +2575,40 @@ msgstr ""
msgid "Outline"
msgstr ""
-#: spyder/plugins/projects.py:83 spyder/widgets/projects/explorer.py:112
+#: spyder/plugins/projects.py:77 spyder/widgets/projects/explorer.py:112
#: spyder/widgets/projects/explorer.py:126
msgid "Project explorer"
msgstr ""
-#: spyder/plugins/projects.py:95
+#: spyder/plugins/projects.py:89
msgid "New Project..."
msgstr ""
-#: spyder/plugins/projects.py:98
+#: spyder/plugins/projects.py:92
msgid "Open Project..."
msgstr ""
-#: spyder/plugins/projects.py:101
+#: spyder/plugins/projects.py:95
msgid "Close Project"
msgstr ""
-#: spyder/plugins/projects.py:104
+#: spyder/plugins/projects.py:98
msgid "Delete Project"
msgstr ""
-#: spyder/plugins/projects.py:110
+#: spyder/plugins/projects.py:104
msgid "Project Preferences"
msgstr ""
-#: spyder/plugins/projects.py:112
+#: spyder/plugins/projects.py:106
msgid "Recent Projects"
msgstr ""
-#: spyder/plugins/projects.py:249
+#: spyder/plugins/projects.py:264
msgid "Open project"
msgstr ""
-#: spyder/plugins/projects.py:255
+#: spyder/plugins/projects.py:270
msgid "%s is not a Spyder project!"
msgstr ""
@@ -2702,7 +2768,7 @@ msgid "Context"
msgstr ""
#: spyder/plugins/shortcuts.py:587
-#: spyder/widgets/variableexplorer/collectionseditor.py:128
+#: spyder/widgets/variableexplorer/collectionseditor.py:153
msgid "Name"
msgstr ""
@@ -2742,36 +2808,44 @@ msgstr ""
msgid "Do you want to reset to default values?"
msgstr ""
-#: spyder/plugins/variableexplorer.py:25
+#: spyder/plugins/variableexplorer.py:24
+msgid "View and edit DataFrames and Series in the Variable Explorer"
+msgstr ""
+
+#: spyder/plugins/variableexplorer.py:29
+msgid "View and edit two and three dimensional arrays in the Variable Explorer"
+msgstr ""
+
+#: spyder/plugins/variableexplorer.py:37
msgid "Filter"
msgstr ""
-#: spyder/plugins/variableexplorer.py:27
-#: spyder/widgets/variableexplorer/namespacebrowser.py:200
+#: spyder/plugins/variableexplorer.py:39
+#: spyder/widgets/variableexplorer/namespacebrowser.py:203
msgid "Exclude private references"
msgstr ""
-#: spyder/plugins/variableexplorer.py:28
-#: spyder/widgets/variableexplorer/namespacebrowser.py:215
+#: spyder/plugins/variableexplorer.py:40
+#: spyder/widgets/variableexplorer/namespacebrowser.py:218
msgid "Exclude capitalized references"
msgstr ""
-#: spyder/plugins/variableexplorer.py:29
-#: spyder/widgets/variableexplorer/namespacebrowser.py:208
+#: spyder/plugins/variableexplorer.py:41
+#: spyder/widgets/variableexplorer/namespacebrowser.py:211
msgid "Exclude all-uppercase references"
msgstr ""
-#: spyder/plugins/variableexplorer.py:30
-#: spyder/widgets/variableexplorer/namespacebrowser.py:223
+#: spyder/plugins/variableexplorer.py:42
+#: spyder/widgets/variableexplorer/namespacebrowser.py:226
msgid "Exclude unsupported data types"
msgstr ""
-#: spyder/plugins/variableexplorer.py:36
-#: spyder/widgets/variableexplorer/collectionseditor.py:702
+#: spyder/plugins/variableexplorer.py:48
+#: spyder/widgets/variableexplorer/collectionseditor.py:738
msgid "Show arrays min/max"
msgstr ""
-#: spyder/plugins/variableexplorer.py:178
+#: spyder/plugins/variableexplorer.py:202
msgid "Variable explorer"
msgstr ""
@@ -2803,12 +2877,12 @@ msgstr ""
msgid "Back"
msgstr ""
-#: spyder/plugins/workingdirectory.py:132 spyder/widgets/explorer.py:1194
+#: spyder/plugins/workingdirectory.py:130 spyder/widgets/explorer.py:1199
#: spyder/widgets/variableexplorer/importwizard.py:539
msgid "Next"
msgstr ""
-#: spyder/plugins/workingdirectory.py:143
+#: spyder/plugins/workingdirectory.py:141
msgid ""
"This is the working directory for newly\n"
"opened consoles (Python/IPython consoles and\n"
@@ -2817,39 +2891,43 @@ msgid ""
"created in the editor"
msgstr ""
-#: spyder/plugins/workingdirectory.py:168
+#: spyder/plugins/workingdirectory.py:166
msgid "Browse a working directory"
msgstr ""
-#: spyder/plugins/workingdirectory.py:175
+#: spyder/plugins/workingdirectory.py:173
msgid "Change to parent directory"
msgstr ""
-#: spyder/plugins/workingdirectory.py:182 spyder/widgets/findinfiles.py:225
+#: spyder/plugins/workingdirectory.py:180 spyder/widgets/findinfiles.py:240
msgid "Current working directory"
msgstr ""
-#: spyder/utils/codeanalysis.py:92
+#: spyder/utils/codeanalysis.py:94
msgid "Real-time code analysis on the Editor"
msgstr ""
-#: spyder/utils/codeanalysis.py:96
+#: spyder/utils/codeanalysis.py:98
msgid "Real-time code style analysis on the Editor"
msgstr ""
-#: spyder/utils/environ.py:46
+#: spyder/utils/environ.py:48
msgid "Environment variables"
msgstr ""
-#: spyder/utils/environ.py:96
+#: spyder/utils/environ.py:57
+msgid "An error occurred while trying to show your environment variables. The error was
{0}"
+msgstr ""
+
+#: spyder/utils/environ.py:108
msgid "Module pywin32 was not found.
Please restart this Windows session (not the computer) for changes to take effect."
msgstr ""
-#: spyder/utils/environ.py:109
+#: spyder/utils/environ.py:121
msgid "If you accept changes, this will modify the current user environment variables directly in Windows registry. Use it with precautions, at your own risks.
Note that for changes to take effect, you will need to restart the parent process of this application (simply restart Spyder if you have executed it from a Windows shortcut, otherwise restart any application from which you may have executed it, like Python(x,y) Home for example)"
msgstr ""
-#: spyder/utils/help/sphinxify.py:217 spyder/utils/help/sphinxify.py:227
+#: spyder/utils/help/sphinxify.py:216 spyder/utils/help/sphinxify.py:226
msgid "It was not possible to generate rich text help for this object.Please see it in plain text."
msgstr ""
@@ -2858,133 +2936,76 @@ msgstr ""
msgid "Editor's code completion, go-to-definition and help"
msgstr ""
-#: spyder/utils/iofuncs.py:408
-msgid "Supported files"
-msgstr ""
-
-#: spyder/utils/iofuncs.py:410
-msgid "All files (*.*)"
-msgstr ""
-
-#: spyder/utils/iofuncs.py:420
-msgid "Spyder data files"
-msgstr ""
-
-#: spyder/utils/iofuncs.py:422
-#: spyder/widgets/variableexplorer/collectionseditor.py:1061
-msgid "NumPy arrays"
-msgstr ""
-
-#: spyder/utils/iofuncs.py:423
-msgid "NumPy zip arrays"
-msgstr ""
-
-#: spyder/utils/iofuncs.py:424
-msgid "Matlab files"
-msgstr ""
-
-#: spyder/utils/iofuncs.py:425
-msgid "CSV text files"
-msgstr ""
-
-#: spyder/utils/iofuncs.py:427
-msgid "JPEG images"
-msgstr ""
-
-#: spyder/utils/iofuncs.py:428
-msgid "PNG images"
-msgstr ""
-
-#: spyder/utils/iofuncs.py:429
-msgid "GIF images"
-msgstr ""
-
-#: spyder/utils/iofuncs.py:430
-msgid "TIFF images"
-msgstr ""
-
-#: spyder/utils/iofuncs.py:431 spyder/utils/iofuncs.py:432
-msgid "Pickle files"
-msgstr ""
-
-#: spyder/utils/iofuncs.py:433
-msgid "JSON files"
-msgstr ""
-
-#: spyder/utils/iofuncs.py:452 spyder/utils/iofuncs.py:459
-msgid "Unsupported file type '%s'"
-msgstr ""
-
-#: spyder/utils/programs.py:287
+#: spyder/utils/programs.py:308
msgid "It was not possible to run this file in an external terminal"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:34
+#: spyder/utils/syntaxhighlighters.py:35
msgid "Syntax highlighting for Matlab, Julia and other file types"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:43
+#: spyder/utils/syntaxhighlighters.py:44
msgid "Background:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:44
+#: spyder/utils/syntaxhighlighters.py:45
#: spyder/widgets/sourcecode/codeeditor.py:107
msgid "Current line:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:45
+#: spyder/utils/syntaxhighlighters.py:46
msgid "Current cell:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:46
+#: spyder/utils/syntaxhighlighters.py:47
msgid "Occurrence:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:47
+#: spyder/utils/syntaxhighlighters.py:48
msgid "Link:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:48
+#: spyder/utils/syntaxhighlighters.py:49
msgid "Side areas:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:49
+#: spyder/utils/syntaxhighlighters.py:50
msgid "Matched
parens:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:50
+#: spyder/utils/syntaxhighlighters.py:51
msgid "Unmatched
parens:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:51
+#: spyder/utils/syntaxhighlighters.py:52
msgid "Normal text:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:52
+#: spyder/utils/syntaxhighlighters.py:53
msgid "Keyword:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:53
+#: spyder/utils/syntaxhighlighters.py:54
msgid "Builtin:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:54
+#: spyder/utils/syntaxhighlighters.py:55
msgid "Definition:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:55
+#: spyder/utils/syntaxhighlighters.py:56
msgid "Comment:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:56
+#: spyder/utils/syntaxhighlighters.py:57
msgid "String:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:57
+#: spyder/utils/syntaxhighlighters.py:58
msgid "Number:"
msgstr ""
-#: spyder/utils/syntaxhighlighters.py:58
+#: spyder/utils/syntaxhighlighters.py:59
msgid "Instance:"
msgstr ""
@@ -3020,39 +3041,39 @@ msgstr ""
msgid "Array dimensions not valid"
msgstr ""
-#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2731
+#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2738
msgid "Zoom out"
msgstr ""
-#: spyder/widgets/browser.py:61 spyder/widgets/sourcecode/codeeditor.py:2727
+#: spyder/widgets/browser.py:61 spyder/widgets/sourcecode/codeeditor.py:2734
msgid "Zoom in"
msgstr ""
-#: spyder/widgets/browser.py:213
+#: spyder/widgets/browser.py:216
msgid "Home"
msgstr ""
-#: spyder/widgets/browser.py:249
+#: spyder/widgets/browser.py:252
msgid "Find text"
msgstr ""
-#: spyder/widgets/browser.py:266
+#: spyder/widgets/browser.py:269
msgid "Address:"
msgstr ""
-#: spyder/widgets/browser.py:302
+#: spyder/widgets/browser.py:305
msgid "Unable to load page"
msgstr ""
-#: spyder/widgets/comboboxes.py:164
+#: spyder/widgets/comboboxes.py:165
msgid "Press enter to validate this entry"
msgstr ""
-#: spyder/widgets/comboboxes.py:165
+#: spyder/widgets/comboboxes.py:166
msgid "This entry is incorrect"
msgstr ""
-#: spyder/widgets/comboboxes.py:208
+#: spyder/widgets/comboboxes.py:209
msgid "Press enter to validate this path"
msgstr ""
@@ -3084,100 +3105,101 @@ msgstr ""
msgid "Copy to clipboard"
msgstr ""
-#: spyder/widgets/editor.py:501
+#: spyder/widgets/editor.py:511
msgid "Find symbols in file..."
msgstr ""
-#: spyder/widgets/editor.py:504
+#: spyder/widgets/editor.py:514
msgid "Copy path to clipboard"
msgstr ""
-#: spyder/widgets/editor.py:508
+#: spyder/widgets/editor.py:518
msgid "Close all to the right"
msgstr ""
-#: spyder/widgets/editor.py:510
+#: spyder/widgets/editor.py:520
msgid "Close all but this"
msgstr ""
-#: spyder/widgets/editor.py:514 spyder/widgets/explorer.py:370
+#: spyder/widgets/editor.py:524 spyder/widgets/explorer.py:373
msgid "Show in Finder"
msgstr ""
-#: spyder/widgets/editor.py:516 spyder/widgets/explorer.py:372
+#: spyder/widgets/editor.py:526 spyder/widgets/explorer.py:375
msgid "Show in external file explorer"
msgstr ""
-#: spyder/widgets/editor.py:1193
+#: spyder/widgets/editor.py:1201
msgid "Temporary file"
msgstr ""
-#: spyder/widgets/editor.py:1279
+#: spyder/widgets/editor.py:1287
msgid "New window"
msgstr ""
-#: spyder/widgets/editor.py:1280
+#: spyder/widgets/editor.py:1288
msgid "Create a new editor window"
msgstr ""
-#: spyder/widgets/editor.py:1283
+#: spyder/widgets/editor.py:1291
msgid "Split vertically"
msgstr ""
-#: spyder/widgets/editor.py:1285
+#: spyder/widgets/editor.py:1293
msgid "Split vertically this editor window"
msgstr ""
-#: spyder/widgets/editor.py:1287
+#: spyder/widgets/editor.py:1295
msgid "Split horizontally"
msgstr ""
-#: spyder/widgets/editor.py:1289
+#: spyder/widgets/editor.py:1297
msgid "Split horizontally this editor window"
msgstr ""
-#: spyder/widgets/editor.py:1291
+#: spyder/widgets/editor.py:1299
msgid "Close this panel"
msgstr ""
-#: spyder/widgets/editor.py:1531
+#: spyder/widgets/editor.py:1534
msgid "%s has been modified.
Do you want to save changes?"
msgstr ""
-#: spyder/widgets/editor.py:1617 spyder/widgets/editor.py:1780
-msgid "Save"
+#: spyder/widgets/editor.py:1620 spyder/widgets/editor.py:1783
+#: spyder/widgets/explorer.py:82
+msgid "Save Error"
msgstr ""
-#: spyder/widgets/editor.py:1618 spyder/widgets/editor.py:1781
-#: spyder/widgets/shell.py:267
+#: spyder/widgets/editor.py:1621 spyder/widgets/editor.py:1784
+#: spyder/widgets/explorer.py:83
msgid "Unable to save file '%s'
Error message:
%s"
msgstr ""
-#: spyder/widgets/editor.py:1968
+#: spyder/widgets/editor.py:1971
msgid "%s is unavailable (this file may have been removed, moved or renamed outside Spyder).
Do you want to close it?"
msgstr ""
-#: spyder/widgets/editor.py:1991
+#: spyder/widgets/editor.py:1994
msgid "%s has been modified outside Spyder.
Do you want to reload it and lose all your changes?"
msgstr ""
-#: spyder/widgets/editor.py:2101
+#: spyder/widgets/editor.py:2104
msgid "All changes to %s will be lost.
Do you want to revert file from disk?"
msgstr ""
-#: spyder/widgets/editor.py:2245
+#: spyder/widgets/editor.py:2250
msgid "Loading %s..."
msgstr ""
-#: spyder/widgets/editor.py:2257
+#: spyder/widgets/editor.py:2262
msgid "%s contains mixed end-of-line characters.
Spyder will fix this automatically."
msgstr ""
-#: spyder/widgets/editor.py:2664
+#: spyder/widgets/editor.py:2672
msgid "Close window"
msgstr ""
-#: spyder/widgets/editor.py:2666
+#: spyder/widgets/editor.py:2674
msgid "Close this window"
msgstr ""
@@ -3209,7 +3231,7 @@ msgstr ""
msgid "Show absolute path"
msgstr ""
-#: spyder/widgets/editortools.py:207 spyder/widgets/explorer.py:283
+#: spyder/widgets/editortools.py:207 spyder/widgets/explorer.py:286
msgid "Show all files"
msgstr ""
@@ -3221,202 +3243,198 @@ msgstr ""
msgid "Show/hide outline explorer"
msgstr ""
-#: spyder/widgets/explorer.py:279
+#: spyder/widgets/explorer.py:282
msgid "Edit filename filters..."
msgstr ""
-#: spyder/widgets/explorer.py:293
+#: spyder/widgets/explorer.py:296
msgid "Edit filename filters"
msgstr ""
-#: spyder/widgets/explorer.py:294
+#: spyder/widgets/explorer.py:297
msgid "Name filters:"
msgstr ""
-#: spyder/widgets/explorer.py:313
+#: spyder/widgets/explorer.py:316
msgid "File..."
msgstr ""
-#: spyder/widgets/explorer.py:317
+#: spyder/widgets/explorer.py:320
msgid "Module..."
msgstr ""
-#: spyder/widgets/explorer.py:321
+#: spyder/widgets/explorer.py:324
msgid "Folder..."
msgstr ""
-#: spyder/widgets/explorer.py:325
+#: spyder/widgets/explorer.py:328
msgid "Package..."
msgstr ""
-#: spyder/widgets/explorer.py:346
-#: spyder/widgets/variableexplorer/collectionseditor.py:677
+#: spyder/widgets/explorer.py:349
+#: spyder/widgets/variableexplorer/collectionseditor.py:713
msgid "Edit"
msgstr ""
-#: spyder/widgets/explorer.py:348
+#: spyder/widgets/explorer.py:351
msgid "Move..."
msgstr ""
-#: spyder/widgets/explorer.py:351
+#: spyder/widgets/explorer.py:354
msgid "Delete..."
msgstr ""
-#: spyder/widgets/explorer.py:354
+#: spyder/widgets/explorer.py:357
msgid "Rename..."
msgstr ""
-#: spyder/widgets/explorer.py:357
+#: spyder/widgets/explorer.py:360
msgid "Open"
msgstr ""
-#: spyder/widgets/explorer.py:358 spyder/widgets/sourcecode/codeeditor.py:2699
+#: spyder/widgets/explorer.py:361 spyder/widgets/sourcecode/codeeditor.py:2706
msgid "Convert to Python script"
msgstr ""
-#: spyder/widgets/explorer.py:399
+#: spyder/widgets/explorer.py:393
msgid "Commit"
msgstr ""
-#: spyder/widgets/explorer.py:402
+#: spyder/widgets/explorer.py:396
msgid "Browse repository"
msgstr ""
-#: spyder/widgets/explorer.py:413
+#: spyder/widgets/explorer.py:407
msgid "Open command prompt here"
msgstr ""
-#: spyder/widgets/explorer.py:415
+#: spyder/widgets/explorer.py:409
msgid "Open terminal here"
msgstr ""
-#: spyder/widgets/explorer.py:416
+#: spyder/widgets/explorer.py:410
msgid "Open IPython console here"
msgstr ""
-#: spyder/widgets/explorer.py:430
+#: spyder/widgets/explorer.py:424
msgid "New"
msgstr ""
-#: spyder/widgets/explorer.py:438
+#: spyder/widgets/explorer.py:432
msgid "Import"
msgstr ""
-#: spyder/widgets/explorer.py:584
+#: spyder/widgets/explorer.py:583
msgid "Do you really want to delete %s?"
msgstr ""
-#: spyder/widgets/explorer.py:602
+#: spyder/widgets/explorer.py:601
msgid "delete"
msgstr ""
-#: spyder/widgets/explorer.py:603 spyder/widgets/projects/explorer.py:148
+#: spyder/widgets/explorer.py:602 spyder/widgets/projects/explorer.py:148
#: spyder/widgets/projects/explorer.py:256
msgid "Project Explorer"
msgstr ""
-#: spyder/widgets/explorer.py:604 spyder/widgets/projects/explorer.py:149
+#: spyder/widgets/explorer.py:603 spyder/widgets/projects/explorer.py:149
msgid "Unable to %s %s
Error message:
%s"
msgstr ""
-#: spyder/widgets/explorer.py:619
+#: spyder/widgets/explorer.py:618
msgid "File Explorer"
msgstr ""
-#: spyder/widgets/explorer.py:620
+#: spyder/widgets/explorer.py:619
msgid "The current directory contains a project.
If you want to delete the project, please go to Projects » Delete Project"
msgstr ""
-#: spyder/widgets/explorer.py:637 spyder/widgets/sourcecode/codeeditor.py:2160
+#: spyder/widgets/explorer.py:636 spyder/widgets/sourcecode/codeeditor.py:2167
msgid "Conversion error"
msgstr ""
-#: spyder/widgets/explorer.py:638 spyder/widgets/sourcecode/codeeditor.py:2161
+#: spyder/widgets/explorer.py:637 spyder/widgets/sourcecode/codeeditor.py:2168
msgid ""
"It was not possible to convert this notebook. The error is:\n"
"\n"
msgstr ""
-#: spyder/widgets/explorer.py:655 spyder/widgets/explorer.py:663
-#: spyder/widgets/explorer.py:674
-#: spyder/widgets/variableexplorer/collectionseditor.py:706
-#: spyder/widgets/variableexplorer/collectionseditor.py:952
+#: spyder/widgets/explorer.py:654 spyder/widgets/explorer.py:662
+#: spyder/widgets/explorer.py:676
+#: spyder/widgets/variableexplorer/collectionseditor.py:742
+#: spyder/widgets/variableexplorer/collectionseditor.py:988
msgid "Rename"
msgstr ""
-#: spyder/widgets/explorer.py:656
+#: spyder/widgets/explorer.py:655
msgid "New name:"
msgstr ""
-#: spyder/widgets/explorer.py:664
+#: spyder/widgets/explorer.py:663
msgid "Do you really want to rename %s and overwrite the existing file %s?"
msgstr ""
-#: spyder/widgets/explorer.py:675
+#: spyder/widgets/explorer.py:677
msgid "Unable to rename file %s
Error message:
%s"
msgstr ""
-#: spyder/widgets/explorer.py:722
+#: spyder/widgets/explorer.py:724
msgid "Unable to move %s
Error message:
%s"
msgstr ""
-#: spyder/widgets/explorer.py:740
+#: spyder/widgets/explorer.py:742
msgid "Unable to create folder %s
Error message:
%s"
msgstr ""
-#: spyder/widgets/explorer.py:753 spyder/widgets/explorer.py:787
+#: spyder/widgets/explorer.py:755 spyder/widgets/explorer.py:789
msgid "Unable to create file %s
Error message:
%s"
msgstr ""
-#: spyder/widgets/explorer.py:761
+#: spyder/widgets/explorer.py:763
msgid "New folder"
msgstr ""
-#: spyder/widgets/explorer.py:762
+#: spyder/widgets/explorer.py:764
msgid "Folder name:"
msgstr ""
-#: spyder/widgets/explorer.py:767
+#: spyder/widgets/explorer.py:769
msgid "New package"
msgstr ""
-#: spyder/widgets/explorer.py:768
+#: spyder/widgets/explorer.py:770
msgid "Package name:"
msgstr ""
-#: spyder/widgets/explorer.py:808
+#: spyder/widgets/explorer.py:810
msgid "New module"
msgstr ""
-#: spyder/widgets/explorer.py:823
+#: spyder/widgets/explorer.py:825
msgid "For %s support, please install one of the
following tools:
%s"
msgstr ""
-#: spyder/widgets/explorer.py:827
+#: spyder/widgets/explorer.py:829
msgid "Unable to find external program.
%s"
msgstr ""
-#: spyder/widgets/explorer.py:1048
+#: spyder/widgets/explorer.py:1049
msgid "Show current directory only"
msgstr ""
-#: spyder/widgets/explorer.py:1158
+#: spyder/widgets/explorer.py:1163
msgid "You don't have the right permissions to open this directory"
msgstr ""
-#: spyder/widgets/explorer.py:1189
+#: spyder/widgets/explorer.py:1194
msgid "Show icons and text"
msgstr ""
-#: spyder/widgets/explorer.py:1191
+#: spyder/widgets/explorer.py:1196
#: spyder/widgets/variableexplorer/importwizard.py:535
msgid "Previous"
msgstr ""
-#: spyder/widgets/explorer.py:1197
-msgid "Parent"
-msgstr ""
-
#: spyder/widgets/fileswitcher.py:110
msgid "unsaved file"
msgstr ""
@@ -3429,321 +3447,430 @@ msgstr ""
msgid "lines"
msgstr ""
-#: spyder/widgets/findinfiles.py:124
+#: spyder/widgets/findinfiles.py:121
msgid "Unexpected error: see internal console"
msgstr ""
-#: spyder/widgets/findinfiles.py:152
+#: spyder/widgets/findinfiles.py:158
msgid "invalid regular expression"
msgstr ""
-#: spyder/widgets/findinfiles.py:202
+#: spyder/widgets/findinfiles.py:217
msgid "permission denied errors were encountered"
msgstr ""
-#: spyder/widgets/findinfiles.py:217
+#: spyder/widgets/findinfiles.py:232
msgid "Search directory"
msgstr ""
-#: spyder/widgets/findinfiles.py:230
+#: spyder/widgets/findinfiles.py:245
msgid "Project"
msgstr ""
-#: spyder/widgets/findinfiles.py:231
+#: spyder/widgets/findinfiles.py:246
msgid "Search in all files and directories present on the current project path (if opened)"
msgstr ""
-#: spyder/widgets/findinfiles.py:236
+#: spyder/widgets/findinfiles.py:251
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
msgid "File"
msgstr ""
-#: spyder/widgets/findinfiles.py:237
+#: spyder/widgets/findinfiles.py:252
msgid "Search in current opened file"
msgstr ""
-#: spyder/widgets/findinfiles.py:242
+#: spyder/widgets/findinfiles.py:257
msgid "Select other directory"
msgstr ""
-#: spyder/widgets/findinfiles.py:243
+#: spyder/widgets/findinfiles.py:258
msgid "Search in other folder present on the file system"
msgstr ""
-#: spyder/widgets/findinfiles.py:247
+#: spyder/widgets/findinfiles.py:262
msgid "Clear the list of other directories"
msgstr ""
-#: spyder/widgets/findinfiles.py:318
+#: spyder/widgets/findinfiles.py:333
msgid "Clear other directories"
msgstr ""
-#: spyder/widgets/findinfiles.py:319
+#: spyder/widgets/findinfiles.py:334
msgid "Do you want to clear the list of other directories?"
msgstr ""
-#: spyder/widgets/findinfiles.py:415
+#: spyder/widgets/findinfiles.py:404 spyder/widgets/findreplace.py:52
+msgid "Regular expression error"
+msgstr ""
+
+#: spyder/widgets/findinfiles.py:427
msgid "Search pattern"
msgstr ""
-#: spyder/widgets/findinfiles.py:418 spyder/widgets/findinfiles.py:458
-#: spyder/widgets/findreplace.py:99
+#: spyder/widgets/findinfiles.py:430 spyder/widgets/findinfiles.py:470
+#: spyder/widgets/findreplace.py:100
msgid "Regular expression"
msgstr ""
-#: spyder/widgets/findinfiles.py:421 spyder/widgets/findreplace.py:105
+#: spyder/widgets/findinfiles.py:433 spyder/widgets/findreplace.py:106
msgid "Case Sensitive"
msgstr ""
-#: spyder/widgets/findinfiles.py:432
+#: spyder/widgets/findinfiles.py:444
msgid "Search"
msgstr ""
-#: spyder/widgets/findinfiles.py:435
+#: spyder/widgets/findinfiles.py:447
msgid "Start search"
msgstr ""
-#: spyder/widgets/findinfiles.py:442
+#: spyder/widgets/findinfiles.py:454
msgid "Stop search"
msgstr ""
-#: spyder/widgets/findinfiles.py:452
-msgid "Excluded filenames pattern"
+#: spyder/widgets/findinfiles.py:464
+msgid "Exclude pattern"
msgstr ""
-#: spyder/widgets/findinfiles.py:461
+#: spyder/widgets/findinfiles.py:473
msgid "Exclude:"
msgstr ""
-#: spyder/widgets/findinfiles.py:470
+#: spyder/widgets/findinfiles.py:482
msgid "Search in:"
msgstr ""
-#: spyder/widgets/findinfiles.py:499
+#: spyder/widgets/findinfiles.py:511
msgid "Hide advanced options"
msgstr ""
-#: spyder/widgets/findinfiles.py:502
+#: spyder/widgets/findinfiles.py:514
msgid "Show advanced options"
msgstr ""
-#: spyder/widgets/findinfiles.py:759 spyder/widgets/findinfiles.py:843
+#: spyder/widgets/findinfiles.py:790 spyder/widgets/findinfiles.py:877
msgid "String not found"
msgstr ""
-#: spyder/widgets/findinfiles.py:845
+#: spyder/widgets/findinfiles.py:879
msgid "matches in"
msgstr ""
-#: spyder/widgets/findinfiles.py:846
+#: spyder/widgets/findinfiles.py:880
msgid "file"
msgstr ""
-#: spyder/widgets/findinfiles.py:878
+#: spyder/widgets/findinfiles.py:912
msgid " Scanning: {0}"
msgstr ""
-#: spyder/widgets/findinfiles.py:880
+#: spyder/widgets/findinfiles.py:914
msgid " Searching for files in folder: {0}"
msgstr ""
-#: spyder/widgets/findinfiles.py:884
+#: spyder/widgets/findinfiles.py:918
msgid " Searching for files..."
msgstr ""
-#: spyder/widgets/findreplace.py:48
+#: spyder/widgets/findreplace.py:49
msgid "No matches"
msgstr ""
-#: spyder/widgets/findreplace.py:49 spyder/widgets/findreplace.py:50
-#: spyder/widgets/findreplace.py:72
+#: spyder/widgets/findreplace.py:50 spyder/widgets/findreplace.py:51
+#: spyder/widgets/findreplace.py:73
msgid "Search string"
msgstr ""
-#: spyder/widgets/findreplace.py:51
-msgid "Regular expression error"
-msgstr ""
-
-#: spyder/widgets/findreplace.py:111
+#: spyder/widgets/findreplace.py:112
msgid "Whole words"
msgstr ""
-#: spyder/widgets/findreplace.py:117
+#: spyder/widgets/findreplace.py:118
msgid "Highlight matches"
msgstr ""
-#: spyder/widgets/findreplace.py:131
+#: spyder/widgets/findreplace.py:132
msgid "Replace with:"
msgstr ""
-#: spyder/widgets/findreplace.py:133
+#: spyder/widgets/findreplace.py:134
msgid "Replace string"
msgstr ""
-#: spyder/widgets/findreplace.py:137
+#: spyder/widgets/findreplace.py:138
msgid "Replace/find next"
msgstr ""
-#: spyder/widgets/findreplace.py:142
+#: spyder/widgets/findreplace.py:143
msgid "Replace selection"
msgstr ""
-#: spyder/widgets/findreplace.py:150
+#: spyder/widgets/findreplace.py:151
msgid "Replace all"
msgstr ""
-#: spyder/widgets/findreplace.py:577
+#: spyder/widgets/findreplace.py:583
msgid "of"
msgstr ""
-#: spyder/widgets/findreplace.py:581
+#: spyder/widgets/findreplace.py:587
msgid "matches"
msgstr ""
-#: spyder/widgets/findreplace.py:584
+#: spyder/widgets/findreplace.py:590
msgid "no matches"
msgstr ""
-#: spyder/widgets/internalshell.py:262
+#: spyder/widgets/github/backend.py:151
+msgid "Invalid credentials"
+msgstr ""
+
+#: spyder/widgets/github/backend.py:152
+msgid "Failed to create Github issue, invalid credentials..."
+msgstr ""
+
+#: spyder/widgets/github/backend.py:159
+msgid "Failed to create issue"
+msgstr ""
+
+#: spyder/widgets/github/backend.py:160
+msgid "Failed to create Github issue. Error %d"
+msgstr ""
+
+#: spyder/widgets/github/backend.py:167
+msgid "Issue created on Github"
+msgstr ""
+
+#: spyder/widgets/github/backend.py:168
+msgid "Issue successfully created. Would you like to open the issue in your web browser?"
+msgstr ""
+
+#: spyder/widgets/github/backend.py:195
+msgid "Failed to store password"
+msgstr ""
+
+#: spyder/widgets/github/backend.py:196
+msgid "It was not possible to securely save your password. You will be prompted for your Github credentials next time you want to report an issue."
+msgstr ""
+
+#: spyder/widgets/github/backend.py:212
+msgid "Failed to store token"
+msgstr ""
+
+#: spyder/widgets/github/backend.py:213
+msgid "It was not possible to securely save your token. You will be prompted for your Github token next time you want to report an issue."
+msgstr ""
+
+#: spyder/widgets/github/backend.py:237
+msgid "Failed to retrieve password"
+msgstr ""
+
+#: spyder/widgets/github/backend.py:238
+msgid "It was not possible to retrieve your password. Please introduce it again."
+msgstr ""
+
+#: spyder/widgets/github/backend.py:249
+msgid "Failed to retrieve token"
+msgstr ""
+
+#: spyder/widgets/github/backend.py:250
+msgid "It was not possible to retrieve your token. Please introduce it again."
+msgstr ""
+
+#: spyder/widgets/github/gh_login.py:38
+msgid "Sign in to Github"
+msgstr ""
+
+#: spyder/widgets/github/gh_login.py:57
+msgid "For regular users, i.e. users without two-factor authentication enabled"
+msgstr ""
+
+#: spyder/widgets/github/gh_login.py:62
+msgid "Username:"
+msgstr ""
+
+#: spyder/widgets/github/gh_login.py:69
+msgid "Password: "
+msgstr ""
+
+#: spyder/widgets/github/gh_login.py:81
+msgid "Remember me"
+msgstr ""
+
+#: spyder/widgets/github/gh_login.py:82
+msgid "Spyder will save your credentials safely"
+msgstr ""
+
+#: spyder/widgets/github/gh_login.py:99
+msgid "Password Only"
+msgstr ""
+
+#: spyder/widgets/github/gh_login.py:105
+msgid "For users with two-factor authentication enabled, or who prefer a per-app token authentication.
You can go here and click \"Generate token\" at the bottom to create a new token to use for this, with the appropriate permissions."
+msgstr ""
+
+#: spyder/widgets/github/gh_login.py:127
+msgid "Remember token"
+msgstr ""
+
+#: spyder/widgets/github/gh_login.py:128
+msgid "Spyder will save your token safely"
+msgstr ""
+
+#: spyder/widgets/github/gh_login.py:145
+msgid "Access Token"
+msgstr ""
+
+#: spyder/widgets/github/gh_login.py:148
+msgid "Sign in"
+msgstr ""
+
+#: spyder/widgets/internalshell.py:263
msgid "Help..."
msgstr ""
-#: spyder/widgets/internalshell.py:279
+#: spyder/widgets/internalshell.py:280
msgid "Shell special commands:"
msgstr ""
-#: spyder/widgets/internalshell.py:280
+#: spyder/widgets/internalshell.py:281
msgid "Internal editor:"
msgstr ""
-#: spyder/widgets/internalshell.py:281
+#: spyder/widgets/internalshell.py:282
msgid "External editor:"
msgstr ""
-#: spyder/widgets/internalshell.py:282
+#: spyder/widgets/internalshell.py:283
msgid "Run script:"
msgstr ""
-#: spyder/widgets/internalshell.py:283
+#: spyder/widgets/internalshell.py:284
msgid "Remove references:"
msgstr ""
-#: spyder/widgets/internalshell.py:284
+#: spyder/widgets/internalshell.py:285
msgid "System commands:"
msgstr ""
-#: spyder/widgets/internalshell.py:285
+#: spyder/widgets/internalshell.py:286
msgid "Python help:"
msgstr ""
-#: spyder/widgets/internalshell.py:286
+#: spyder/widgets/internalshell.py:287
msgid "GUI-based editor:"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:272
+#: spyder/widgets/internalshell.py:418
+msgid "In order to use commands like \"raw_input\" or \"input\" run Spyder with the multithread option (--multithread) from a system terminal"
+msgstr ""
+
+#: spyder/widgets/ipythonconsole/client.py:308
msgid "An error ocurred while starting the kernel"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:313
-#: spyder/widgets/ipythonconsole/client.py:369
-#: spyder/widgets/ipythonconsole/client.py:402
-#: spyder/widgets/ipythonconsole/shell.py:233
-#: spyder/widgets/variableexplorer/namespacebrowser.py:193
+#: spyder/widgets/ipythonconsole/client.py:352
+#: spyder/widgets/ipythonconsole/client.py:408
+#: spyder/widgets/ipythonconsole/client.py:441
+#: spyder/widgets/ipythonconsole/shell.py:234
+#: spyder/widgets/variableexplorer/namespacebrowser.py:196
msgid "Remove all variables"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:322
+#: spyder/widgets/ipythonconsole/client.py:361
msgid "Show environment variables"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:329
+#: spyder/widgets/ipythonconsole/client.py:368
msgid "Show sys.path contents"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:356
+#: spyder/widgets/ipythonconsole/client.py:395
msgid "Stop the current command"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:367
-#: spyder/widgets/variableexplorer/collectionseditor.py:699
-#: spyder/widgets/variableexplorer/collectionseditor.py:934
+#: spyder/widgets/ipythonconsole/client.py:406
+#: spyder/widgets/variableexplorer/collectionseditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:970
msgid "Remove"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:390
+#: spyder/widgets/ipythonconsole/client.py:429
msgid "Inspect current object"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:396
+#: spyder/widgets/ipythonconsole/client.py:435
msgid "Clear line or block"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:409
+#: spyder/widgets/ipythonconsole/client.py:448
msgid "Clear console"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:462
+#: spyder/widgets/ipythonconsole/client.py:507
msgid "Are you sure you want to restart the kernel?"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:464
+#: spyder/widgets/ipythonconsole/client.py:509
msgid "Restart kernel?"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:476
+#: spyder/widgets/ipythonconsole/client.py:526
msgid ""
"Error restarting kernel: %s\n"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:484
+#: spyder/widgets/ipythonconsole/client.py:534
msgid ""
"
Restarting kernel...\n"
"
"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:488
+#: spyder/widgets/ipythonconsole/client.py:538
msgid ""
"Cannot restart a kernel not started by Spyder\n"
msgstr ""
-#: spyder/widgets/ipythonconsole/client.py:597
+#: spyder/widgets/ipythonconsole/client.py:649
msgid "Connecting to kernel..."
msgstr ""
-#: spyder/widgets/ipythonconsole/help.py:128 spyder/widgets/mixins.py:712
+#: spyder/widgets/ipythonconsole/help.py:128 spyder/widgets/mixins.py:726
msgid "Arguments"
msgstr ""
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:129
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:138
msgid "Loading this kind of data while debugging is not supported."
msgstr ""
-#: spyder/widgets/ipythonconsole/namespacebrowser.py:148
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:157
msgid "Saving data while debugging is not supported."
msgstr ""
-#: spyder/widgets/ipythonconsole/shell.py:234
+#: spyder/widgets/ipythonconsole/shell.py:235
msgid "All user-defined variables will be removed. Are you sure you want to proceed?"
msgstr ""
-#: spyder/widgets/ipythonconsole/shell.py:240
+#: spyder/widgets/ipythonconsole/shell.py:241
msgid "Don't show again."
msgstr ""
-#: spyder/widgets/ipythonconsole/shell.py:264
+#: spyder/widgets/ipythonconsole/shell.py:266
msgid ""
"
Removing all variables...\n"
"
"
msgstr ""
-#: spyder/widgets/ipythonconsole/shell.py:430
-msgid "Changing backend to Qt for Mayavi"
+#: spyder/widgets/ipythonconsole/shell.py:432
+msgid "Changing backend to Qt4 for Mayavi"
msgstr ""
-#: spyder/widgets/ipythonconsole/shell.py:475
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel died, restarting"
msgstr ""
-#: spyder/widgets/ipythonconsole/shell.py:475
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel restarting"
msgstr ""
@@ -3771,51 +3898,56 @@ msgstr ""
msgid "Expand selection"
msgstr ""
-#: spyder/widgets/pathmanager.py:97
+#: spyder/widgets/pathmanager.py:98
msgid "Move to top"
msgstr ""
-#: spyder/widgets/pathmanager.py:103
+#: spyder/widgets/pathmanager.py:104
msgid "Move up"
msgstr ""
-#: spyder/widgets/pathmanager.py:109
+#: spyder/widgets/pathmanager.py:110
msgid "Move down"
msgstr ""
-#: spyder/widgets/pathmanager.py:115
+#: spyder/widgets/pathmanager.py:116
msgid "Move to bottom"
msgstr ""
-#: spyder/widgets/pathmanager.py:126 spyder/widgets/pathmanager.py:267
+#: spyder/widgets/pathmanager.py:127 spyder/widgets/pathmanager.py:270
+#: spyder/widgets/pathmanager.py:282
msgid "Add path"
msgstr ""
-#: spyder/widgets/pathmanager.py:131 spyder/widgets/pathmanager.py:246
+#: spyder/widgets/pathmanager.py:132 spyder/widgets/pathmanager.py:247
msgid "Remove path"
msgstr ""
-#: spyder/widgets/pathmanager.py:141
+#: spyder/widgets/pathmanager.py:142
msgid "Synchronize..."
msgstr ""
-#: spyder/widgets/pathmanager.py:143
+#: spyder/widgets/pathmanager.py:144
msgid "Synchronize Spyder's path list with PYTHONPATH environment variable"
msgstr ""
-#: spyder/widgets/pathmanager.py:155
+#: spyder/widgets/pathmanager.py:156
msgid "Synchronize"
msgstr ""
-#: spyder/widgets/pathmanager.py:156
+#: spyder/widgets/pathmanager.py:157
msgid "This will synchronize Spyder's path list with PYTHONPATH environment variable for current user, allowing you to run your Python modules outside Spyder without having to configure sys.path.
Do you want to clear contents of PYTHONPATH before adding Spyder's path list?"
msgstr ""
-#: spyder/widgets/pathmanager.py:247
+#: spyder/widgets/pathmanager.py:248
msgid "Do you really want to remove selected path?"
msgstr ""
-#: spyder/widgets/pathmanager.py:268
+#: spyder/widgets/pathmanager.py:271
+msgid "You are using Python 2 and the path selected has Unicode characters. The new path will not be added."
+msgstr ""
+
+#: spyder/widgets/pathmanager.py:283
msgid "This directory is already included in Spyder path list.
Do you want to move it to the top of the list?"
msgstr ""
@@ -3929,7 +4061,7 @@ msgstr ""
msgid "Create new project"
msgstr ""
-#: spyder/widgets/projects/type/__init__.py:216
+#: spyder/widgets/projects/type/__init__.py:223
msgid "Empty project"
msgstr ""
@@ -3941,57 +4073,80 @@ msgstr ""
msgid "Python package"
msgstr ""
-#: spyder/widgets/pydocgui.py:110
+#: spyder/widgets/pydocgui.py:117
msgid "Module or package:"
msgstr ""
-#: spyder/widgets/reporterror.py:121
-msgid "Spyder internal error"
+#: spyder/widgets/reporterror.py:128
+msgid "Issue reporter"
msgstr ""
-#: spyder/widgets/reporterror.py:129
-msgid ""
-"Spyder has encountered an internal problem
\n"
-" Before reporting it, please consult our comprehensive \n"
-" Troubleshooting Guide \n"
-" which should help solve most issues, and search for \n"
-" known bugs matching your error \n"
-" message or problem description for a quicker solution.\n"
-"
\n"
-" If you don't find anything, please enter a detailed step-by-step \n"
-" description (in English) of what led up to the problem below. \n"
-" Issue reports without a clear way to reproduce them will be \n"
-" closed.
\n"
-" Thanks for helping us making Spyder better for everyone!\n"
-" "
-msgstr ""
-
-#: spyder/widgets/reporterror.py:163
-msgid "Hide all future errors this session"
-msgstr ""
-
-#: spyder/widgets/reporterror.py:171
+#: spyder/widgets/reporterror.py:136
+msgid "Please fill the following information"
+msgstr ""
+
+#: spyder/widgets/reporterror.py:138
+msgid "Spyder has encountered an internal problem!"
+msgstr ""
+
+#: spyder/widgets/reporterror.py:140
+msgid "{title}
Before reporting this problem, please consult our comprehensive Troubleshooting Guide which should help solve most issues, and search for known bugs matching your error message or problem description for a quicker solution."
+msgstr ""
+
+#: spyder/widgets/reporterror.py:158 spyder/widgets/reporterror.py:190
+msgid "{} more characters to go..."
+msgstr ""
+
+#: spyder/widgets/reporterror.py:162
+msgid "Title: {}"
+msgstr ""
+
+#: spyder/widgets/reporterror.py:168
+msgid "Steps to reproduce: {}"
+msgstr ""
+
+#: spyder/widgets/reporterror.py:169
+msgid "Please enter a detailed step-by-step description (in English) of what led up to the problem below. Issue reports without a clear way to reproduce them will be closed."
+msgstr ""
+
+#: spyder/widgets/reporterror.py:194
+msgid "Hide all future errors during this session"
+msgstr ""
+
+#: spyder/widgets/reporterror.py:201
msgid "Submit to Github"
msgstr ""
-#: spyder/widgets/reporterror.py:175 spyder/widgets/reporterror.py:227
+#: spyder/widgets/reporterror.py:205 spyder/widgets/reporterror.py:312
msgid "Show details"
msgstr ""
-#: spyder/widgets/reporterror.py:178
+#: spyder/widgets/reporterror.py:210
+#: spyder/widgets/variableexplorer/arrayeditor.py:740
+#: spyder/widgets/variableexplorer/collectionseditor.py:1397
+#: spyder/widgets/variableexplorer/dataframeeditor.py:756
+#: spyder/widgets/variableexplorer/texteditor.py:72
msgid "Close"
msgstr ""
-#: spyder/widgets/reporterror.py:235
+#: spyder/widgets/reporterror.py:286
+msgid "An error occurred while trying to send the issue to Github automatically. Would you like to open it manually?
If so, please make sure to paste your clipboard into the issue report box that will appear in a new browser tab before clicking Submit on that page."
+msgstr ""
+
+#: spyder/widgets/reporterror.py:320
msgid "Hide details"
msgstr ""
-#: spyder/widgets/reporterror.py:243
+#: spyder/widgets/reporterror.py:329 spyder/widgets/reporterror.py:337
msgid "more characters to go..."
msgstr ""
-#: spyder/widgets/reporterror.py:245
-msgid "Submission enabled; thanks!"
+#: spyder/widgets/reporterror.py:331
+msgid "Description complete; thanks!"
+msgstr ""
+
+#: spyder/widgets/reporterror.py:339
+msgid "Title complete; thanks!"
msgstr ""
#: spyder/widgets/shell.py:131
@@ -4038,41 +4193,41 @@ msgstr ""
msgid "Line count:"
msgstr ""
-#: spyder/widgets/sourcecode/codeeditor.py:1327
+#: spyder/widgets/sourcecode/codeeditor.py:1334
msgid "Breakpoint"
msgstr ""
-#: spyder/widgets/sourcecode/codeeditor.py:1328
+#: spyder/widgets/sourcecode/codeeditor.py:1335
msgid "Condition:"
msgstr ""
-#: spyder/widgets/sourcecode/codeeditor.py:1733
+#: spyder/widgets/sourcecode/codeeditor.py:1740
msgid "Code analysis"
msgstr ""
-#: spyder/widgets/sourcecode/codeeditor.py:1787
+#: spyder/widgets/sourcecode/codeeditor.py:1794
msgid "To do"
msgstr ""
-#: spyder/widgets/sourcecode/codeeditor.py:2147
+#: spyder/widgets/sourcecode/codeeditor.py:2154
msgid "Removal error"
msgstr ""
-#: spyder/widgets/sourcecode/codeeditor.py:2148
+#: spyder/widgets/sourcecode/codeeditor.py:2155
msgid ""
"It was not possible to remove outputs from this notebook. The error is:\n"
"\n"
msgstr ""
-#: spyder/widgets/sourcecode/codeeditor.py:2696
+#: spyder/widgets/sourcecode/codeeditor.py:2703
msgid "Clear all ouput"
msgstr ""
-#: spyder/widgets/sourcecode/codeeditor.py:2702
+#: spyder/widgets/sourcecode/codeeditor.py:2709
msgid "Go to definition"
msgstr ""
-#: spyder/widgets/sourcecode/codeeditor.py:2735
+#: spyder/widgets/sourcecode/codeeditor.py:2742
msgid "Zoom reset"
msgstr ""
@@ -4124,291 +4279,312 @@ msgstr ""
msgid "Close current tab"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:511
+#: spyder/widgets/variableexplorer/arrayeditor.py:509
msgid "It was not possible to copy values for this array"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:546
-#: spyder/widgets/variableexplorer/arrayeditor.py:579
-#: spyder/widgets/variableexplorer/dataframeeditor.py:703
-#: spyder/widgets/variableexplorer/dataframeeditor.py:748
+#: spyder/widgets/variableexplorer/arrayeditor.py:545
+#: spyder/widgets/variableexplorer/arrayeditor.py:578
+#: spyder/widgets/variableexplorer/dataframeeditor.py:728
+#: spyder/widgets/variableexplorer/dataframeeditor.py:787
msgid "Format"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:551
-#: spyder/widgets/variableexplorer/dataframeeditor.py:707
+#: spyder/widgets/variableexplorer/arrayeditor.py:550
+#: spyder/widgets/variableexplorer/dataframeeditor.py:732
msgid "Resize"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:554
-#: spyder/widgets/variableexplorer/dataframeeditor.py:711
+#: spyder/widgets/variableexplorer/arrayeditor.py:553
+#: spyder/widgets/variableexplorer/dataframeeditor.py:736
msgid "Background color"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:580
-#: spyder/widgets/variableexplorer/dataframeeditor.py:749
+#: spyder/widgets/variableexplorer/arrayeditor.py:579
+#: spyder/widgets/variableexplorer/dataframeeditor.py:788
msgid "Float formatting"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:588
+#: spyder/widgets/variableexplorer/arrayeditor.py:587
msgid "Format (%s) is incorrect"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:624
+#: spyder/widgets/variableexplorer/arrayeditor.py:625
msgid "Arrays with more than 3 dimensions are not supported"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:628
+#: spyder/widgets/variableexplorer/arrayeditor.py:629
msgid "The 'xlabels' argument length do no match array column number"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:632
+#: spyder/widgets/variableexplorer/arrayeditor.py:633
msgid "The 'ylabels' argument length do no match array row number"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:639
+#: spyder/widgets/variableexplorer/arrayeditor.py:640
msgid "%s arrays"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:640
+#: spyder/widgets/variableexplorer/arrayeditor.py:641
msgid "%s are currently not supported"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:647
+#: spyder/widgets/variableexplorer/arrayeditor.py:648
msgid "NumPy array"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:649
-#: spyder/widgets/variableexplorer/arrayeditor.py:806
+#: spyder/widgets/variableexplorer/arrayeditor.py:650
+#: spyder/widgets/variableexplorer/arrayeditor.py:828
msgid "Array editor"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:651
+#: spyder/widgets/variableexplorer/arrayeditor.py:652
msgid "read only"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:681
+#: spyder/widgets/variableexplorer/arrayeditor.py:685
msgid "Record array fields:"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Data"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Mask"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:693
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Masked data"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:704
+#: spyder/widgets/variableexplorer/arrayeditor.py:708
msgid "Axis:"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:709
+#: spyder/widgets/variableexplorer/arrayeditor.py:713
msgid "Index:"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:722
+#: spyder/widgets/variableexplorer/arrayeditor.py:726
msgid "Warning: changes are applied separately"
msgstr ""
-#: spyder/widgets/variableexplorer/arrayeditor.py:723
+#: spyder/widgets/variableexplorer/arrayeditor.py:727
msgid "For performance reasons, changes applied to masked array won't be reflected in array's data (and vice-versa)."
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:126
+#: spyder/widgets/variableexplorer/arrayeditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:1392
+#: spyder/widgets/variableexplorer/dataframeeditor.py:751
+#: spyder/widgets/variableexplorer/texteditor.py:67
+msgid "Save and Close"
+msgstr ""
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:151
msgid "Index"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:131
+#: spyder/widgets/variableexplorer/collectionseditor.py:156
msgid "Tuple"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:134
+#: spyder/widgets/variableexplorer/collectionseditor.py:159
msgid "List"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:137
+#: spyder/widgets/variableexplorer/collectionseditor.py:162
msgid "Dictionary"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:139
+#: spyder/widgets/variableexplorer/collectionseditor.py:164
msgid "Key"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:144
+#: spyder/widgets/variableexplorer/collectionseditor.py:169
msgid "Attribute"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:148
+#: spyder/widgets/variableexplorer/collectionseditor.py:173
msgid "elements"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Size"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Type"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:319
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Value"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:417
+#: spyder/widgets/variableexplorer/collectionseditor.py:450
msgid ""
"Opening this variable can be slow\n"
"\n"
"Do you want to continue anyway?"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:428
+#: spyder/widgets/variableexplorer/collectionseditor.py:461
msgid "Spyder was unable to retrieve the value of this variable from the console.
The error mesage was:
%s"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:608
+#: spyder/widgets/variableexplorer/collectionseditor.py:643
msgid "Edit item"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:609
+#: spyder/widgets/variableexplorer/collectionseditor.py:644
msgid "Unable to assign data to item.
Error message:
%s"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:669
+#: spyder/widgets/variableexplorer/collectionseditor.py:705
msgid "Resize rows to contents"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:680
-#: spyder/widgets/variableexplorer/collectionseditor.py:1030
-#: spyder/widgets/variableexplorer/collectionseditor.py:1047
+#: spyder/widgets/variableexplorer/collectionseditor.py:716
+#: spyder/widgets/variableexplorer/collectionseditor.py:1066
+#: spyder/widgets/variableexplorer/collectionseditor.py:1083
msgid "Plot"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:684
+#: spyder/widgets/variableexplorer/collectionseditor.py:720
msgid "Histogram"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:688
+#: spyder/widgets/variableexplorer/collectionseditor.py:724
msgid "Show image"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:692
-#: spyder/widgets/variableexplorer/collectionseditor.py:1055
+#: spyder/widgets/variableexplorer/collectionseditor.py:728
+#: spyder/widgets/variableexplorer/collectionseditor.py:1091
msgid "Save array"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:696
-#: spyder/widgets/variableexplorer/collectionseditor.py:994
-#: spyder/widgets/variableexplorer/collectionseditor.py:1002
+#: spyder/widgets/variableexplorer/collectionseditor.py:732
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Insert"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:709
-#: spyder/widgets/variableexplorer/collectionseditor.py:955
+#: spyder/widgets/variableexplorer/collectionseditor.py:745
+#: spyder/widgets/variableexplorer/collectionseditor.py:991
msgid "Duplicate"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:932
+#: spyder/widgets/variableexplorer/collectionseditor.py:968
msgid "Do you want to remove the selected item?"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:933
+#: spyder/widgets/variableexplorer/collectionseditor.py:969
msgid "Do you want to remove all selected items?"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:953
+#: spyder/widgets/variableexplorer/collectionseditor.py:989
msgid "New variable name:"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:956
+#: spyder/widgets/variableexplorer/collectionseditor.py:992
msgid "Variable name:"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:994
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
msgid "Key:"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:1002
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Value:"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:1018
+#: spyder/widgets/variableexplorer/collectionseditor.py:1054
msgid "Import error"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:1019
+#: spyder/widgets/variableexplorer/collectionseditor.py:1055
msgid "Please install matplotlib or guiqwt."
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:1031
+#: spyder/widgets/variableexplorer/collectionseditor.py:1067
msgid "Unable to plot data.
Error message:
%s"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:1048
+#: spyder/widgets/variableexplorer/collectionseditor.py:1084
msgid "Unable to show image.
Error message:
%s"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:1071
+#: spyder/widgets/variableexplorer/collectionseditor.py:1097
+msgid "NumPy arrays"
+msgstr ""
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1107
msgid "Unable to save array
Error message:
%s"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:1096
+#: spyder/widgets/variableexplorer/collectionseditor.py:1132
msgid "It was not possible to copy this array"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:1121
+#: spyder/widgets/variableexplorer/collectionseditor.py:1144
+msgid "It was not possible to copy this dataframe"
+msgstr ""
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1166
msgid "Clipboard contents"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:1136
+#: spyder/widgets/variableexplorer/collectionseditor.py:1181
msgid "Import from clipboard"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:1138
+#: spyder/widgets/variableexplorer/collectionseditor.py:1183
msgid "Empty clipboard"
msgstr ""
-#: spyder/widgets/variableexplorer/collectionseditor.py:1139
+#: spyder/widgets/variableexplorer/collectionseditor.py:1184
msgid "Nothing to be imported from clipboard."
msgstr ""
-#: spyder/widgets/variableexplorer/dataframeeditor.py:597
+#: spyder/widgets/variableexplorer/dataframeeditor.py:321
+msgid ""
+"It is not possible to display this value because\n"
+"an error ocurred while trying to do it"
+msgstr ""
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To bool"
msgstr ""
-#: spyder/widgets/variableexplorer/dataframeeditor.py:597
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To complex"
msgstr ""
-#: spyder/widgets/variableexplorer/dataframeeditor.py:598
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To float"
msgstr ""
-#: spyder/widgets/variableexplorer/dataframeeditor.py:598
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To int"
msgstr ""
-#: spyder/widgets/variableexplorer/dataframeeditor.py:599
+#: spyder/widgets/variableexplorer/dataframeeditor.py:623
msgid "To str"
msgstr ""
-#: spyder/widgets/variableexplorer/dataframeeditor.py:683
+#: spyder/widgets/variableexplorer/dataframeeditor.py:707
msgid "%s editor"
msgstr ""
-#: spyder/widgets/variableexplorer/dataframeeditor.py:717
+#: spyder/widgets/variableexplorer/dataframeeditor.py:742
msgid "Column min/max"
msgstr ""
-#: spyder/widgets/variableexplorer/dataframeeditor.py:757
+#: spyder/widgets/variableexplorer/dataframeeditor.py:796
msgid "Format ({}) is incorrect"
msgstr ""
-#: spyder/widgets/variableexplorer/dataframeeditor.py:761
+#: spyder/widgets/variableexplorer/dataframeeditor.py:800
msgid "Format ({}) should start with '%'"
msgstr ""
@@ -4516,74 +4692,332 @@ msgstr ""
msgid "Unable to proceed to next step
Please check your entries.
Error message:
%s"
msgstr ""
-#: spyder/widgets/variableexplorer/namespacebrowser.py:181
-#: spyder/widgets/variableexplorer/namespacebrowser.py:385
+#: spyder/widgets/variableexplorer/namespacebrowser.py:184
+#: spyder/widgets/variableexplorer/namespacebrowser.py:397
msgid "Import data"
msgstr ""
-#: spyder/widgets/variableexplorer/namespacebrowser.py:184
-#: spyder/widgets/variableexplorer/namespacebrowser.py:465
-#: spyder/widgets/variableexplorer/namespacebrowser.py:479
+#: spyder/widgets/variableexplorer/namespacebrowser.py:187
+#: spyder/widgets/variableexplorer/namespacebrowser.py:477
+#: spyder/widgets/variableexplorer/namespacebrowser.py:491
+#: spyder/plugins/profiler/widgets/profilergui.py:121
msgid "Save data"
msgstr ""
-#: spyder/widgets/variableexplorer/namespacebrowser.py:189
+#: spyder/widgets/variableexplorer/namespacebrowser.py:192
msgid "Save data as..."
msgstr ""
-#: spyder/widgets/variableexplorer/namespacebrowser.py:201
+#: spyder/widgets/variableexplorer/namespacebrowser.py:204
msgid "Exclude references which name starts with an underscore"
msgstr ""
-#: spyder/widgets/variableexplorer/namespacebrowser.py:209
+#: spyder/widgets/variableexplorer/namespacebrowser.py:212
msgid "Exclude references which name is uppercase"
msgstr ""
-#: spyder/widgets/variableexplorer/namespacebrowser.py:216
+#: spyder/widgets/variableexplorer/namespacebrowser.py:219
msgid "Exclude references which name starts with an uppercase character"
msgstr ""
-#: spyder/widgets/variableexplorer/namespacebrowser.py:224
+#: spyder/widgets/variableexplorer/namespacebrowser.py:227
msgid "Exclude references to unsupported data types (i.e. which won't be handled/saved correctly)"
msgstr ""
-#: spyder/widgets/variableexplorer/namespacebrowser.py:405
+#: spyder/widgets/variableexplorer/namespacebrowser.py:306
+msgid "The object you are trying to modify is too big to be sent back to the kernel. Therefore, your modifications won't take place."
+msgstr ""
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:417
msgid "Unsupported file extension '%s'
Would you like to import it anyway (by selecting a known file format)?"
msgstr ""
-#: spyder/widgets/variableexplorer/namespacebrowser.py:413
+#: spyder/widgets/variableexplorer/namespacebrowser.py:425
msgid "Open file as:"
msgstr ""
-#: spyder/widgets/variableexplorer/namespacebrowser.py:447
+#: spyder/widgets/variableexplorer/namespacebrowser.py:459
msgid "Unable to load '%s'
Error message:
%s"
msgstr ""
-#: spyder/widgets/variableexplorer/namespacebrowser.py:480
+#: spyder/widgets/variableexplorer/namespacebrowser.py:492
msgid "Unable to save current workspace
Error message:
%s"
msgstr ""
-#: spyder/widgets/variableexplorer/texteditor.py:74
+#: spyder/widgets/variableexplorer/texteditor.py:84
msgid "Text editor"
msgstr ""
-#: spyder/widgets/variableexplorer/utils.py:31
-msgid "View and edit DataFrames and Series in the Variable Explorer"
+#: spyder/workers/updates.py:128 spyder/workers/updates.py:130
+msgid "Unable to retrieve information."
msgstr ""
-#: spyder/widgets/variableexplorer/utils.py:36
-msgid "View and edit two and three dimensional arrays in the Variable Explorer"
+#: spyder/workers/updates.py:132
+msgid "Unable to connect to the internet.
Make sure the connection is working properly."
msgstr ""
-#: spyder/workers/updates.py:90 spyder/workers/updates.py:92
-msgid "Unable to retrieve information."
+#: spyder/workers/updates.py:135
+msgid "Unable to check for updates."
msgstr ""
-#: spyder/workers/updates.py:94
-msgid "Unable to connect to the internet.
Make sure the connection is working properly."
+#: spyder/plugins/breakpoints/plugin.py:45
+msgid "Breakpoints"
msgstr ""
-#: spyder/workers/updates.py:97
-msgid "Unable to check for updates."
+#: spyder/plugins/breakpoints/plugin.py:80
+msgid "List breakpoints"
+msgstr ""
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "Condition"
+msgstr ""
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "Line"
+msgstr ""
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:201
+msgid "Clear this breakpoint"
+msgstr ""
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:206
+msgid "Edit this breakpoint"
+msgstr ""
+
+#: spyder/plugins/profiler/plugin.py:33 spyder/plugins/pylint/plugin.py:47
+msgid "Results"
+msgstr ""
+
+#: spyder/plugins/profiler/plugin.py:34
+msgid ""
+"Profiler plugin results (the output of python's profile/cProfile)\n"
+"are stored here:"
+msgstr ""
+
+#: spyder/plugins/profiler/plugin.py:75
+msgid "Profiler"
+msgstr ""
+
+#: spyder/plugins/profiler/plugin.py:104
+#: spyder/plugins/profiler/widgets/profilergui.py:81
+msgid "Profile"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:82
+msgid "Run profiler"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:88
+msgid "Stop current profiling"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:96
+#: spyder/plugins/profiler/widgets/profilergui.py:219
+msgid "Select Python script"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:102
+#: spyder/plugins/pylint/widgets/pylintgui.py:224
+msgid "Output"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:104
+msgid "Show program's output"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:113
+msgid "Collapse one level up"
msgstr ""
+#: spyder/plugins/profiler/widgets/profilergui.py:118
+msgid "Expand one level down"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:124
+msgid "Save profiling data"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:126
+msgid "Load data"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:129
+msgid "Load profiling data for comparison"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:131
+msgid "Clear comparison"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:171
+msgid "Please install"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:172
+msgid "the Python profiler modules"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:179
+msgid "Save profiler result"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:182
+#: spyder/plugins/profiler/widgets/profilergui.py:188
+msgid "Profiler result"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:187
+msgid "Select script to compare"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:227
+#: spyder/plugins/profiler/widgets/profilergui.py:232
+msgid "Profiler output"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:251
+msgid "Profiling, please wait..."
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:343
+msgid "Sorting data, please wait..."
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Function/Module"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Total Time"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Diff"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Calls"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Local Time"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:391
+msgid "File:line"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:565
+msgid "Function or module name"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:569
+msgid "Time in function (including sub-functions)"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:578
+msgid "Local time in function (not in sub-functions)"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:588
+msgid "Total number of calls (including recursion)"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:598
+msgid "File:line where function is defined"
+msgstr ""
+
+#: spyder/plugins/profiler/widgets/profilergui.py:603
+msgid "recursion"
+msgstr ""
+
+#: spyder/plugins/pylint/plugin.py:36
+msgid "Save file before analyzing it"
+msgstr ""
+
+#: spyder/plugins/pylint/plugin.py:40
+msgid "The following option will be applied at next startup."
+msgstr ""
+
+#: spyder/plugins/pylint/plugin.py:43
+msgid "History: "
+msgstr ""
+
+#: spyder/plugins/pylint/plugin.py:44
+msgid " results"
+msgstr ""
+
+#: spyder/plugins/pylint/plugin.py:48
+msgid "Results are stored here:"
+msgstr ""
+
+#: spyder/plugins/pylint/plugin.py:98
+#: spyder/plugins/pylint/widgets/pylintgui.py:83
+msgid "Static code analysis"
+msgstr ""
+
+#: spyder/plugins/pylint/plugin.py:133
+msgid "Run static code analysis"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:117
+msgid "Results for "
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:122
+msgid "Convention"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:124
+msgid "Refactor"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:206
+msgid "Analyze"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:207
+msgid "Run analysis"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:212
+msgid "Stop current analysis"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:218
+#: spyder/plugins/pylint/widgets/pylintgui.py:288
+msgid "Select Python file"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:226
+msgid "Complete output"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:260
+msgid "Pylint script was not found. Please add \"%s\" to PATH."
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:263
+msgid "Please install pylint:"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:326
+msgid "Pylint output"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:465
+msgid "Source code has not been rated yet."
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:471
+msgid "Analysis did not succeed (see output for more details)."
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:484
+msgid "Global evaluation:"
+msgstr ""
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:488
+msgid "previous run:"
+msgstr ""
diff --git a/spyder/locale/zh_CN/LC_MESSAGES/spyder.mo b/spyder/locale/zh_CN/LC_MESSAGES/spyder.mo
index 3f1d04dd0ac..e28a25357fd 100644
Binary files a/spyder/locale/zh_CN/LC_MESSAGES/spyder.mo and b/spyder/locale/zh_CN/LC_MESSAGES/spyder.mo differ
diff --git a/spyder/locale/zh_CN/LC_MESSAGES/spyder.po b/spyder/locale/zh_CN/LC_MESSAGES/spyder.po
index 0c521107099..662a8d39dcf 100644
--- a/spyder/locale/zh_CN/LC_MESSAGES/spyder.po
+++ b/spyder/locale/zh_CN/LC_MESSAGES/spyder.po
@@ -1,3394 +1,5918 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR ORGANIZATION
-# FIRST AUTHOR , YEAR.
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+#
+# Spyder's Chinese gettext translation file
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
-"POT-Creation-Date: \n"
-"PO-Revision-Date: 2017-04-06 10:30+0800\n"
-"Last-Translator: 李增海 <860007600@qq.com>\n"
+"POT-Creation-Date: 2018-11-13 11:49+-05\n"
+"PO-Revision-Date: 2019-04-04 10:22+0800\n"
+"Last-Translator: weak_ptr \n"
"Language-Team: \n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
-"X-Generator: Poedit 1.8.7.1\n"
+"X-Generator: Poedit 2.2.1\n"
"Plural-Forms: nplurals=1; plural=0;\n"
+#: spyder/app/mainwindow.py:139
msgid "Initializing..."
msgstr "初始化..."
+#: spyder/app/mainwindow.py:252
+msgid "Python2 documentation"
+msgstr "Python2文档"
+
+#: spyder/app/mainwindow.py:254
+msgid "Python3 documentation"
+msgstr "Python3文档"
+
+#: spyder/app/mainwindow.py:256
msgid "Numpy and Scipy documentation"
msgstr "Numpy和Scipy文档"
+#: spyder/app/mainwindow.py:258
msgid "Matplotlib documentation"
msgstr "Matplotlib文档"
-msgid "PyQt4 Reference Guide"
-msgstr "PyQt4参考指南"
+#: spyder/app/mainwindow.py:261
+msgid "PyQt5 Reference Guide"
+msgstr "PyQt5参考指南"
-msgid "PyQt4 API Reference"
-msgstr "PyQt4 API参考"
+#: spyder/app/mainwindow.py:264
+msgid "PyQt5 API Reference"
+msgstr "PyQt5 API参考"
+#: spyder/app/mainwindow.py:266
msgid "WinPython"
msgstr "WinPython"
+#: spyder/app/mainwindow.py:525
+msgid ""
+"An error occurred while creating a socket needed by Spyder. Please, try to "
+"run as an Administrator from cmd.exe the following command and then restart "
+"your computer:
netsh winsock reset"
+"b>
"
+msgstr ""
+"创建Spyder所需的套接字时出现错误。请尝试使用管理员权限启动cmd,执行下述命令后"
+"重启您的电脑:
netsh winsock reset"
+"b>
"
+
+#: spyder/app/mainwindow.py:557
msgid "Close current pane"
msgstr "关闭当前窗格"
+#: spyder/app/mainwindow.py:562
msgid "Lock panes"
msgstr "锁定窗格"
+#: spyder/app/mainwindow.py:569
msgid "Use next layout"
msgstr "使用下一个布局"
+#: spyder/app/mainwindow.py:573
msgid "Use previous layout"
msgstr "使用上一个布局"
+#: spyder/app/mainwindow.py:583 spyder/widgets/editor.py:507
+msgid "File switcher..."
+msgstr "文件切换..."
+
+#: spyder/app/mainwindow.py:585
+msgid "Fast switch between files"
+msgstr "文件间快速切换"
+
+#: spyder/app/mainwindow.py:591
+msgid "Symbol finder..."
+msgstr "搜索符号..."
+
+#: spyder/app/mainwindow.py:593
+msgid "Fast symbol search in file"
+msgstr "文件内符号快速搜索"
+
+#: spyder/app/mainwindow.py:612 spyder/widgets/sourcecode/codeeditor.py:2680
msgid "Undo"
msgstr "撤销"
+#: spyder/app/mainwindow.py:614 spyder/widgets/sourcecode/codeeditor.py:2683
msgid "Redo"
msgstr "重做"
+#: spyder/app/mainwindow.py:616 spyder/widgets/shell.py:123
+#: spyder/widgets/sourcecode/codeeditor.py:2689
+#: spyder/widgets/variableexplorer/arrayeditor.py:465
+#: spyder/widgets/variableexplorer/collectionseditor.py:710
+#: spyder/widgets/variableexplorer/dataframeeditor.py:616
msgid "Copy"
msgstr "复制"
+#: spyder/app/mainwindow.py:618 spyder/widgets/shell.py:119
+#: spyder/widgets/sourcecode/codeeditor.py:2686
msgid "Cut"
msgstr "剪切"
+#: spyder/app/mainwindow.py:620 spyder/widgets/shell.py:127
+#: spyder/widgets/sourcecode/codeeditor.py:2692
+#: spyder/widgets/variableexplorer/collectionseditor.py:707
msgid "Paste"
msgstr "粘贴"
+#: spyder/app/mainwindow.py:623 spyder/widgets/shell.py:140
+#: spyder/widgets/sourcecode/codeeditor.py:2695
msgid "Select All"
msgstr "全选"
+#: spyder/app/mainwindow.py:633 spyder/plugins/editor.py:1421
msgid "&File"
msgstr "文件(&F)"
+#: spyder/app/mainwindow.py:634 spyder/plugins/editor.py:1409
msgid "File toolbar"
msgstr "文件工具栏"
+#: spyder/app/mainwindow.py:638 spyder/plugins/editor.py:1422
msgid "&Edit"
msgstr "编辑(&E)"
+#: spyder/app/mainwindow.py:639 spyder/plugins/editor.py:1419
msgid "Edit toolbar"
msgstr "编辑工具栏"
+#: spyder/app/mainwindow.py:643 spyder/plugins/editor.py:1423
msgid "&Search"
msgstr "查找(&S)"
+#: spyder/app/mainwindow.py:644 spyder/plugins/editor.py:1411
msgid "Search toolbar"
msgstr "查找工具栏"
+#: spyder/app/mainwindow.py:648 spyder/plugins/editor.py:1424
msgid "Sour&ce"
msgstr "代码(&C)"
+#: spyder/app/mainwindow.py:649 spyder/plugins/editor.py:1413
msgid "Source toolbar"
msgstr "代码工具栏"
+#: spyder/app/mainwindow.py:653 spyder/plugins/editor.py:803
+#: spyder/plugins/editor.py:1425
msgid "&Run"
msgstr "运行(&R)"
+#: spyder/app/mainwindow.py:654 spyder/plugins/editor.py:1415
msgid "Run toolbar"
msgstr "运行工具栏"
+#: spyder/app/mainwindow.py:658 spyder/plugins/editor.py:762
msgid "&Debug"
msgstr "调试(&D)"
+#: spyder/app/mainwindow.py:659 spyder/plugins/editor.py:1417
msgid "Debug toolbar"
-msgstr "调试工具栏调试&D"
+msgstr "调试工具栏"
+#: spyder/app/mainwindow.py:663
msgid "C&onsoles"
-msgstr "控制台"
+msgstr "控制台(&O)"
+#: spyder/app/mainwindow.py:666
msgid "&Projects"
msgstr "项目(&P)"
+#: spyder/app/mainwindow.py:669 spyder/plugins/editor.py:1426
msgid "&Tools"
msgstr "工具(&T)"
+#: spyder/app/mainwindow.py:672 spyder/plugins/editor.py:1427
msgid "&View"
msgstr "查看(&V)"
+#: spyder/app/mainwindow.py:675 spyder/plugins/editor.py:1428
msgid "&Help"
msgstr "帮助(&H)"
+#: spyder/app/mainwindow.py:680
msgid "Welcome to Spyder!"
msgstr "欢迎使用Spyder!"
+#: spyder/app/mainwindow.py:685
msgid "Pre&ferences"
msgstr "偏好设置(&F)"
+#: spyder/app/mainwindow.py:692 spyder/widgets/pathmanager.py:54
msgid "PYTHONPATH manager"
msgstr "PYTHONPATH管理器"
+#: spyder/app/mainwindow.py:695
msgid "Python Path Manager"
msgstr "PYTHONPATH管理器"
+#: spyder/app/mainwindow.py:698
msgid "Update module names list"
msgstr "更新模块的名称列表"
+#: spyder/app/mainwindow.py:701
msgid "Refresh list of module names available in PYTHONPATH"
msgstr "刷新PYTHONPATH中可用模块列表"
+#: spyder/app/mainwindow.py:704
msgid "Reset Spyder to factory defaults"
-msgstr "重置Spyder到初始设置"
+msgstr "恢复出厂设置"
+#: spyder/app/mainwindow.py:709
msgid "Current user environment variables..."
msgstr "当前用户环境变量…"
-msgid "Show and edit current user environment variables in Windows registry (i.e. for all sessions)"
-msgstr "显示和编辑当前用户在Windows的环境变量(即所有会话)"
+#: spyder/app/mainwindow.py:711
+msgid ""
+"Show and edit current user environment variables in Windows registry (i.e. "
+"for all sessions)"
+msgstr "显示和编辑当前用户在Windows注册表的环境变量(应用于所有会话)"
+#: spyder/app/mainwindow.py:720 spyder/app/mainwindow.py:1115
msgid "External Tools"
msgstr "外部工具"
+#: spyder/app/mainwindow.py:723
msgid "WinPython control panel"
msgstr "WinPython控制面板"
+#: spyder/app/mainwindow.py:733
msgid "Qt Designer"
msgstr "Qt设计器"
+#: spyder/app/mainwindow.py:737
msgid "Qt Linguist"
msgstr "Qt语言家"
-msgid "Qt examples"
-msgstr "Qt例子"
-
+#: spyder/app/mainwindow.py:758
msgid "guidata examples"
msgstr "guidata例子"
+#: spyder/app/mainwindow.py:769
msgid "guiqwt examples"
msgstr "guiqwt例子"
+#: spyder/app/mainwindow.py:774
msgid "Sift"
msgstr "\"msgid \"ViTables"
-msgid "ViTables"
-msgstr "ViTables"
-
+#: spyder/app/mainwindow.py:792
msgid "Fullscreen mode"
msgstr "全屏模式"
+#: spyder/app/mainwindow.py:804
msgid "Main toolbar"
msgstr "主工具栏"
+#: spyder/app/mainwindow.py:813
+msgid ""
+"Spyder Internal Console\n"
+"\n"
+"This console is used to report application\n"
+"internal errors and to inspect Spyder\n"
+"internals with the following commands:\n"
+" spy.app, spy.window, dir(spy)\n"
+"\n"
+"Please don't use it to run your code\n"
+"\n"
+msgstr ""
+"Spyder内部控制台\n"
+"\n"
+"这个控制台用于汇报应用程序内部错误并通过spy.app, spy.window, dir(spy) 来检查"
+"Spyder内部。\n"
+"\n"
+"请不要使用它执行您的代码\n"
+"\n"
+
+#: spyder/app/mainwindow.py:830
msgid "Loading help..."
msgstr "加载帮助…"
+#: spyder/app/mainwindow.py:837
msgid "Loading outline explorer..."
-msgstr "加载输出资源管理器…"
+msgstr "加载大纲浏览器…"
+#: spyder/app/mainwindow.py:843
msgid "Loading editor..."
msgstr "加载编辑器…"
+#: spyder/app/mainwindow.py:849 spyder/plugins/console.py:141
+#: spyder/widgets/ipythonconsole/client.py:453
msgid "&Quit"
msgstr "退出(&Q)"
+#: spyder/app/mainwindow.py:851 spyder/plugins/console.py:143
msgid "Quit"
msgstr "退出"
+#: spyder/app/mainwindow.py:855
msgid "&Restart"
msgstr "重启(&R)"
+#: spyder/app/mainwindow.py:857
msgid "Restart"
msgstr "重启"
+#: spyder/app/mainwindow.py:871
msgid "Loading file explorer..."
msgstr "加载文件管理器…"
+#: spyder/app/mainwindow.py:878
msgid "Loading history plugin..."
msgstr "加载历史插件.."
+#: spyder/app/mainwindow.py:889
msgid "Loading online help..."
msgstr "加载在线帮助…"
+#: spyder/app/mainwindow.py:894
msgid "Loading project explorer..."
-msgstr "加载项目管理器…"
-
-msgid "Loading external console..."
-msgstr "加载外部控制台…"
+msgstr "加载项目资源管理器…"
+#: spyder/app/mainwindow.py:907
msgid "Loading namespace browser..."
msgstr "加载命名空间浏览器…"
+#: spyder/app/mainwindow.py:913
msgid "Loading IPython console..."
-msgstr "加载Ipython控制台"
+msgstr "加载Ipython控制台..."
+#: spyder/app/mainwindow.py:918
msgid "Setting up main window..."
msgstr "设置主窗口…"
+#: spyder/app/mainwindow.py:922
+msgid "Troubleshooting..."
+msgstr "故障排查..."
+
+#: spyder/app/mainwindow.py:924
msgid "Dependencies..."
msgstr "依赖…"
+#: spyder/app/mainwindow.py:928
msgid "Report issue..."
msgstr "报告问题…"
+#: spyder/app/mainwindow.py:932
msgid "Spyder support..."
msgstr "Spyder支持…"
+#: spyder/app/mainwindow.py:935
msgid "Check for updates..."
msgstr "检查更新…"
+#: spyder/app/mainwindow.py:940
msgid "Spyder documentation"
msgstr "Spyder文档"
+#: spyder/app/mainwindow.py:948
msgid "Spyder tutorial"
msgstr "Spyder教程"
+#: spyder/app/mainwindow.py:953
+msgid "Shortcuts Summary"
+msgstr "快捷键摘要"
+
+#: spyder/app/mainwindow.py:959
msgid "Interactive tours"
msgstr "互动之旅"
+#: spyder/app/mainwindow.py:986
msgid "Python documentation"
msgstr "Python文档"
+#: spyder/app/mainwindow.py:992
msgid "IPython documentation"
msgstr "IPython文档"
+#: spyder/app/mainwindow.py:993
msgid "Intro to IPython"
msgstr "Python介绍"
+#: spyder/app/mainwindow.py:995
msgid "Quick reference"
msgstr "快速参考"
+#: spyder/app/mainwindow.py:997
msgid "Console help"
msgstr "控制台帮助"
+#: spyder/app/mainwindow.py:1027
msgid "Installed Python modules"
-msgstr "安装Python模块"
+msgstr "已安装的Python模块"
+#: spyder/app/mainwindow.py:1031
msgid "Online documentation"
msgstr "在线文档"
+#: spyder/app/mainwindow.py:1044
msgid "Qt documentation"
msgstr "Qt文档"
+#: spyder/app/mainwindow.py:1050
msgid "About %s..."
msgstr "关于%s…"
+#: spyder/app/mainwindow.py:1081
msgid "Panes"
msgstr "窗格"
+#: spyder/app/mainwindow.py:1083
msgid "Toolbars"
msgstr "工具栏"
+#: spyder/app/mainwindow.py:1084
msgid "Window layouts"
msgstr "窗口布局"
+#: spyder/app/mainwindow.py:1093 spyder/app/mainwindow.py:1920
+#: spyder/app/mainwindow.py:1921
msgid "Show toolbars"
msgstr "显示工具栏"
+#: spyder/app/mainwindow.py:1108
msgid "Attached console window (debugging)"
-msgstr "附件控制台窗口(调试)"
-
+msgstr "已连接的控制台窗口(调试)"
+
+#: spyder/app/mainwindow.py:1298 spyder/app/mainwindow.py:1988
+#: spyder/plugins/configdialog.py:1154 spyder/plugins/projects.py:269
+#: spyder/widgets/explorer.py:723 spyder/widgets/explorer.py:828
+#: spyder/widgets/reporterror.py:285
+#: spyder/widgets/variableexplorer/arrayeditor.py:586
+#: spyder/widgets/variableexplorer/collectionseditor.py:460
+#: spyder/widgets/variableexplorer/dataframeeditor.py:797
+#: spyder/plugins/profiler/widgets/profilergui.py:295
+#: spyder/widgets/variableexplorer/namespacebrowser.py:311
+#: spyder/plugins/pylint/widgets/pylintgui.py:128
+#: spyder/plugins/pylint/widgets/pylintgui.py:363
+#: spyder/plugins/pylint/widgets/pylintgui.py:391
msgid "Error"
msgstr "错误"
+#: spyder/app/mainwindow.py:1299
msgid ""
-"You have missing dependencies!
%s
Please install them to avoid this message."
-"b>
Note: Spyder could work without some of these dependencies, however to have a smooth experience "
-"when using Spyder we strongly recommend you to install all the listed missing dependencies.
Failing "
-"to install these dependencies might result in bugs. Please be sure that any found bugs are not the direct result "
+"You have missing dependencies!
%s
Please "
+"install them to avoid this message.
Note: Spyder could "
+"work without some of these dependencies, however to have a smooth experience "
+"when using Spyder we strongly recommend you to install all the listed "
+"missing dependencies.
Failing to install these dependencies might "
+"result in bugs. Please be sure that any found bugs are not the direct result "
"of missing dependencies, prior to reporting a new issue."
msgstr ""
-"你缺少依赖!
%s
请安装缺少的依赖可以消除此信息。
提示: Spyder可"
-"以在没有这些依赖的情况下工作,为使得Spyder运行更 流畅强烈建议你安装所有缺失的依赖。
不安装这些依赖"
+"您缺少依赖!
%s
请安装缺少的依赖可以消除此信"
+"息。
提示: Spyder可以在没有这些依赖的情况下工作,为使得"
+"Spyder运行更 流畅强烈建议您安装所有缺失的依赖。
不安装这些依赖"
"可能会导致错误。请确保任何发生的BUG不是因为丢失依赖导致,之后再报告该BUG。"
+#: spyder/app/mainwindow.py:1756
msgid "Spyder Default Layout"
msgstr "Spyder默认布局"
+#: spyder/app/mainwindow.py:1774
msgid "Save current layout"
msgstr "保存当前布局"
+#: spyder/app/mainwindow.py:1778
msgid "Layout preferences"
msgstr "布局偏好"
+#: spyder/app/mainwindow.py:1782
msgid "Reset to spyder default"
-msgstr "重置Spyder为默认"
-
+msgstr "重置为Spyder默认布局"
+
+#: spyder/app/mainwindow.py:1802 spyder/app/mainwindow.py:1824
+#: spyder/app/mainwindow.py:1890 spyder/app/mainwindow.py:1898
+#: spyder/app/mainwindow.py:2843 spyder/plugins/configdialog.py:1415
+#: spyder/plugins/ipythonconsole.py:134 spyder/plugins/ipythonconsole.py:987
+#: spyder/plugins/ipythonconsole.py:1439 spyder/plugins/maininterpreter.py:162
+#: spyder/plugins/maininterpreter.py:183 spyder/plugins/maininterpreter.py:212
+#: spyder/utils/environ.py:56 spyder/utils/environ.py:107
+#: spyder/utils/environ.py:120
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:140
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:158
+#: spyder/widgets/variableexplorer/arrayeditor.py:508
+#: spyder/widgets/variableexplorer/collectionseditor.py:449
+#: spyder/plugins/pylint/widgets/pylintgui.py:126
+#: spyder/widgets/variableexplorer/collectionseditor.py:1143
+#: spyder/widgets/variableexplorer/namespacebrowser.py:305
msgid "Warning"
msgstr "警告"
+#: spyder/app/mainwindow.py:1803
+msgid ""
+"Window layout will be reset to default settings: this affects window "
+"position, size and dockwidgets.\n"
+"Do you want to continue?"
+msgstr ""
+"窗口布局将重置为默认设置:这会影响窗口位置,大小和停靠组件。\n"
+"您想继续吗?"
+
+#: spyder/app/mainwindow.py:1825
msgid ""
-"Layout %s will be overwritten. Do you want "
-"to continue?"
+"Layout %s will be "
+"overwritten. Do you want to "
+"continue?"
msgstr "布局%s 将被覆盖,是否继续?"
+#: spyder/app/mainwindow.py:1891
+msgid ""
+"Error opening the custom layout. Please close Spyder and try again. If the "
+"issue persists, then you must use 'Reset to Spyder default' from the layout "
+"menu."
+msgstr ""
+"打开自定义布局时出错。 请关闭Spyder并再试一次。 如果问题仍然存在,则必须使用"
+"布局菜单中的“重置为Spyder默认值”。"
+
+#: spyder/app/mainwindow.py:1899
msgid "Quick switch layout #%s has not yet been defined."
-msgstr "快速转换布局#%s 还没有被定义"
+msgstr "快速转换布局#%s 还没有被定义。"
+#: spyder/app/mainwindow.py:1917 spyder/app/mainwindow.py:1918
msgid "Hide toolbars"
msgstr "隐藏工具栏"
+#: spyder/app/mainwindow.py:1989
+msgid ""
+"{} is no longer a valid Spyder project! Since it is the current "
+"active project, it will be closed automatically."
+msgstr ""
+" {} 不再是有效的Spyder项目! 由于它是当前活动项目,因此将自动关闭。"
+
+#: spyder/app/mainwindow.py:2252 spyder/app/mainwindow.py:2253
msgid "Maximize current pane"
msgstr "最大化当前窗格"
+#: spyder/app/mainwindow.py:2256
msgid "Restore current pane"
msgstr "恢复当前窗格"
+#: spyder/app/mainwindow.py:2257
msgid "Restore pane to its original size"
msgstr "将窗格恢复到初始大小"
+#: spyder/app/mainwindow.py:2439
msgid "About %s"
msgstr "关于 %s"
+#: spyder/app/mainwindow.py:2579 spyder/plugins/editor.py:168
+#: spyder/plugins/runconfig.py:354 spyder/plugins/runconfig.py:476
+#: spyder/utils/programs.py:307 spyder/widgets/explorer.py:347
msgid "Run"
msgstr "运行"
+#: spyder/app/mainwindow.py:2580
msgid "Running an external system terminal is not supported on platform %s."
-msgstr "运行的额外系统终端在当前版本 %s 上不支持。"
+msgstr "不支持在当前平台 %s 上运行外部系统终端。"
-msgid "Spyder will restart and reset to default settings:
Do you want to continue?"
+#: spyder/app/mainwindow.py:2844
+msgid ""
+"Spyder will restart and reset to default settings:
Do you want to "
+"continue?"
msgstr "Spyder将重启和恢复默认设置:
是否继续?"
+#: spyder/app/mainwindow.py:2973 spyder/widgets/helperwidgets.py:254
msgid "Spyder updates"
msgstr "Spyder更新"
+#: spyder/app/mainwindow.py:2974 spyder/plugins/configdialog.py:888
msgid "Check for updates on startup"
msgstr "在启动时检查更新"
+#: spyder/app/mainwindow.py:2993
+msgid ""
+"
IMPORTANT NOTE: It seems that you are using Spyder with "
+"Anaconda/Miniconda. Please don't use pip
to "
+"update it as that will probably break your installation.
Instead, "
+"please wait until new conda packages are available and use conda"
+"code> to perform the update.
"
+msgstr ""
+"
重要提示:您似乎正在和Anaconda/Miniconda一起使用Spyder。请"
+"不要使用pip
来更新它,因为这可能会破坏您的安装。
请"
+"等到新的conda包可用并使用conda
来执行更新。
"
+
+#: spyder/app/mainwindow.py:3003
msgid ""
-"Spyder %s is available!
Please use your package manager to update Spyder or go to our Releases page to download this new version.
If you are not sure how to proceed to update Spyder "
+"Spyder %s is available!
Please use your package manager to "
+"update Spyder or go to our Releases page to download this "
+"new version.
If you are not sure how to proceed to update Spyder "
"please refer to our Installation instructions."
msgstr ""
-"Spyder %s 可用!
请使用你的模块管理器更新Spyder或去我们的 发布 页面下载最新版本. "
-"
如果您不确定如何更新请参与我们的安装 说明文档。"
+"Spyder%s可用!
请使用您的模块管理器更新Spyder或去我们的发布页面下载最新版本.
如果您不确定如何更新请参考我们的安装说明文档。"
+#: spyder/app/mainwindow.py:3016
msgid "Spyder is up to date."
-msgstr "Spyder更新到最新。"
+msgstr "Spyder已经更新到最新。"
+
+#: spyder/app/restart.py:134
+msgid ""
+"It was not possible to close the previous Spyder instance.\n"
+"Restart aborted."
+msgstr ""
+"无法关闭上一个Spyder实例。\n"
+"重启已中止。"
+
+#: spyder/app/restart.py:136
+msgid ""
+"Spyder could not reset to factory defaults.\n"
+"Restart aborted."
+msgstr ""
+"Spyder无法重置为出厂默认值。\n"
+"重启已中止。"
+
+#: spyder/app/restart.py:138
+msgid ""
+"It was not possible to restart Spyder.\n"
+"Operation aborted."
+msgstr ""
+"无法重启 Spyder。\n"
+"操作中止。"
+#: spyder/app/restart.py:140
msgid "Spyder exit error"
msgstr "Spyder退出错误"
+#: spyder/app/restart.py:141
msgid "Spyder reset error"
msgstr "Spyder重置错误"
+#: spyder/app/restart.py:142
msgid "Spyder restart error"
msgstr "Spyder启动错误"
+#: spyder/app/restart.py:183
msgid "Closing Spyder"
msgstr "Spyder关闭中"
+#: spyder/app/restart.py:257
msgid "Resetting Spyder to defaults"
msgstr "重置Spyder到默认配置"
+#: spyder/app/restart.py:289
msgid "Restarting"
msgstr "重启中"
+#: spyder/app/tour.py:123
msgid "Welcome to the Introduction tour"
msgstr "欢迎参观介绍"
+#: spyder/app/tour.py:124
msgid ""
-"Spyder is a powerful Interactive Development Environment (or IDE) for the Python programming language."
-"
Here we are going to guide you through its most important features.
Please use the arrow keys or "
+"Spyder is a powerful Interactive Development Environment (or IDE) for "
+"the Python programming language.
Here we are going to guide you "
+"through its most important features.
Please use the arrow keys or "
"click on the buttons below to move along the tour."
msgstr ""
-"Spyder是基于Python语言的一个功能强大的继承开发环境 (或IDE) .
我们将指导你了解其最重要的特点。"
-"
请使用方向键或点击下面的按钮来浏览。"
+"Spyder是基于Python语言的一个功能强大的交互式开发环境(或IDE)。
"
+"我们将指导您了解其最重要的特点。
请使用方向键或点击下面的按钮来浏览。"
+#: spyder/app/tour.py:133
msgid "The Editor"
-msgstr "当前编辑者"
+msgstr "编辑器"
+#: spyder/app/tour.py:134
msgid ""
-"This is the pane where you write Python code before evaluating it. You can get automatic suggestions and "
-"completions while writing, by pressing the Tab key next to a given text.
The Editor comes with a "
-"line number area (highlighted here in red), where Spyder shows warnings and syntax errors. They can help you to "
-"detect potential problems before running the code.
You can also set debug breakpoints in the line number "
-"area, by doing a double click next to a non-empty line."
-msgstr ""
-
+"This is the pane where you write Python code before evaluating it. You can "
+"get automatic suggestions and completions while writing, by pressing the "
+"Tab key next to a given text.
The Editor comes with a line "
+"number area (highlighted here in red), where Spyder shows warnings and "
+"syntax errors. They can help you to detect potential problems before running "
+"the code.
You can also set debug breakpoints in the line number area, "
+"by doing a double click next to a non-empty line."
+msgstr ""
+"这是您编写代码的地方。在编写代码时,您可以按下Tab来获得自动补全。"
+"
在编辑器的行号区域(红色方框内的区域),Spyder 会提示警告和语法错误。"
+"这些提示可以帮助您在运行代码前发现潜在的问题。
您也可以双击在非空行一"
+"侧的行号区域设置断点。"
+
+#: spyder/app/tour.py:149
msgid "The IPython console"
msgstr "IPython控制台"
+#: spyder/app/tour.py:150
msgid ""
-"This is one of panes where you can run or execute the code you wrote on the Editor. To do it you need to press "
-"the F5 key.
This console comes with several useful features that greatly improve your programming "
-"workflow (like syntax highlighting and inline plots). If you want to know more about them, please follow this link.
Please click on the button below to run some simple code in this console. This will "
+"This is one of panes where you can run or execute the code you wrote on the "
+"Editor. To do it you need to press the F5 key.
This console "
+"comes with several useful features that greatly improve your programming "
+"workflow (like syntax highlighting and inline plots). If you want to know "
+"more about them, please follow this link.
Please "
+"click on the button below to run some simple code in this console. This will "
"be useful to show you other important features."
msgstr ""
+"这是您的代码执行窗格。您可以按下F5运行代码。
这个控制台有很多有"
+"用的特性来改善您的编程体验(比如说代码高亮和图表显示)。如果您希望了解更多,"
+"请查看这个链接.
请点击下面的按钮在控制台执行一些简"
+"单的代码,这会向您展示一些重要的特性。"
+#: spyder/app/tour.py:166
msgid "The Variable Explorer"
-msgstr "变量资源管理器"
-
-msgid ""
-"In this pane you can view and edit the variables generated during the execution of a program, or those entered "
-"directly in one of Spyder consoles.
As you can see, the Variable Explorer is showing the variables "
-"generated during the last step of this tour. By doing a double-click on any of them, a new window will be opened, "
-"where you can inspect and modify their contents."
-msgstr ""
-
-msgid "The Python console"
-msgstr "Python控制台"
+msgstr "变量管理器"
+#: spyder/app/tour.py:167
msgid ""
-"You can also run your code on a Python console. These consoles are useful because they let you run a file in a "
-"console dedicated only to it.To select this behavior, please press the F6 key.
By pressing the "
-"button below and then focusing the Variable Explorer, you will notice that Python consoles are also connected to "
-"that pane, and that the Variable Explorer only shows the variables of the currently focused console."
-msgstr ""
-
+"In this pane you can view and edit the variables generated during the "
+"execution of a program, or those entered directly in one of Spyder consoles."
+"
As you can see, the Variable Explorer is showing the variables "
+"generated during the last step of this tour. By doing a double-click on any "
+"of them, a new window will be opened, where you can inspect and modify their "
+"contents."
+msgstr ""
+"在这个窗格,您可以查看和编辑程序运行与控制台代码执行时产生的变量。
如"
+"您所见,变量管理器展示了这个教程最后一步产生的变量。双击这些变量会打开一个新"
+"窗口,在里面您可以查看和编辑变量的内容。"
+
+#: spyder/app/tour.py:179 spyder/plugins/help.py:482 spyder/plugins/help.py:931
+#: spyder/widgets/internalshell.py:271
msgid "Help"
msgstr "帮助"
+#: spyder/app/tour.py:180
msgid ""
-"This pane displays documentation of the functions, classes, methods or modules you are currently using in the "
-"Editor or the Consoles.
To use it, you need to press Ctrl+I in front of an object. If that object "
+"This pane displays documentation of the functions, classes, methods or "
+"modules you are currently using in the Editor or the Consoles.
To use "
+"it, you need to press Ctrl+I in front of an object. If that object "
"has some documentation associated with it, it will be displayed here."
msgstr ""
+"这个窗格显示了您当前在编辑器或终端里使用的函数、类、方法或模块的文档。"
+"
您可以在一个对象前按下Ctrl+I使用这个窗格。如果那个对象有关联的"
+"文档,那么文档将会展示在这里。"
+#: spyder/app/tour.py:190
msgid "The File Explorer"
-msgstr "文件资源管理器"
+msgstr "文件管理器"
+#: spyder/app/tour.py:191
msgid ""
-"This pane lets you navigate through the directories and files present in your computer.
You can also open "
-"any of these files with its corresponding application, by doing a double click on it.
There is one "
-"exception to this rule: plain-text files will always be opened in the Spyder Editor."
+"This pane lets you navigate through the directories and files present in "
+"your computer.
You can also open any of these files with its "
+"corresponding application, by doing a double click on it.
There is "
+"one exception to this rule: plain-text files will always be opened in the "
+"Spyder Editor."
msgstr ""
+"此窗格允许您浏览计算机中存在的目录和文件。
您可以通过双击来使用与文件"
+"类型关联的应用程序来打开任意的文件。
但此规则有一个例外:将始终在"
+"Spyder编辑器中打开纯文本文件。"
+#: spyder/app/tour.py:201
msgid "The History Log"
msgstr "历史日志"
-msgid "This pane records all commands introduced in the Python and IPython consoles."
-msgstr "这个窗格"
+#: spyder/app/tour.py:202
+msgid ""
+"This pane records all commands introduced in the Python and IPython consoles."
+msgstr "这个窗格记录了在Python和IPython控制台里输入的命令。"
+#: spyder/app/tour.py:250
msgid "Spyder is an interactive development environment based on bla"
-msgstr " Spyder 是一种基于BLA的交互式开发环境"
+msgstr " Spyder 是一个社区开发和支持的交互式开发环境"
+#: spyder/app/tour.py:254
msgid "Welcome to Spyder introduction tour"
msgstr "欢迎来到Spyder浏览介绍"
+#: spyder/app/tour.py:255
msgid "Spyder is an interactive development environment based on bla"
-msgstr "Spyder是一种基于BLA的交互式开发环境"
+msgstr "Spyder是一个社区开发和支持的交互式开发环境"
+#: spyder/app/tour.py:260
msgid "Introduction tour"
msgstr "介绍阅览"
+#: spyder/app/tour.py:261
msgid "New features in version 3.0"
msgstr "版本3中的新功能"
+#: spyder/app/tour.py:555 spyder/plugins/ipythonconsole.py:474
msgid "Run code"
msgstr "运行代码"
+#: spyder/app/tour.py:830
msgid "Go to step: "
-msgstr "跳转到step:"
-
-msgid "Update LANGUAGE_CODES (inside config/base.py) if a new translation has been added to Spyder"
-msgstr "如果添加翻译到Spyder,请更新语言代码(包含在 config/base.py),"
-
-msgid "Integrate the IPython console"
-msgstr "整合Ipython控制台"
-
-msgid "Manipulate Jupyter notebooks on the Editor"
-msgstr "在编辑器操作Jupyter notebooks"
+msgstr "跳转到step: "
+#: spyder/config/utils.py:24 spyder/plugins/pylint/widgets/pylintgui.py:289
msgid "Python files"
msgstr "Python文件"
+#: spyder/config/utils.py:26
msgid "Cython/Pyrex files"
msgstr "Cython/Pyrex文件"
+#: spyder/config/utils.py:27
msgid "C files"
msgstr "C文件"
+#: spyder/config/utils.py:28
msgid "C++ files"
msgstr "C++文件"
+#: spyder/config/utils.py:29
msgid "OpenCL files"
msgstr "OpenCL文件"
+#: spyder/config/utils.py:30
msgid "Fortran files"
msgstr "Fortran文件"
+#: spyder/config/utils.py:31
msgid "IDL files"
msgstr "IDL文件"
+#: spyder/config/utils.py:32
msgid "MATLAB files"
msgstr "MATLAB文件"
+#: spyder/config/utils.py:33
msgid "Julia files"
msgstr "Julia文件"
+#: spyder/config/utils.py:34
msgid "Yaml files"
msgstr "Yaml文件"
+#: spyder/config/utils.py:35
msgid "Patch and diff files"
msgstr "补丁和差异文件"
+#: spyder/config/utils.py:36
msgid "Batch files"
msgstr "批处理文件"
+#: spyder/config/utils.py:37
msgid "Text files"
msgstr "文本文件"
+#: spyder/config/utils.py:38
msgid "reStructuredText files"
-msgstr "关于文件"
+msgstr "reStructuredText文件"
+#: spyder/config/utils.py:39
msgid "gettext files"
msgstr "gettext文件"
+#: spyder/config/utils.py:40
msgid "NSIS files"
msgstr "NSIS文件"
+#: spyder/config/utils.py:41
msgid "Web page files"
msgstr "网页文件"
+#: spyder/config/utils.py:42
msgid "XML files"
msgstr "XML文件"
+#: spyder/config/utils.py:43
msgid "Javascript files"
msgstr "JavaScript文件"
+#: spyder/config/utils.py:44
msgid "Json files"
msgstr "Json文件"
+#: spyder/config/utils.py:45
msgid "IPython notebooks"
msgstr "IPython notebooks"
+#: spyder/config/utils.py:46
msgid "Enaml files"
msgstr "Enaml文件"
+#: spyder/config/utils.py:47
msgid "Configuration files"
msgstr "配置文件"
+#: spyder/config/utils.py:49
+msgid "Markdown files"
+msgstr "Markdown文件"
+
+#: spyder/config/utils.py:53 spyder/widgets/explorer.py:796
msgid "All files"
msgstr "所有文件"
+#: spyder/config/utils.py:138
msgid "Supported text files"
-msgstr "支持文本文件"
+msgstr "支持的文本文件"
+#: spyder/plugins/__init__.py:512 spyder/plugins/editor.py:105
+#: spyder/plugins/editor.py:568 spyder/plugins/editor.py:1830
+#: spyder/plugins/help.py:117 spyder/plugins/help.py:383
+#: spyder/widgets/editor.py:544 spyder/widgets/sourcecode/codeeditor.py:98
+#: spyder/widgets/sourcecode/codeeditor.py:3229
msgid "Editor"
msgstr "编辑器"
+#: spyder/plugins/configdialog.py:146
msgid "Reset to defaults"
msgstr "重置为默认设置"
+#: spyder/plugins/configdialog.py:158
msgid "Preferences"
msgstr "偏好"
+#: spyder/plugins/configdialog.py:514
msgid "Invalid directory path"
msgstr "目录无效"
+#: spyder/plugins/configdialog.py:517 spyder/plugins/configdialog.py:532
+#: spyder/plugins/runconfig.py:220 spyder/plugins/runconfig.py:268
+#: spyder/plugins/workingdirectory.py:241 spyder/widgets/explorer.py:707
+#: spyder/widgets/findinfiles.py:347 spyder/widgets/pathmanager.py:259
+#: spyder/widgets/projects/projectdialog.py:155
msgid "Select directory"
msgstr "选择目录"
+#: spyder/plugins/configdialog.py:544 spyder/plugins/configdialog.py:704
msgid "Invalid file path"
msgstr "无效文件路径"
+#: spyder/plugins/configdialog.py:547 spyder/plugins/configdialog.py:564
+#: spyder/plugins/configdialog.py:707
msgid "Select file"
msgstr "选择文件"
+#: spyder/plugins/configdialog.py:563
msgid "All files (*)"
msgstr "所有文件(*)"
+#: spyder/plugins/configdialog.py:636
msgid "Bold"
msgstr "粗体"
+#: spyder/plugins/configdialog.py:639
msgid "Italic"
msgstr "斜体"
+#: spyder/plugins/configdialog.py:728
msgid "Font: "
-msgstr "字体:"
+msgstr "字体: "
+#: spyder/plugins/configdialog.py:734
msgid "Size: "
-msgstr "大小:"
+msgstr "大小: "
+#: spyder/plugins/configdialog.py:753
msgid "Font style"
msgstr "字体样式"
+#: spyder/plugins/configdialog.py:830
msgid "Spyder needs to restart to change the following setting:"
msgstr "Spyder需要重启以更改以下设置:"
+#: spyder/plugins/configdialog.py:833
msgid "Spyder needs to restart to change the following settings:"
msgstr "Spyder需要重启以更改以下设置:"
+#: spyder/plugins/configdialog.py:835
msgid "Do you wish to restart now?"
-msgstr "你希望现在重启吗?"
+msgstr "您希望现在重启吗?"
+#: spyder/plugins/configdialog.py:841
msgid "Information"
msgstr "信息"
+#: spyder/plugins/configdialog.py:855 spyder/plugins/configdialog.py:862
+#: spyder/widgets/projects/configdialog.py:74
msgid "General"
msgstr "通用"
-msgid "Language"
-msgstr "语言"
+#: spyder/plugins/configdialog.py:866
+msgid "Language:"
+msgstr "语言:"
+#: spyder/plugins/configdialog.py:874
+msgid "Rendering engine:"
+msgstr "渲染引擎:"
+
+#: spyder/plugins/configdialog.py:879
msgid "Use a single instance"
msgstr "使用单个实例"
-msgid "Set this to open external
Python files in an already running instance (Requires a restart)"
+#: spyder/plugins/configdialog.py:881
+msgid ""
+"Set this to open external
Python files in an already running instance "
+"(Requires a restart)"
msgstr "设置为在已运行的实例中打开外部Python文件(需要重新启动)"
+#: spyder/plugins/configdialog.py:885
msgid "Prompt when exiting"
msgstr "退出时提示"
-msgid "Pop up internal console when internal errors appear"
-msgstr "出现内部错误时弹出内部控制台"
+#: spyder/plugins/configdialog.py:886
+msgid "Show internal Spyder errors to report them to Github"
+msgstr "显示内部Spyder错误以将其报告到Github"
+#: spyder/plugins/configdialog.py:914 spyder/plugins/editor.py:114
+#: spyder/plugins/ipythonconsole.py:301
+#: spyder/widgets/projects/configdialog.py:81
msgid "Interface"
msgstr "接口"
+#: spyder/plugins/configdialog.py:922
msgid "Qt windows style"
msgstr "Qt窗体风格"
+#: spyder/plugins/configdialog.py:928
msgid "Icon theme"
msgstr "图标主题"
+#: spyder/plugins/configdialog.py:932
msgid "Vertical title bars in panes"
msgstr "在窗体上垂直显示标题"
+#: spyder/plugins/configdialog.py:934
msgid "Vertical tabs in panes"
msgstr "在窗体上垂直显示选项卡"
+#: spyder/plugins/configdialog.py:936
msgid "Animated toolbars and panes"
msgstr "动态工具栏和窗体"
+#: spyder/plugins/configdialog.py:938
msgid "Tear off menus"
msgstr "分离菜单"
+#: spyder/plugins/configdialog.py:939
msgid "Set this to detach any
menu from the main window"
-msgstr "设置该选项后
可以从主窗口中删除任意菜单"
-
-msgid "Enable high DPI scaling"
-msgstr "高DPI缩放"
-
-msgid "Set this for high DPI displays"
-msgstr "设置高DPI缩放显示"
+msgstr "设置该选项后,可以从主窗口中删除任意菜单"
+#: spyder/plugins/configdialog.py:941
msgid "Custom margin for panes:"
-msgstr "自定义窗体边缘尺寸"
+msgstr "自定义窗格外边距:"
+#: spyder/plugins/configdialog.py:943
msgid "pixels"
msgstr "像素"
+#: spyder/plugins/configdialog.py:950
+msgid "Cursor blinking:"
+msgstr "光标闪烁:"
+
+#: spyder/plugins/configdialog.py:952
+msgid "ms"
+msgstr "毫秒"
+
+#: spyder/plugins/configdialog.py:991
msgid "Status bar"
msgstr "状态栏"
+#: spyder/plugins/configdialog.py:992
msgid "Show status bar"
msgstr "显示状态栏"
+#: spyder/plugins/configdialog.py:994
msgid "Show memory usage every"
msgstr "显示内存使用情况,每"
+#: spyder/plugins/configdialog.py:996 spyder/plugins/configdialog.py:1005
+#: spyder/plugins/editor.py:139 spyder/plugins/editor.py:283
msgid " ms"
msgstr " 毫秒"
+#: spyder/plugins/configdialog.py:1003
msgid "Show CPU usage every"
msgstr "显示CPU使用情况,每"
+#: spyder/plugins/configdialog.py:1036
+msgid "Screen resolution"
+msgstr "分辨率"
+
+#: spyder/plugins/configdialog.py:1038
+msgid ""
+"Configuration for high DPI screens
Please see {0}"
+"a><> for more information about these options (in English)."
+msgstr ""
+"高DPI显示器配置
请查阅{0}来获取关于此选项的更多信"
+"息。"
+
+#: spyder/plugins/configdialog.py:1048
+msgid "Normal"
+msgstr "普通"
+
+#: spyder/plugins/configdialog.py:1052
+msgid "Enable auto high DPI scaling"
+msgstr "自动高DPI缩放"
+
+#: spyder/plugins/configdialog.py:1055
+msgid "Set this for high DPI displays"
+msgstr "为高DPI显示设置此项"
+
+#: spyder/plugins/configdialog.py:1059
+msgid "Set a custom high DPI scaling"
+msgstr "自定义高DPI缩放"
+
+#: spyder/plugins/configdialog.py:1062
+msgid "Set this for high DPI displays when auto scaling does not work"
+msgstr "当自动缩放不起作用时,为高DPI显示设置此项"
+
+#: spyder/plugins/configdialog.py:1068
+msgid ""
+"Enter values for different screens separated by semicolons ';', float values "
+"are supported"
+msgstr "为不同屏幕输入以分号';'分隔的值,支持浮点值"
+
+#: spyder/plugins/configdialog.py:1095
msgid "Plain text font"
msgstr "纯文本字体"
+#: spyder/plugins/configdialog.py:1101
msgid "Rich text font"
msgstr "富文本字体"
+#: spyder/plugins/configdialog.py:1104
msgid "Fonts"
msgstr "字体"
+#: spyder/plugins/configdialog.py:1118
msgid "Appearance"
msgstr "外观"
+#: spyder/plugins/configdialog.py:1120 spyder/plugins/ipythonconsole.py:633
msgid "Advanced Settings"
msgstr "高级设置"
+#: spyder/plugins/configdialog.py:1155
+msgid ""
+"We're sorry but the following error occurred while trying to set your "
+"selected language:
{}"
+msgstr "很抱歉,尝试设置所选语言时出现以下错误:
{} "
+
+#: spyder/plugins/configdialog.py:1164
msgid "Syntax coloring"
msgstr "语法颜色标记"
+#: spyder/plugins/configdialog.py:1177
msgid ""
-"Here you can select the color scheme used in the Editor and all other Spyder plugins.
You can also edit "
-"the color schemes provided by Spyder or create your own ones by using the options provided below.
"
+"Here you can select the color scheme used in the Editor and all other Spyder "
+"plugins.
You can also edit the color schemes provided by Spyder or "
+"create your own ones by using the options provided below.
"
msgstr ""
-"在此处你可以选择用于编辑器和其他所有Spyder插件的颜色方案
你也可以编辑Spyder提供的配色方案或使用下面的选项创"
-"建你个人的配色方案
"
+"在此处您可以选择用于编辑器和其他所有Spyder插件的颜色方案
您也可以编辑"
+"Spyder提供的配色方案或使用下面的选项创建您个人的配色方案
"
+#: spyder/plugins/configdialog.py:1182
msgid "Edit selected"
msgstr "编辑所选"
+#: spyder/plugins/configdialog.py:1183
msgid "Create new scheme"
msgstr "创建新方案"
+#: spyder/plugins/configdialog.py:1184 spyder/widgets/explorer.py:582
+#: spyder/widgets/projects/explorer.py:243 spyder/widgets/shell.py:136
msgid "Delete"
msgstr "删除"
+#: spyder/plugins/configdialog.py:1187
msgid "Reset"
msgstr "重置"
+#: spyder/plugins/configdialog.py:1194
msgid "Scheme:"
msgstr "方案:"
+#: spyder/plugins/configdialog.py:1225
msgid "Manage color schemes"
msgstr "管理配色方案"
+#: spyder/plugins/configdialog.py:1416
msgid "Are you sure you want to delete this scheme?"
-msgstr "你确定删除该方案吗?"
+msgstr "您确定删除该方案吗?"
+#: spyder/plugins/configdialog.py:1533
msgid "Text"
msgstr "文本"
+#: spyder/plugins/configdialog.py:1535
msgid "Highlight"
msgstr "高亮"
+#: spyder/plugins/configdialog.py:1537
msgid "Background"
msgstr "背景"
+#: spyder/plugins/configdialog.py:1541
msgid "Scheme name:"
msgstr "方案名:"
+#: spyder/plugins/configdialog.py:1548
msgid "Color scheme editor"
msgstr "配色方案编辑器"
+#: spyder/plugins/console.py:116
msgid "Internal console"
msgstr "内部控制台"
+#: spyder/plugins/console.py:146
msgid "&Run..."
msgstr "运行(&R)…"
+#: spyder/plugins/console.py:148
msgid "Run a Python script"
msgstr "运行一个Python脚本"
+#: spyder/plugins/console.py:151
msgid "Environment variables..."
msgstr "环境变量…"
+#: spyder/plugins/console.py:153
msgid "Show and edit environment variables (for current session)"
msgstr "显示和编辑环境变量(当前会话)"
+#: spyder/plugins/console.py:157
msgid "Show sys.path contents..."
msgstr "显示sys.path内容…"
+#: spyder/plugins/console.py:159
msgid "Show (read-only) sys.path"
msgstr "显示sys.path(只读)"
+#: spyder/plugins/console.py:162
msgid "Buffer..."
msgstr "缓冲区…"
+#: spyder/plugins/console.py:163 spyder/plugins/history.py:45
msgid "Set maximum line count"
msgstr "设置最大行数"
+#: spyder/plugins/console.py:166
msgid "External editor path..."
msgstr "外部编辑路径…"
+#: spyder/plugins/console.py:167
msgid "Set external editor executable path"
-msgstr "设置外部编辑器的可执行路径"
+msgstr "设置外部编辑器可执行文件路径"
+#: spyder/plugins/console.py:170 spyder/plugins/editor.py:149
+#: spyder/plugins/help.py:152 spyder/plugins/help.py:358
+#: spyder/plugins/history.py:48 spyder/plugins/history.py:159
msgid "Wrap lines"
msgstr "折行"
+#: spyder/plugins/console.py:173 spyder/plugins/editor.py:185
+#: spyder/plugins/ipythonconsole.py:311
msgid "Display balloon tips"
msgstr "显示提示气球"
+#: spyder/plugins/console.py:177 spyder/plugins/editor.py:179
msgid "Automatic code completion"
msgstr "代码自动补全"
+#: spyder/plugins/console.py:181 spyder/plugins/editor.py:183
msgid "Enter key selects completion"
-msgstr "Entry键完成选择"
+msgstr "回车键选择补全"
+#: spyder/plugins/console.py:186
msgid "Internal console settings"
msgstr "内部控制台设置"
+#: spyder/plugins/console.py:265
msgid "Run Python script"
msgstr "运行Python脚本"
+#: spyder/plugins/console.py:266 spyder/widgets/explorer.py:811
+#: spyder/plugins/profiler/widgets/profilergui.py:220
msgid "Python scripts"
msgstr "Python脚本"
+#: spyder/plugins/console.py:311
msgid "Buffer"
msgstr "缓冲区"
+#: spyder/plugins/console.py:312
msgid "Maximum line count"
msgstr "最大行数"
+#: spyder/plugins/console.py:322
msgid "External editor"
msgstr "外部编辑器"
+#: spyder/plugins/console.py:323
msgid "External editor executable path:"
msgstr "外部编辑器可执行路径:"
-msgid "Edit template for new modules"
-msgstr "为新模块编辑模板"
+#: spyder/plugins/editor.py:59
+msgid "Manipulate Jupyter notebooks on the Editor"
+msgstr "在编辑器操作Jupyter notebooks"
-msgid "Sort files according to full path"
-msgstr "按完整路径排序文件"
+#: spyder/plugins/editor.py:111
+msgid "Edit template for new modules"
+msgstr "编辑新模块模板"
+#: spyder/plugins/editor.py:116
msgid "Show tab bar"
msgstr "显示标签栏"
+#: spyder/plugins/editor.py:122 spyder/plugins/editor.py:199
+#: spyder/plugins/help.py:151 spyder/plugins/history.py:47
+#: spyder/plugins/ipythonconsole.py:349
msgid "Source code"
msgstr "源代码"
+#: spyder/plugins/editor.py:123
msgid "Show line numbers"
-msgstr "显示行数"
+msgstr "显示行号"
+#: spyder/plugins/editor.py:124 spyder/plugins/editor.py:985
msgid "Show blank spaces"
msgstr "显示空白"
+#: spyder/plugins/editor.py:125
msgid "Show vertical line after"
-msgstr "在指定字符数后显示垂直线:"
+msgstr "显示垂直标尺"
+#: spyder/plugins/editor.py:126
msgid "characters"
msgstr "字符"
+#: spyder/plugins/editor.py:133
msgid "Highlight current line"
msgstr "高亮显示当前行"
+#: spyder/plugins/editor.py:135
msgid "Highlight current cell"
-msgstr "高亮显示当前单元格"
+msgstr "高亮显示当前Cell"
+#: spyder/plugins/editor.py:137
msgid "Highlight occurrences after"
-msgstr "事件发生后指定时间内高亮显示:"
+msgstr "高亮延迟时间"
+#: spyder/plugins/editor.py:169
msgid "Save all files before running script"
msgstr "在执行脚本前保存所有文件"
+#: spyder/plugins/editor.py:172
msgid "Run selection"
msgstr "运行所选"
+#: spyder/plugins/editor.py:173
msgid "Maintain focus in the Editor after running cells or selections"
-msgstr "在运行单元格或选择之后保持编辑器中的焦点"
+msgstr "运行或选择Cell后保持编辑器焦点"
+#: spyder/plugins/editor.py:176
msgid "Introspection"
msgstr "内省"
+#: spyder/plugins/editor.py:181
msgid "Case sensitive code completion"
msgstr "代码完成区分大小写"
+#: spyder/plugins/editor.py:186
msgid "Link to object definition"
msgstr "链接到对象的定义"
+#: spyder/plugins/editor.py:188
+msgid ""
+"If this option is enabled, clicking on an object\n"
+"name (left-click + Ctrl key) will go this object\n"
+"definition (if resolved)."
+msgstr "如果启用此选项,则单击对象名称(左键单击+ Ctrl键)将转到此对象定义。"
+
+#: spyder/plugins/editor.py:192
msgid ""
-"Warning:
The Python module rope is not installed on this computer: calltips, code completion and "
-"go-to-definition features won't be available."
-msgstr "警告:
Python模块rope在这台计算机上没有安装:调用提示、代码完成和转到定义功能将不可用。"
+"Warning:
The Python module rope is not installed on this "
+"computer: calltips, code completion and go-to-definition features won't be "
+"available."
+msgstr ""
+"警告:
Python模块rope在这台计算机上没有安装:调用提示、代"
+"码完成和转到定义功能将不可用。"
+#: spyder/plugins/editor.py:200
msgid "Automatic insertion of parentheses, braces and brackets"
msgstr "自动插入圆括号、中括号、大括号"
+#: spyder/plugins/editor.py:203
msgid "Automatic insertion of closing quotes"
-msgstr "自动插入结束引用"
+msgstr "自动插入成对的引号"
+#: spyder/plugins/editor.py:205
msgid "Automatic insertion of colons after 'for', 'if', 'def', etc"
msgstr "在'for', 'if', 'def'等关键字后面插入冒号"
+#: spyder/plugins/editor.py:208
msgid "Automatic indentation after 'else', 'elif', etc."
-msgstr "在输入else、elif后自动缩进"
+msgstr "在输入else、elif后自动缩进。"
+#: spyder/plugins/editor.py:210
msgid "Indentation characters: "
-msgstr "缩进字符:"
+msgstr "缩进字符: "
+#: spyder/plugins/editor.py:211
msgid "2 spaces"
msgstr "2空格"
+#: spyder/plugins/editor.py:212
msgid "3 spaces"
msgstr "3空格"
+#: spyder/plugins/editor.py:213
msgid "4 spaces"
msgstr "4空格"
+#: spyder/plugins/editor.py:214
msgid "5 spaces"
msgstr "5空格"
+#: spyder/plugins/editor.py:215
msgid "6 spaces"
msgstr "6空格"
+#: spyder/plugins/editor.py:216
msgid "7 spaces"
msgstr "7空格"
+#: spyder/plugins/editor.py:217
msgid "8 spaces"
msgstr "8空格"
+#: spyder/plugins/editor.py:218
msgid "Tabulations"
msgstr "表格"
+#: spyder/plugins/editor.py:219
msgid "Tab stop width:"
-msgstr "制表宽度:"
+msgstr "制表符宽度:"
+#: spyder/plugins/editor.py:219
msgid "spaces"
msgstr "空格"
+#: spyder/plugins/editor.py:231
msgid "Tab always indent"
-msgstr "标签总是缩进"
+msgstr "Tab键总是缩进"
+#: spyder/plugins/editor.py:233
+msgid ""
+"If enabled, pressing Tab will always indent,\n"
+"even when the cursor is not at the beginning\n"
+"of a line (when this option is enabled, code\n"
+"completion may be triggered using the alternate\n"
+"shortcut: Ctrl+Space)"
+msgstr ""
+"如果启用,按Tab键将始终缩进,即使光标不在行的开头\n"
+"(启用此选项时,可以使用备用快捷键触发代码完成:Ctrl + Space)"
+
+#: spyder/plugins/editor.py:238
msgid "Intelligent backspace"
msgstr "智能退格键"
+#: spyder/plugins/editor.py:240
msgid "Automatically remove trailing spaces when saving files"
msgstr "保存文件时自动移除尾随空格"
+#: spyder/plugins/editor.py:244
msgid "Analysis"
msgstr "分析"
+#: spyder/plugins/editor.py:246
msgid "(Refer to the {} page)"
msgstr "(参阅 {} 页 )"
+#: spyder/plugins/editor.py:251
msgid "Real-time code analysis"
msgstr "实时代码分析"
+#: spyder/plugins/editor.py:253
msgid ""
-"If enabled, Python source code will be analyzed using pyflakes, lines containing errors or warnings will be "
-"highlighted.
Note: add analysis:ignore in a comment to ignore code analysis warnings.
"
+"If enabled, Python source code will be analyzed using pyflakes, lines "
+"containing errors or warnings will be highlighted.
Note: add "
+"analysis:ignore in a comment to ignore code analysis warnings.
"
msgstr ""
-"如果启用,Python源码将使用pyflakes进行分析,行中包含错误或警告时将被高亮。
提示:在注释中添加"
-"analysis:ignore来隐藏分析警告。"
+"如果启用,Python源码将使用pyflakes进行分析,行中包含错误或警告时将被高亮。"
+"
提示:在注释中添加analysis:ignore来隐藏分析警告。
"
+#: spyder/plugins/editor.py:261
msgid "Code analysis requires pyflakes %s+"
msgstr "代码分析需要pyflakes %s+"
+#: spyder/plugins/editor.py:263
msgid "Real-time code style analysis"
msgstr "实时代码风格分析"
+#: spyder/plugins/editor.py:265
msgid ""
-"If enabled, Python source code will be analyzedusing pep8, lines that are not following PEP8 style guide will "
-"be highlighted.
Note: add analysis:ignore in a comment to ignore style analysis warnings.
"
+"If enabled, Python source code will be analyzed using pycodestyle, lines "
+"that are not following PEP8 style guide will be highlighted.
Note"
+"u>: add analysis:ignore in a comment to ignore style analysis "
+"warnings.
"
msgstr ""
+"如果启用,将使用pycodestyle分析Python源代码,将突出显示不遵循PEP8样式指南"
+"的行。
注意:添加analysis:ignore在注释中忽略样式分析警"
+"告。
"
-msgid "Code annotations (TODO, FIXME, XXX, HINT, TIP, @todo)"
-msgstr "代码注释(TODO, FIXME, XXX, HINT, TIP, @todo)"
+#: spyder/plugins/editor.py:272
+msgid ""
+"Code annotations (TODO, FIXME, XXX, HINT, TIP, @todo, HACK, BUG, "
+"OPTIMIZE, !!!, ???)"
+msgstr ""
+"代码注解(TODO, FIXME, XXX, HINT, TIP, @todo, HACK, BUG, OPTIMIZE, !!!, ???)"
+#: spyder/plugins/editor.py:276
msgid "Perform analysis when saving file and every"
-msgstr "只在保存文件文件每"
+msgstr "保存文件和定时执行分析,定时分析间隔"
+#: spyder/plugins/editor.py:280
msgid "Perform analysis only when saving file"
msgstr "只在保存文件时执行分析"
+#: spyder/plugins/editor.py:339
msgid "End-of-line characters"
msgstr "行结束符"
+#: spyder/plugins/editor.py:340
msgid ""
-"When opening a text file containing mixed end-of-line characters (this may raise syntax errors in the consoles on "
-"Windows platforms), Spyder may fix the file automatically."
-msgstr "当打开含有混合结束字符的文本文件时(这可能会引发Window平台下控制台的语法错误),Spyder自动修复文件。"
+"When opening a text file containing mixed end-of-line characters (this may "
+"raise syntax errors in the consoles on Windows platforms), Spyder may fix "
+"the file automatically."
+msgstr ""
+"当打开含有混合结束字符的文本文件时(这可能会引发Window平台下控制台的语法错"
+"误),Spyder自动修复文件。"
+#: spyder/plugins/editor.py:346
msgid "Fix automatically and show warning message box"
msgstr "自动修复并显示警告对话框"
+#: spyder/plugins/editor.py:357 spyder/plugins/ipythonconsole.py:627
+#: spyder/plugins/variableexplorer.py:47
msgid "Display"
msgstr "显示"
+#: spyder/plugins/editor.py:359
msgid "Code Introspection/Analysis"
msgstr "代码内省/分析"
+#: spyder/plugins/editor.py:362
msgid "Advanced settings"
msgstr "高级设置"
-msgid "Show/hide outline explorer"
-msgstr "显示/隐藏概要浏览器"
-
+#: spyder/plugins/editor.py:644
msgid "&New file..."
msgstr "新建(&N)..."
+#: spyder/plugins/editor.py:645 spyder/widgets/explorer.py:788
+#: spyder/widgets/explorer.py:795
msgid "New file"
msgstr "新建"
+#: spyder/plugins/editor.py:654
msgid "O&pen last closed"
msgstr "打开最后关闭的文件(&P)"
+#: spyder/plugins/editor.py:655
msgid "Open last closed"
msgstr "打开最后关闭的文件"
+#: spyder/plugins/editor.py:661
msgid "&Open..."
msgstr "打开(&O)..."
+#: spyder/plugins/editor.py:662 spyder/plugins/editor.py:1881
+#: spyder/plugins/editor.py:1887
msgid "Open file"
msgstr "打开文件"
-msgid "File switcher..."
-msgstr "文件切换"
-
-msgid "Fast switch between files"
-msgstr "文件间快速切换"
-
-msgid "Symbol finder..."
-msgstr "符号搜索"
-
-msgid "Fast symbol search in file"
-msgstr "文件内符号快速搜索"
-
+#: spyder/plugins/editor.py:668
msgid "&Revert"
msgstr "恢复(&R)"
+#: spyder/plugins/editor.py:669
msgid "Revert file from disk"
msgstr "从硬盘恢复文件"
+#: spyder/plugins/editor.py:672
msgid "&Save"
msgstr "保存(&S)"
+#: spyder/plugins/editor.py:673 spyder/widgets/editor.py:1675
msgid "Save file"
msgstr "保存文件"
+#: spyder/plugins/editor.py:679
msgid "Sav&e all"
msgstr "保存所有(&E)"
+#: spyder/plugins/editor.py:680
msgid "Save all files"
msgstr "保存所有文件"
+#: spyder/plugins/editor.py:686
msgid "Save &as..."
msgstr "另存为(&A)..."
+#: spyder/plugins/editor.py:687
msgid "Save current file as..."
msgstr "另存当前文件为..."
+#: spyder/plugins/editor.py:692
+msgid "Save copy as..."
+msgstr "另存为..."
+
+#: spyder/plugins/editor.py:693
+msgid "Save copy of current file as..."
+msgstr "另存为..."
+
+#: spyder/plugins/editor.py:696 spyder/plugins/editor.py:697
msgid "Print preview..."
-msgstr "打印预览"
+msgstr "打印预览..."
+#: spyder/plugins/editor.py:698
msgid "&Print..."
msgstr "打印(&P)"
+#: spyder/plugins/editor.py:699
msgid "Print current file..."
msgstr "打印当前文件…"
+#: spyder/plugins/editor.py:702
msgid "&Close"
msgstr "关闭(&C)"
+#: spyder/plugins/editor.py:703
msgid "Close current file"
msgstr "关闭当前文件"
+#: spyder/plugins/editor.py:706
msgid "C&lose all"
msgstr "关闭所有(&L)"
+#: spyder/plugins/editor.py:707
msgid "Close all opened files"
msgstr "关闭所有打开的文件"
+#: spyder/plugins/editor.py:714
msgid "&Find text"
msgstr "查找下一个(&F)"
+#: spyder/plugins/editor.py:720
msgid "Find &next"
msgstr "查找下一个(&N)"
+#: spyder/plugins/editor.py:726
msgid "Find &previous"
msgstr "查找上一个(&P)"
+#: spyder/plugins/editor.py:732
msgid "&Replace text"
msgstr "替换文本(&R)"
+#: spyder/plugins/editor.py:741
msgid "Set/Clear breakpoint"
msgstr "设置/清除 断点"
+#: spyder/plugins/editor.py:748
msgid "Set/Edit conditional breakpoint"
msgstr "设置/编辑条件断点"
+#: spyder/plugins/editor.py:755
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:180
msgid "Clear breakpoints in all files"
msgstr "清理所有文件中的断点"
+#: spyder/plugins/editor.py:757
msgid "Debug with winpdb"
msgstr "用winpdb调试"
+#: spyder/plugins/editor.py:764
msgid "Debug file"
msgstr "调试文件"
+#: spyder/plugins/editor.py:769
msgid "Step"
msgstr "步"
+#: spyder/plugins/editor.py:770
msgid "Run current line"
msgstr "运行当前行"
+#: spyder/plugins/editor.py:775
msgid "Continue"
msgstr "继续"
+#: spyder/plugins/editor.py:777
msgid "Continue execution until next breakpoint"
msgstr "继续运行直到下一个断点"
+#: spyder/plugins/editor.py:782
msgid "Step Into"
msgstr "步入"
+#: spyder/plugins/editor.py:784
msgid "Step into function or method of current line"
msgstr "步入当前行的函数或方法"
+#: spyder/plugins/editor.py:789
msgid "Step Return"
msgstr "步回"
+#: spyder/plugins/editor.py:791
msgid "Run until current function or method returns"
-msgstr "执行知道当前函数或方法返回"
+msgstr "执行直到当前函数或方法返回"
+#: spyder/plugins/editor.py:796 spyder/widgets/findinfiles.py:450
+#: spyder/widgets/ipythonconsole/client.py:393
+#: spyder/plugins/profiler/widgets/profilergui.py:87
+#: spyder/plugins/pylint/widgets/pylintgui.py:211
msgid "Stop"
msgstr "停止"
+#: spyder/plugins/editor.py:797
msgid "Stop debugging"
msgstr "停止调试"
+#: spyder/plugins/editor.py:804
msgid "Run file"
msgstr "运行文件"
-msgid "&Configure..."
-msgstr "配置(&C)"
+#: spyder/plugins/editor.py:809
+msgid "&Configuration per file..."
+msgstr "单文件配置(&C)"
+#: spyder/plugins/editor.py:811
msgid "Run settings"
msgstr "运行设置"
+#: spyder/plugins/editor.py:817
msgid "Re-run &last script"
msgstr "重新运行最后的脚本(&L)"
+#: spyder/plugins/editor.py:819
msgid "Run again last file"
msgstr "再次运行最后的文件"
+#: spyder/plugins/editor.py:825 spyder/widgets/sourcecode/codeeditor.py:2727
msgid "Run &selection or current line"
msgstr "运行所选或当前行(&S)"
+#: spyder/plugins/editor.py:828
msgid "Run selection or current line"
msgstr "运行所选或当前行"
+#: spyder/plugins/editor.py:836 spyder/widgets/sourcecode/codeeditor.py:2715
msgid "Run cell"
-msgstr "运行单元"
+msgstr "运行Cell"
+#: spyder/plugins/editor.py:839
+msgid ""
+"Run current cell (Ctrl+Enter)\n"
+"[Use #%% to create cells]"
+msgstr ""
+"运行当前Cell (Ctrl+Enter)\n"
+"[使用#%%来创建Cell]"
+
+#: spyder/plugins/editor.py:845 spyder/widgets/sourcecode/codeeditor.py:2719
msgid "Run cell and advance"
-msgstr "运行单元并继续"
+msgstr "运行Cell并继续"
+#: spyder/plugins/editor.py:848
msgid "Run current cell and go to the next one (Shift+Enter)"
-msgstr "运行当前单元并跳到下一单元(Shift+Enter)"
+msgstr "运行当前Cell并跳到下一个(Shift+Enter)"
+
+#: spyder/plugins/editor.py:854 spyder/widgets/sourcecode/codeeditor.py:2723
+msgid "Re-run last cell"
+msgstr "重新运行最后一个Cell"
+#: spyder/plugins/editor.py:855
+msgid "Re run last cell "
+msgstr "重新运行最后一个Cell "
+
+#: spyder/plugins/editor.py:865
msgid "Show todo list"
msgstr "显示代办事项列表"
-msgid "Show TODO/FIXME/XXX/HINT/TIP/@todo comments list"
-msgstr "显示TODO/FIXME/XXX/HINT/TIP/@todo注释列表"
+#: spyder/plugins/editor.py:866
+msgid ""
+"Show comments list (TODO/FIXME/XXX/HINT/TIP/@todo/HACK/BUG/OPTIMIZE/!!!/???)"
+msgstr "显示注释 (TODO/FIXME/XXX/HINT/TIP/@todo/HACK/BUG/OPTIMIZE/!!!/???)"
+#: spyder/plugins/editor.py:874
msgid "Show warning/error list"
msgstr "显示警告/错误列表"
+#: spyder/plugins/editor.py:875
msgid "Show code analysis warnings/errors"
msgstr "显示代码分析的警告/错误"
+#: spyder/plugins/editor.py:881
msgid "Previous warning/error"
msgstr "上一个警告/错误"
+#: spyder/plugins/editor.py:882
msgid "Go to previous code analysis warning/error"
msgstr "转到上一个代码分析的警告/错误"
+#: spyder/plugins/editor.py:885
msgid "Next warning/error"
msgstr "下一个警告/错误"
+#: spyder/plugins/editor.py:886
msgid "Go to next code analysis warning/error"
msgstr "转到下一个代码分析的警告/错误"
+#: spyder/plugins/editor.py:890
msgid "Last edit location"
msgstr "最后一次的编辑位置"
+#: spyder/plugins/editor.py:891
msgid "Go to last edit location"
msgstr "转到最后一次的编辑位置"
+#: spyder/plugins/editor.py:899
msgid "Previous cursor position"
msgstr "上一个光标位置"
+#: spyder/plugins/editor.py:900
msgid "Go to previous cursor position"
msgstr "转到上一个光标位置"
+#: spyder/plugins/editor.py:908
msgid "Next cursor position"
msgstr "下一个光标位置"
+#: spyder/plugins/editor.py:909
msgid "Go to next cursor position"
msgstr "转到下一个光标位置"
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Comment"
msgstr "注释"
+#: spyder/plugins/editor.py:919 spyder/widgets/sourcecode/codeeditor.py:2699
msgid "Uncomment"
msgstr "取消注释"
+#: spyder/plugins/editor.py:920
msgid "Comment current line or selection"
msgstr "注释当前行或所选行"
+#: spyder/plugins/editor.py:924
msgid "Add &block comment"
msgstr "添加块注释(&B)"
+#: spyder/plugins/editor.py:925
msgid "Add block comment around current line or selection"
msgstr "在当前行或所选行添加块注释"
+#: spyder/plugins/editor.py:931
msgid "R&emove block comment"
-msgstr "移除块注释(&R)"
+msgstr "移除块注释(&E)"
+#: spyder/plugins/editor.py:932
msgid "Remove comment block around current line or selection"
msgstr "在当前行或所选行移除块注释"
+#: spyder/plugins/editor.py:943
msgid "Indent"
msgstr "缩进"
+#: spyder/plugins/editor.py:944
msgid "Indent current line or selection"
msgstr "缩进当前行或所选行"
+#: spyder/plugins/editor.py:947
msgid "Unindent"
msgstr "取消缩进"
+#: spyder/plugins/editor.py:948
msgid "Unindent current line or selection"
msgstr "取消缩进当前行或所选行"
+#: spyder/plugins/editor.py:952
msgid "Toggle Uppercase"
msgstr "切换大写"
+#: spyder/plugins/editor.py:953
msgid "Change to uppercase current line or selection"
msgstr "将当前行或所选行转为大写"
+#: spyder/plugins/editor.py:959
msgid "Toggle Lowercase"
msgstr "切换小写"
+#: spyder/plugins/editor.py:960
msgid "Change to lowercase current line or selection"
msgstr "将当前行或所选行转为小写"
+#: spyder/plugins/editor.py:967
msgid "Carriage return and line feed (Windows)"
-msgstr "回车与换行(Windows)"
+msgstr "回车与换行 CRLF(Windows)"
+#: spyder/plugins/editor.py:970
msgid "Line feed (UNIX)"
-msgstr "换行(UNIX)"
+msgstr "换行 LF(UNIX)"
+#: spyder/plugins/editor.py:973
msgid "Carriage return (Mac)"
-msgstr "回车(Mac)"
+msgstr "回车 CR(Mac)"
+#: spyder/plugins/editor.py:979
msgid "Convert end-of-line characters"
-msgstr "转换结束字符串"
+msgstr "转换换行符"
+#: spyder/plugins/editor.py:983
msgid "Remove trailing spaces"
msgstr "删除尾部空格"
+#: spyder/plugins/editor.py:987
msgid "Fix indentation"
msgstr "固定缩进"
+#: spyder/plugins/editor.py:988
msgid "Replace tab characters by space characters"
msgstr "用空格替换tab缩进"
+#: spyder/plugins/editor.py:991
msgid "Go to line..."
msgstr "转到行…"
+#: spyder/plugins/editor.py:999
msgid "Set console working directory"
msgstr "设置控制台工作目录"
-msgid "Set current console (and file explorer) working directory to current script directory"
+#: spyder/plugins/editor.py:1001
+msgid ""
+"Set current console (and file explorer) working directory to current script "
+"directory"
msgstr "将当前控制台(和文件管理器)工作目录设置为当前脚本目录"
+#: spyder/plugins/editor.py:1006
msgid "Maximum number of recent files..."
msgstr "最近文件的最大数量..."
+#: spyder/plugins/editor.py:1009
msgid "Clear recent files list"
msgstr "清理最近的文件列表"
+#: spyder/plugins/editor.py:1009 spyder/plugins/projects.py:101
+#: spyder/widgets/findinfiles.py:261
msgid "Clear this list"
msgstr "清理这个列表"
+#: spyder/plugins/editor.py:1013
msgid "Open &recent"
msgstr "打开最近(&R)"
+#: spyder/plugins/editor.py:1674
msgid "Spyder Editor"
msgstr "Spyder编辑器"
+#: spyder/plugins/editor.py:1675
msgid "This is a temporary script file."
-msgstr "这是一个临时脚本文件"
+msgstr "这是一个临时脚本文件。"
+#: spyder/plugins/editor.py:1758
msgid "untitled"
msgstr "未命名"
+#: spyder/plugins/editor.py:1831
msgid "Maximum number of recent files"
msgstr "最近文件的最大数量"
+#: spyder/plugins/editor.py:1977
msgid "Printing..."
-msgstr "打印中"
+msgstr "打印中..."
+#: spyder/plugins/explorer.py:55
msgid "File explorer"
-msgstr "文件资源管理器"
-
-msgid "Interactive data plotting in the consoles"
-msgstr "控制台中的交互式数据绘图"
-
-msgid "Python console"
-msgstr "Python控制台"
-
-msgid "One tab per script"
-msgstr "每个脚本一个标签"
-
-msgid "Show elapsed time"
-msgstr "显示耗时"
-
-msgid "Show icons and text"
-msgstr "显示图标和文本"
-
-msgid "Buffer: "
-msgstr "缓存:"
-
-msgid " lines"
-msgstr " 行"
-
-msgid "Merge process standard output/error channels"
-msgstr "合并进程标准输出/错误通道"
-
-msgid "Colorize standard error channel using ANSI escape codes"
-msgstr "使用标准误差通道使用ANSI转义码"
-
-msgid "Background color"
-msgstr "背景色"
-
-msgid "This option will be applied the next time a Python console or a terminal is opened."
-msgstr "下次打开Python控制台或终端时,将应用此选项。"
-
-msgid "Light background (white color)"
-msgstr "浅色背景(白色)"
-
-msgid "PYTHONSTARTUP replacement"
-msgstr "PYTHONSTARTUP替代"
-
-msgid "Default PYTHONSTARTUP script"
-msgstr "默认PYTHONSTARTUP脚本"
-
-msgid "Use the following startup script:"
-msgstr "使用以下启动脚本:"
-
-msgid "Monitor"
-msgstr "监控"
-
-msgid ""
-"The monitor provides introspection features to console: code completion, calltips and variable explorer. Because "
-"it relies on several modules, disabling the monitor may be useful to accelerate console startup."
-msgstr ""
-"显示器提供用于控制台的自省功能︰ 代码完成、 调用提示 和变量资源管理器。因为它依赖于几个模块,禁用显示器可能有助于"
-"加速控制台启动。"
-
-msgid "Enable monitor"
-msgstr "启用监视器"
-
-msgid "Default library"
-msgstr "缺省库"
-
-msgid "Qt-Python Bindings"
-msgstr "Qt-Python绑定"
-
-msgid "Library:"
-msgstr "库:"
-
-msgid "This option will act on
libraries such as Matplotlib, guidata or ETS"
-msgstr "该选项将作用于 Matplotlib, guidata 或 ETS等库。"
-
-msgid "Graphics"
-msgstr "绘图"
-
-msgid ""
-"Decide which backend to use to display graphics. If unsure, please select the Automatic backend."
-"
Note: We support a very limited number of backends in our Python consoles. If you prefer to work "
-"with a different one, please use an IPython console."
-msgstr ""
-"决定使用哪个后台来显示图形。如果未能确定,请选择自动后台。
提示:我们在Python控制台上支持有限"
-"数量的后台。如果你希望用不同的后端工作,请使用IPython控制台。"
-
-msgid "None"
-msgstr "None"
-
-msgid "Automatic"
-msgstr "自动"
-
-msgid "Backend:"
-msgstr "后台"
-
-msgid "This option will be applied the next time a console is opened."
-msgstr "此选项将会应用在下次打开控制台。"
-
-msgid "Enthought Tool Suite"
-msgstr "Enthought工具套件"
-
-msgid "Enthought Tool Suite (ETS) supports PyQt4 (qt4) and wxPython (wx) graphical user interfaces."
-msgstr "Enthought工具套件(ETS)支持PyQt4(Qt4)和wxPython(Wx)图形用户界面。"
-
-msgid "ETS_TOOLKIT:"
-msgstr "ETS_TOOLKIT:"
-
-msgid "External modules"
-msgstr "外部模块"
-
-msgid ""
-"No Python console is currently selected to run %s.
Please select or open a new Python console and "
-"try again."
-msgstr "当前没有为运行%s选择Python控制台.
请选择或打开一个新的Python控制台并尝试重新运行"
-
-msgid "Command Window"
-msgstr "命令窗口"
-
-msgid "Terminal"
-msgstr "终端"
-
-msgid "Open a &Python console"
-msgstr "打开一个Python控制台(&P)"
-
-msgid "Open &command prompt"
-msgstr "打开命令提示符(&C)"
-
-msgid "Open a Windows command prompt"
-msgstr "打开一个Windows命令提示符"
-
-msgid "Open a &terminal"
-msgstr "打开一个终端(&T)"
-
-msgid "Open a terminal window"
-msgstr "打开一个终端窗口"
+msgstr "文件管理器"
+#: spyder/plugins/findinfiles.py:117 spyder/widgets/findinfiles.py:949
msgid "Find in files"
-msgstr "在文件中查找..."
+msgstr "在文件中查找"
+#: spyder/plugins/findinfiles.py:141
msgid "&Find in files"
-msgstr "在文件中查找..."
+msgstr "在文件中查找(&F)"
+#: spyder/plugins/findinfiles.py:146
msgid "Search text in multiple files"
msgstr "在多文件中查找文本"
+#: spyder/plugins/help.py:43
msgid "Show help for objects in the Editor and Consoles in a dedicated pane"
msgstr "在专用窗格中显示编辑器和控制台的对象的帮助"
+#: spyder/plugins/help.py:109
msgid "Automatic connections"
msgstr "自动连接"
+#: spyder/plugins/help.py:110
msgid ""
-"This pane can automatically show an object's help information after a left parenthesis is written next to it. "
-"Below you can decide to which plugin you want to connect it to turn on this feature."
-msgstr "此窗格可以在左圆括号后面自动显示对象的帮助信息。下面,您可以决定哪些插件能连接它启用此功能。"
+"This pane can automatically show an object's help information after a left "
+"parenthesis is written next to it. Below you can decide to which plugin you "
+"want to connect it to turn on this feature."
+msgstr ""
+"此窗格可以在左圆括号后面自动显示对象的帮助信息。下面,您可以决定哪些插件能连"
+"接它启用此功能。"
-msgid "Python Console"
-msgstr "Python控制台"
+#: spyder/plugins/help.py:122
+msgid ""
+"This feature requires the Rope or Jedi libraries.\n"
+"It seems you don't have either installed."
+msgstr ""
+"该特性需要 Rope 或 Jedi 库。\n"
+"看起来您两者都没有安装。"
+#: spyder/plugins/help.py:125
msgid "IPython Console"
msgstr "IPython控制台"
+#: spyder/plugins/help.py:135
msgid "Additional features"
msgstr "附加功能"
+#: spyder/plugins/help.py:136
msgid "Render mathematical equations"
msgstr "呈现数学方程"
+#: spyder/plugins/help.py:142
msgid "This feature requires Sphinx 1.1 or superior."
msgstr "此功能要求Sphinx 1.1及以上版本。"
+#: spyder/plugins/help.py:143
msgid "Sphinx %s is currently installed."
msgstr "Sphinx %s当前已安装。"
+#: spyder/plugins/help.py:304
msgid "No further documentation available"
msgstr "没有进一步的文档可用"
+#: spyder/plugins/help.py:307 spyder/plugins/help.py:345
msgid "No documentation available"
msgstr "没有可用的文档"
# 右上角顶部
+#: spyder/plugins/help.py:376
msgid "Source"
msgstr "源"
+#: spyder/plugins/help.py:383 spyder/plugins/runconfig.py:170
+#: spyder/plugins/runconfig.py:486 spyder/widgets/ipythonconsole/client.py:327
msgid "Console"
msgstr "控制台"
+#: spyder/plugins/help.py:391
msgid "Object"
msgstr "对象"
+#: spyder/plugins/help.py:405
msgid "Plain Text"
msgstr "纯文本"
+#: spyder/plugins/help.py:409
msgid "Show Source"
msgstr "显示源码"
+#: spyder/plugins/help.py:413
msgid "Rich Text"
msgstr "富文本"
+#: spyder/plugins/help.py:423
msgid "Automatic import"
msgstr "自动导入"
+#: spyder/plugins/help.py:435 spyder/plugins/history.py:108
+#: spyder/widgets/editor.py:738 spyder/widgets/explorer.py:1205
+#: spyder/widgets/ipythonconsole/client.py:417
+#: spyder/widgets/variableexplorer/namespacebrowser.py:151
msgid "Options"
msgstr "选项"
+#: spyder/plugins/help.py:692
msgid ""
-"Here you can get help of any object by pressing %s in front of it, either on the Editor or the Console.%sHelp can "
-"also be shown automatically after writing a left parenthesis next to an object. You can activate this behavior in "
-"%s."
+"Here you can get help of any object by pressing %s in front of it, either on "
+"the Editor or the Console.%sHelp can also be shown automatically after "
+"writing a left parenthesis next to an object. You can activate this behavior "
+"in %s."
msgstr ""
-"在编辑器或者控制台中,光标在任何对象上时,按下%s你都可以在这里获得帮助信息。%s帮助也可以写一个左括号对象后自动显"
-"示。您可以在%s中激活此行为。"
+"在编辑器或者控制台中,光标在任何对象上时,按下%s您都可以在这里获得帮助信"
+"息。%s帮助也可以写一个左括号对象后自动显示。您可以在%s中激活此行为。"
+#: spyder/plugins/help.py:698
msgid "Preferences > Help"
msgstr "首选项 > 帮助"
+#: spyder/plugins/help.py:705
msgid "Usage"
-msgstr "使用"
+msgstr "使用方式"
+#: spyder/plugins/help.py:706
msgid "New to Spyder? Read our"
-msgstr "全新的Spyder?阅读我们"
+msgstr "第一次使用 Spyder?请阅读我们的"
+#: spyder/plugins/help.py:707
msgid "tutorial"
msgstr "教程"
-msgid "Please consider installing Sphinx to get documentation rendered in rich text."
+#: spyder/plugins/help.py:714
+msgid ""
+"Please consider installing Sphinx to get documentation rendered in rich text."
msgstr "请考虑安装Sphinx 来获取以富文本呈现的文档。"
+#: spyder/plugins/help.py:885
msgid "Lock"
msgstr "锁定"
+#: spyder/plugins/help.py:885
msgid "Unlock"
msgstr "解锁"
+#: spyder/plugins/help.py:932
msgid ""
-"The following error occured when calling Sphinx %s.
Incompatible Sphinx version or doc string decoding "
-"failed.
Error message:
%s"
+"The following error occured when calling Sphinx %s.
Incompatible "
+"Sphinx version or doc string decoding failed.
Error message:
%s"
msgstr ""
+"调用 Sphinx%s 时发生以下错误:
不兼容的Sphinx版本或doc字符串解码失"
+"败。
错误消息:
%s"
+#: spyder/plugins/help.py:976
msgid "No source code available."
-msgstr "没有可用的来源代码"
+msgstr "没有可用的来源代码。"
+#: spyder/plugins/history.py:39 spyder/plugins/pylint/plugin.py:35
msgid "Settings"
msgstr "设置"
+#: spyder/plugins/history.py:43
msgid " entries"
msgstr " 条目"
+#: spyder/plugins/history.py:43
msgid "History depth: "
msgstr "历史深度: "
+#: spyder/plugins/history.py:50
msgid "Scroll automatically to last entry"
msgstr "自动滚动到最后一个条目"
+#: spyder/plugins/history.py:128
msgid "History log"
msgstr "历史日志"
+#: spyder/plugins/history.py:153 spyder/plugins/pylint/plugin.py:115
msgid "History..."
msgstr "历史…"
+#: spyder/plugins/history.py:155 spyder/plugins/pylint/plugin.py:117
msgid "Set history maximum entries"
msgstr "设置历史最大条数"
+#: spyder/plugins/history.py:260 spyder/plugins/pylint/plugin.py:39
+#: spyder/plugins/pylint/plugin.py:160
msgid "History"
msgstr "历史"
+#: spyder/plugins/history.py:261 spyder/plugins/pylint/plugin.py:161
msgid "Maximum entries"
msgstr "最大条数"
+#: spyder/plugins/ipythonconsole.py:64
msgid "Symbolic mathematics in the IPython Console"
-msgstr "在Ipyhton控制台的符号数学"
+msgstr "IPython 控制台的符号化运算"
-msgid "The authenticity of host %s can't be established. Are you sure you want to continue connecting?"
-msgstr ""
+#: spyder/plugins/ipythonconsole.py:68
+msgid "Run Cython files in the IPython Console"
+msgstr "在IPython控制台运行Cython文件"
+
+#: spyder/plugins/ipythonconsole.py:72
+msgid "Integrate the IPython console"
+msgstr "整合Ipython控制台"
+
+#: spyder/plugins/ipythonconsole.py:76
+msgid "IPython interactive python environment"
+msgstr "IPython交互式Python环境"
+
+#: spyder/plugins/ipythonconsole.py:80
+msgid "Display 2D graphics in the IPython Console"
+msgstr "在IPython控制台显示2D图形"
+#: spyder/plugins/ipythonconsole.py:131
+msgid ""
+"The authenticity of host %s can't be established. Are you sure you "
+"want to continue connecting?"
+msgstr "无法确定主机%s身份真实性,您想要继续连接吗?"
+
+#: spyder/plugins/ipythonconsole.py:143
msgid "The authenticity of the host can't be established"
msgstr "主机的真实性不能确定"
+#: spyder/plugins/ipythonconsole.py:150
msgid "Tunnel '%s' failed to start"
-msgstr ""
+msgstr "隧道 '%s' 启动失败"
+#: spyder/plugins/ipythonconsole.py:155
msgid "Could not connect to remote host"
msgstr "无法连接远程主机"
+#: spyder/plugins/ipythonconsole.py:172 spyder/plugins/ipythonconsole.py:846
msgid "Connect to an existing kernel"
-msgstr "连接到一个已存在的内核"
+msgstr "连接到一个已存在的 IPython kernel"
+#: spyder/plugins/ipythonconsole.py:174
msgid ""
-"Please enter the connection info of the kernel you want to connect to. For that you can either select its JSON "
-"connection file using the Browse button, or write directly its id, in case it's a local kernel (for "
-"example kernel-3764.json or just 3764)."
+"Please select the JSON connection file (e.g. kernel-3764.json"
+"tt>) or enter the 4-digit ID (e.g. 3764) of the existing "
+"kernel to connect to, and enter the SSH host name and credentials if a "
+"remote kernel."
msgstr ""
+"请选择JSON连接文件(例如kernel-3764.json)或者输入四位ID("
+"例如3764)来需要连接的已存在 IPython kernel,如果是远程 IPython "
+"kernel,还需要输入SSH主机名和凭据。"
-msgid "Connection info:"
-msgstr "连接信息︰"
+#: spyder/plugins/ipythonconsole.py:183
+msgid "Kernel ID/Connection file:"
+msgstr "IPython kernel ID/连接文件:"
-msgid "Path to connection file or kernel id"
-msgstr "连接文件或核心的路径"
+#: spyder/plugins/ipythonconsole.py:185
+msgid "ID number or path to connection file"
+msgstr "ID或连接文件"
+#: spyder/plugins/ipythonconsole.py:187 spyder/plugins/ipythonconsole.py:216
msgid "Browse"
msgstr "浏览器"
-msgid "This is a remote kernel"
-msgstr "这是一个远程核心"
+#: spyder/plugins/ipythonconsole.py:196
+msgid "This is a remote kernel (via SSH)"
+msgstr "这是一个远程 IPython kernel(SSH)"
+
+#: spyder/plugins/ipythonconsole.py:199
+msgid ""
+"Note: If connecting to a remote kernel, only the SSH keyfile or"
+"i> the Password field need to be completed, unless the keyfile is protected "
+"with a passphrase."
+msgstr ""
+"注意:如果连接远程IPython kernel,只有SSH密钥文件或密码字段需要"
+"填写,除非密钥文件被密码保护。"
+#: spyder/plugins/ipythonconsole.py:207
msgid "username@hostname:port"
msgstr "username@hostname:port"
-msgid "Path to ssh key file"
-msgstr "ssh密钥文件路径"
+#: spyder/plugins/ipythonconsole.py:210
+msgid "Remote user password or SSH keyfile passphrase"
+msgstr "远程用户密码或SSH密钥文件密码"
-msgid "Password or ssh key passphrase"
-msgstr "密码或SSH密钥口令"
+#: spyder/plugins/ipythonconsole.py:215
+msgid "Path to SSH keyfile (optional)"
+msgstr "SSH密钥文件路径(可选)"
-msgid "Host name"
-msgstr "主机名"
+#: spyder/plugins/ipythonconsole.py:224
+msgid "Host name:"
+msgstr "主机名:"
-msgid "Ssh key"
-msgstr "ssh密钥"
+#: spyder/plugins/ipythonconsole.py:225
+msgid "Password:"
+msgstr "密码:"
-msgid "Password"
-msgstr "密码"
+#: spyder/plugins/ipythonconsole.py:226
+msgid "SSH keyfile:"
+msgstr "SSH密钥文件:"
-msgid "Open connection file"
-msgstr "打开连接文件"
+#: spyder/plugins/ipythonconsole.py:257
+msgid "Select kernel connection file"
+msgstr "选择 IPython kernel 连接文件"
-msgid "Select ssh key"
-msgstr "选择SSH密钥"
+#: spyder/plugins/ipythonconsole.py:262
+msgid "Select SSH keyfile"
+msgstr "选择SSH密钥文件"
+#: spyder/plugins/ipythonconsole.py:295 spyder/plugins/ipythonconsole.py:780
msgid "IPython console"
msgstr "IPython控制台"
+#: spyder/plugins/ipythonconsole.py:302
msgid "Display initial banner"
msgstr "显示初始banner"
+#: spyder/plugins/ipythonconsole.py:303
+msgid ""
+"This option lets you hide the message shown at\n"
+"the top of the console when it's opened."
+msgstr "此选项让您隐藏控制台开启时顶端的消息。"
+
+#: spyder/plugins/ipythonconsole.py:305
msgid "Use a pager to display additional text inside the console"
msgstr "使用呼叫器以使控制台上显示附加文本"
+#: spyder/plugins/ipythonconsole.py:307
+msgid ""
+"Useful if you don't want to fill the console with long help or completion "
+"texts.\n"
+"Note: Use the Q key to get out of the pager."
+msgstr ""
+"如果您不想终端被长帮助或补全文本填充时很有用。\n"
+"注意:使用Q键退出。"
+
+#: spyder/plugins/ipythonconsole.py:312
msgid "Ask for confirmation before closing"
msgstr "在关闭之前要求确认"
+#: spyder/plugins/ipythonconsole.py:315
+msgid "Ask for confirmation before removing all user-defined variables"
+msgstr "在移除所有用户定义变量前询问"
+
+#: spyder/plugins/ipythonconsole.py:318
+msgid ""
+"This option lets you hide the warning message shown\n"
+"when resetting the namespace from Spyder."
+msgstr "该选项使您能隐藏重置Spyder命名空间时的警告信息。"
+
+#: spyder/plugins/ipythonconsole.py:320
+#: spyder/widgets/ipythonconsole/client.py:356
+msgid "Show elapsed time"
+msgstr "显示耗时"
+
+#: spyder/plugins/ipythonconsole.py:322
+msgid "Ask for confirmation before restarting"
+msgstr "在重新启动之前要求确认"
+
+#: spyder/plugins/ipythonconsole.py:324
+msgid ""
+"This option lets you hide the warning message shown\n"
+"when restarting the kernel."
+msgstr "该选项会让您隐藏重启 IPython kernel 时的警告信息。"
+
+#: spyder/plugins/ipythonconsole.py:337
msgid "Completion Type"
msgstr "完成类型"
+#: spyder/plugins/ipythonconsole.py:338
msgid "Decide what type of completion to use"
msgstr "在完成时决定使用什么类型"
+#: spyder/plugins/ipythonconsole.py:340
msgid "Graphical"
msgstr "图形"
+#: spyder/plugins/ipythonconsole.py:340
msgid "Plain"
-msgstr ""
+msgstr "原始"
+
+#: spyder/plugins/ipythonconsole.py:340
+msgid "Terminal"
+msgstr "终端"
+#: spyder/plugins/ipythonconsole.py:341
msgid "Completion:"
msgstr "完成:"
-msgid "Light background"
-msgstr "浅背景"
-
-msgid "Dark background"
-msgstr "深色背景"
+#: spyder/plugins/ipythonconsole.py:351
+msgid " lines"
+msgstr " 行"
+#: spyder/plugins/ipythonconsole.py:351
msgid "Buffer: "
-msgstr "缓冲区:"
+msgstr "缓冲区: "
+
+#: spyder/plugins/ipythonconsole.py:353
+msgid ""
+"Set the maximum number of lines of text shown in the\n"
+"console before truncation. Specifying -1 disables it\n"
+"(not recommended!)"
+msgstr ""
+"设置控制台显示的最大行数,超出部分将会被截断。\n"
+"设置为-1可禁用截断(不推荐)。"
+#: spyder/plugins/ipythonconsole.py:362
msgid "Support for graphics (Matplotlib)"
msgstr "图形 (Matplotlib) 支持"
+#: spyder/plugins/ipythonconsole.py:363
msgid "Activate support"
msgstr "激活的支持"
+#: spyder/plugins/ipythonconsole.py:364
msgid "Automatically load Pylab and NumPy modules"
msgstr "自动加载PyLab和NumPy模块"
+#: spyder/plugins/ipythonconsole.py:367
+msgid ""
+"This lets you load graphics support without importing \n"
+"the commands to do plots. Useful to work with other\n"
+"plotting libraries different to Matplotlib or to develop \n"
+"GUIs with Spyder."
+msgstr ""
+"这会让您不导入命令的情况下绘制图形。\n"
+"在使用matplotlib以外的绘图库或开发GUI时很有用。"
+
+#: spyder/plugins/ipythonconsole.py:382
msgid "Inline"
msgstr "内联"
+#: spyder/plugins/ipythonconsole.py:383
+msgid "Automatic"
+msgstr "自动"
+
+#: spyder/plugins/ipythonconsole.py:384
msgid "Graphics backend"
msgstr "图形的后端"
+#: spyder/plugins/ipythonconsole.py:385
msgid ""
-"Decide how graphics are going to be displayed in the console. If unsure, please select %s to put graphics "
-"inside the console or %s to interact with them (through zooming and panning) in a separate window."
+"Decide how graphics are going to be displayed in the console. If unsure, "
+"please select %s to put graphics inside the console or %s to "
+"interact with them (through zooming and panning) in a separate window."
msgstr ""
+"确定如何在控制台中显示图形。 如果不确定,请选择%s将图形放入控制台或"
+"%s以在单独的窗口中与它们进行交互(如缩放和平移)。"
+#: spyder/plugins/ipythonconsole.py:405
+msgid "Backend:"
+msgstr "后端:"
+
+#: spyder/plugins/ipythonconsole.py:407
+msgid "This option will be applied the next time a console is opened."
+msgstr "此选项将会应用在下次打开控制台。"
+
+#: spyder/plugins/ipythonconsole.py:418
msgid "Inline backend"
msgstr "内联后端"
+#: spyder/plugins/ipythonconsole.py:419
msgid "Decide how to render the figures created by this backend"
msgstr "决定如何渲染这个后端创建的图形"
+#: spyder/plugins/ipythonconsole.py:423
msgid "Format:"
msgstr "格式:"
+#: spyder/plugins/ipythonconsole.py:427
msgid "Resolution:"
msgstr "分辨率:"
+#: spyder/plugins/ipythonconsole.py:427
msgid "dpi"
-msgstr "DPI"
+msgstr "dpi"
+#: spyder/plugins/ipythonconsole.py:429
msgid "Only used when the format is PNG. Default is 72"
-msgstr "只有使用的格式是PNG。默认值是72"
+msgstr "只有在格式是PNG时使用。默认值是72"
+#: spyder/plugins/ipythonconsole.py:432
msgid "Width:"
msgstr "宽:"
+#: spyder/plugins/ipythonconsole.py:432 spyder/plugins/ipythonconsole.py:436
msgid "inches"
msgstr "英寸"
+#: spyder/plugins/ipythonconsole.py:434
msgid "Default is 6"
msgstr "默认值是6"
+#: spyder/plugins/ipythonconsole.py:436
msgid "Height:"
msgstr "高度:"
+#: spyder/plugins/ipythonconsole.py:438
msgid "Default is 4"
msgstr "默认值是4"
+#: spyder/plugins/ipythonconsole.py:440
+msgid "Use a tight layout for inline plots"
+msgstr "为嵌入绘图使用紧凑布局"
+
+#: spyder/plugins/ipythonconsole.py:442
+msgid ""
+"Sets bbox_inches to \"tight\" when\n"
+"plotting inline with matplotlib.\n"
+"When enabled, can cause discrepancies\n"
+"between the image displayed inline and\n"
+"that created using savefig."
+msgstr ""
+"绘制嵌入Matplotlib图形时,设置bbox_inches为\"tight\"。\n"
+"启用后,可能造成显示的图形与通过savefig保存的图片不一致。"
+
+#: spyder/plugins/ipythonconsole.py:475
msgid ""
-"You can run several lines of code when a console is started. Please introduce each one separated by commas, for "
-"example:
import os, import sys"
+"You can run several lines of code when a console is started. Please "
+"introduce each one separated by commas, for example:
import os, import "
+"sys"
msgstr ""
+"启动控制台时,您可以通过逗号分隔的多条语句运行多行代码。 例如:
"
+"import os, import sys "
+#: spyder/plugins/ipythonconsole.py:481
msgid "Lines:"
msgstr "行:"
+#: spyder/plugins/ipythonconsole.py:490
msgid "Run a file"
msgstr "运行一个文件"
+#: spyder/plugins/ipythonconsole.py:491
msgid ""
-"You can also run a whole file at startup instead of just some lines (This is similar to have a PYTHONSTARTUP "
-"file)."
-msgstr "你也可以在不只是一些线启动运行整个文件(这是类似于一个pythonstartup文件)。"
+"You can also run a whole file at startup instead of just some lines (This is "
+"similar to have a PYTHONSTARTUP file)."
+msgstr ""
+"你也可以在启动时运行整个文件而不是其中几行(这是一个类似于PYTHONSTARTUP的文"
+"件)。"
+#: spyder/plugins/ipythonconsole.py:495
msgid "Use the following file:"
msgstr "使用下列文件:"
-msgid "Greedy completion"
-msgstr ""
+#: spyder/plugins/ipythonconsole.py:509
+msgid "Jedi completion"
+msgstr "Jedi补全"
+#: spyder/plugins/ipythonconsole.py:510
msgid ""
-"Enable Tab completion on elements of lists, results of function calls, etc, without assigning "
-"them to a variable.
For example, you can get completions on things like li[0].<Tab> or ins."
-"meth().<Tab>"
+"Enable Jedi-based Tab completion in the IPython console; similar to "
+"the greedy completer, but without evaluating the code.
Warning: "
+"Slows down your console when working with large dataframes!"
msgstr ""
+"在IPython中启用基于Jedi的Tab补全;和贪心补全类似,但不会实际执行代"
+"码。
警告:会让您的控制台在处理大DataFrames时效率低下!"
-msgid "Use the greedy completer"
-msgstr ""
+#: spyder/plugins/ipythonconsole.py:517
+msgid "Use Jedi completion in the IPython console"
+msgstr "在IPython控制台使用Jedi补全"
+
+#: spyder/plugins/ipythonconsole.py:530
+msgid "Greedy completion"
+msgstr "贪心补全"
+#: spyder/plugins/ipythonconsole.py:531
+msgid ""
+"Enable Tab completion on elements of lists, results of function "
+"calls, etc, without assigning them to a variable, like li[0].<"
+"Tab> or ins.meth().<Tab>
Warning: Due to a "
+"bug, IPython's greedy completer requires a leading <Space> "
+"for some completions; e.g. np.sin(<Space>np.<Tab> "
+"works while np.sin(np.<Tab> doesn't."
+msgstr ""
+"在列表元素,函数调用结果等上启用 Tab 完成,而不用将它们分配给"
+"变量。
例如,您可以在诸如 li [0].&lt;Tab&gt; 或 ins.meth()."
+"&lt;Tab&gt; 之类的内容上获得补全。
警告: 由于BUG, IPython的"
+"greedy补全在某些情景下需要一个 <Space>开头; 例如, np."
+"sin(<Space>np.<Tab> 没问题, 但np.sin(np.<Tab> "
+"tt> 不行。"
+
+#: spyder/plugins/ipythonconsole.py:543
+msgid "Use greedy completion in the IPython console"
+msgstr "在IPython控制台使用greedy补全"
+
+#: spyder/plugins/ipythonconsole.py:555
msgid "Autocall"
msgstr "自动调用"
+#: spyder/plugins/ipythonconsole.py:556
msgid ""
-"Autocall makes IPython automatically call any callable object even if you didn't type explicit parentheses."
-"
For example, if you type str 43 it becomes str(43) automatically."
+"Autocall makes IPython automatically call any callable object even if you "
+"didn't type explicit parentheses.
For example, if you type str 43 "
+"it becomes str(43) automatically."
msgstr ""
+"即使您没有键入显式括号,Autocall也会使IPython自动调用任何可调用对象。
例"
+"如,如果键入 str 43 ,它将自动变为 str(43)。"
+#: spyder/plugins/ipythonconsole.py:563
msgid "Smart"
-msgstr ""
+msgstr "智能"
+#: spyder/plugins/ipythonconsole.py:564
msgid "Full"
-msgstr ""
+msgstr "完全"
+#: spyder/plugins/ipythonconsole.py:565
msgid "Off"
msgstr "关闭"
+#: spyder/plugins/ipythonconsole.py:567
msgid "Autocall: "
-msgstr "自动调用:"
+msgstr "自动调用: "
+#: spyder/plugins/ipythonconsole.py:568
msgid ""
-"On %s mode, Autocall is not applied if there are no arguments after the callable. On %s mode, all "
-"callable objects are automatically called (even if no arguments are present)."
+"On %s mode, Autocall is not applied if there are no arguments after "
+"the callable. On %s mode, all callable objects are automatically "
+"called (even if no arguments are present)."
msgstr ""
+"在%s 模式下,如果可调用对象后没有参数,则不应用自动调用。 在%s "
+"b>模式下,将自动调用所有可调用对象(即使不存在任何参数)。"
+#: spyder/plugins/ipythonconsole.py:580
msgid "Symbolic Mathematics"
-msgstr "符号数学"
+msgstr "符号化运算"
+#: spyder/plugins/ipythonconsole.py:581
msgid ""
-"Perfom symbolic operations in the console (e.g. integrals, derivatives, vector calculus, etc) and get the outputs "
-"in a beautifully printed style (it requires the Sympy module)."
+"Perfom symbolic operations in the console (e.g. integrals, derivatives, "
+"vector calculus, etc) and get the outputs in a beautifully printed style (it "
+"requires the Sympy module)."
msgstr ""
+"在控制台中使用符号化运算(例如积分,导数,矢量微积分等),并以精美的打印样式"
+"获得输出(它需要Sympy模块)。"
+#: spyder/plugins/ipythonconsole.py:586
msgid "Use symbolic math"
-msgstr "使用符号数学"
+msgstr "使用符号化运算"
+#: spyder/plugins/ipythonconsole.py:587
msgid ""
-"This option loads the Sympy library to work with.
Please refer to its documentation to learn how to use it."
-msgstr ""
+"This option loads the Sympy library to work with.
Please refer to its "
+"documentation to learn how to use it."
+msgstr "此选项需要加载 Sympy 模块以工作。
请参阅其文档以了解如何使用它。"
+#: spyder/plugins/ipythonconsole.py:597
msgid "Prompts"
msgstr "提示"
+#: spyder/plugins/ipythonconsole.py:598
msgid "Modify how Input and Output prompts are shown in the console."
msgstr "修改控制台中显示的输入和输出提示。"
+#: spyder/plugins/ipythonconsole.py:601
msgid "Input prompt:"
-msgstr "输入提示:"
+msgstr "输入提示符:"
-msgid "Default is
In [<span class=\"in-prompt-number\">%i</span>]:"
+#: spyder/plugins/ipythonconsole.py:603
+msgid ""
+"Default is
In [<span class=\"in-prompt-number\">%i</span>]:"
msgstr ""
+"默认值是
输入 [<span class=\"in-prompt-number\">%i</span>]:"
+#: spyder/plugins/ipythonconsole.py:607
msgid "Output prompt:"
-msgstr "输出提示:"
+msgstr "输出提示符:"
-msgid "Default is
Out[<span class=\"out-prompt-number\">%i</span>]:"
+#: spyder/plugins/ipythonconsole.py:609
+msgid ""
+"Default is
Out[<span class=\"out-prompt-number\">%i</span>]:"
msgstr ""
+"默认值是
输出[<span class=\"out-prompt-number\">%i</span>]:"
+
+#: spyder/plugins/ipythonconsole.py:629
+msgid "Graphics"
+msgstr "绘图"
+#: spyder/plugins/ipythonconsole.py:631
msgid "Startup"
msgstr "启动"
+#: spyder/plugins/ipythonconsole.py:658
+msgid ""
+"The directory {} is not writable and it is required to create IPython "
+"consoles. Please make it writable."
+msgstr "目录{}不可写,如果您需要创建IPython控制台,请让它可写。"
+
+#: spyder/plugins/ipythonconsole.py:831
msgid "Open an &IPython console"
msgstr "打开一个IPython控制台(&I)"
+#: spyder/plugins/ipythonconsole.py:838
msgid "Restart kernel"
-msgstr "重启内核"
+msgstr "重启 IPython kernel"
+#: spyder/plugins/ipythonconsole.py:847
msgid "Open a new IPython console connected to an existing kernel"
-msgstr "打开一个新IPython控制台以连接到一个现有内核"
+msgstr "打开一个新 IPython 控制台以连接到一个现有的 IPython kernel"
-msgid "No IPython console is currently available to run %s.
Please open a new one and try again."
-msgstr "当前没有可用IPython控制台来运行%s.
请打开一个新的并且重试。"
+#: spyder/plugins/ipythonconsole.py:850
+msgid "Rename tab"
+msgstr "重命名标签"
-msgid "The directory {} is not writable and it is required to create IPython consoles. Please make it writable."
+#: spyder/plugins/ipythonconsole.py:968
+msgid ""
+"
Please exit from debugging before trying to run a file in this "
+"console.\n"
+"
"
msgstr ""
+"
请在尝试在控制台运行一个文件前退出调试。\n"
+"
"
+#: spyder/plugins/ipythonconsole.py:988
msgid ""
-"Your Python environment or installation doesn't have the ipykernel module installed on it. Without this "
-"module is not possible for Spyder to create a console for you.
You can install ipykernel by "
-"running in a terminal:
pip install ipykernel
or
conda install ipykernel"
+"No IPython console is currently available to run %s.
Please "
+"open a new one and try again."
msgstr ""
+"当前没有可用IPython控制台来运行%s.
请打开一个新的并且重试。"
+#: spyder/plugins/ipythonconsole.py:1096
+msgid ""
+"Your Python environment or installation doesn't have the spyder-kernels"
+"tt> module or the right version of it installed. Without this module is not "
+"possible for Spyder to create a console for you.
You can install it "
+"by running in a system terminal:
conda install spyder-kernels=0."
+"*
or
pip install spyder-kernels==0.*"
+msgstr ""
+"您的Python环境没有安装spyder-kernels模块或模块版本不正确。 如果没有"
+"此模块,Spyder无法为您创建控制台。
您可以在终端中输入下面的命令来安"
+"装:
conda install spyder-kernels=0.*
或"
+"
pip install spyder-kernels==0.*"
+
+#: spyder/plugins/ipythonconsole.py:1362
msgid "Do you want to close this console?"
-msgstr "你想关闭当前控制台吗?"
+msgstr "您想关闭当前控制台吗?"
-msgid "Do you want to close all other consoles connected to the same kernel as this one?"
-msgstr ""
+#: spyder/plugins/ipythonconsole.py:1368
+msgid ""
+"Do you want to close all other consoles connected to the same kernel as this "
+"one?"
+msgstr "是否要关闭连接到同一 IPython kernel 的所有其他控制台?"
-msgid "It was not possible to restart the IPython console when switching to this project. The error was {0}"
-msgstr ""
+#: spyder/plugins/ipythonconsole.py:1440
+msgid ""
+"It was not possible to restart the IPython console when switching to this "
+"project. The error was
{0}"
+msgstr "正在切换到此项目时无法重新启动IPython控制台。 错误
{0}"
+#: spyder/plugins/ipythonconsole.py:1546 spyder/plugins/ipythonconsole.py:1556
+msgid "The error is:
{}"
+msgstr "错误:
{}"
+
+#: spyder/plugins/ipythonconsole.py:1742
msgid "IPython"
msgstr "IPython"
+#: spyder/plugins/ipythonconsole.py:1743
msgid "Unable to connect to %s"
msgstr "无法连接到%s"
+#: spyder/plugins/ipythonconsole.py:1819
msgid "Connection error"
msgstr "连接错误"
+#: spyder/plugins/ipythonconsole.py:1820
+msgid ""
+"Could not open ssh tunnel. The error was:\n"
+"\n"
+msgstr ""
+"无法打开SSH隧道。错误:\n"
+"\n"
+
+#: spyder/plugins/layoutdialog.py:177
msgid "Move Up"
msgstr "上移"
+#: spyder/plugins/layoutdialog.py:178
msgid "Move Down"
msgstr "下移"
+#: spyder/plugins/layoutdialog.py:179
msgid "Delete Layout"
msgstr "删除布局"
+#: spyder/plugins/layoutdialog.py:183
msgid "Layout Display and Order"
msgstr "显示和调整布局"
+#: spyder/plugins/maininterpreter.py:31 spyder/plugins/maininterpreter.py:71
msgid "Python interpreter"
msgstr "Python解释器"
+#: spyder/plugins/maininterpreter.py:73
msgid "Select the Python interpreter for all Spyder consoles"
msgstr "为所有Spyder控制台选择Python解释器"
+#: spyder/plugins/maininterpreter.py:76
msgid "Default (i.e. the same as Spyder's)"
msgstr "默认(即与Spyder的相同)"
+#: spyder/plugins/maininterpreter.py:79
msgid "Use the following Python interpreter:"
msgstr "使用以下的Python解释器:"
+#: spyder/plugins/maininterpreter.py:82
msgid "Executables"
msgstr "可执行程序"
+#: spyder/plugins/maininterpreter.py:92
+msgid "Recent custom interpreters"
+msgstr "最近的自定义解释器"
+
+#: spyder/plugins/maininterpreter.py:107
msgid "User Module Reloader (UMR)"
msgstr "使用模块重载器"
+#: spyder/plugins/maininterpreter.py:108
msgid ""
-"UMR forces Python to reload modules which were imported when executing a file in a Python or IPython console with "
-"the runfile function."
-msgstr "当在Python或Ipython控制台中执行一个文件时,UMR强制Python重载已经引入的模块"
+"UMR forces Python to reload modules which were imported when executing a "
+"file in a Python or IPython console with the runfile function."
+msgstr ""
+"当在Python或IPython控制台中执行一个文件时,UMR强制Python重载已经引入的模块。"
+#: spyder/plugins/maininterpreter.py:113
msgid "Enable UMR"
msgstr "启用UMR"
+#: spyder/plugins/maininterpreter.py:114
msgid ""
-"This option will enable the User Module Reloader (UMR) in Python/IPython consoles. UMR forces Python to reload "
-"deeply modules during import when running a Python script using the Spyder's builtin function runfile."
-"
1. UMR may require to restart the console in which it will be called (otherwise only newly "
-"imported modules will be reloaded when executing files).
2. If errors occur when re-running a PyQt-"
-"based program, please check that the Qt objects are properly destroyed (e.g. you may have to use the attribute "
-"Qt.WA_DeleteOnClose on your main window, using the setAttribute method)"
-msgstr ""
-
+"This option will enable the User Module Reloader (UMR) in Python/IPython "
+"consoles. UMR forces Python to reload deeply modules during import when "
+"running a Python script using the Spyder's builtin function runfile."
+"
1. UMR may require to restart the console in which it will be "
+"called (otherwise only newly imported modules will be reloaded when "
+"executing files).
2. If errors occur when re-running a PyQt-"
+"based program, please check that the Qt objects are properly destroyed (e.g. "
+"you may have to use the attribute Qt.WA_DeleteOnClose on your main "
+"window, using the setAttribute method)"
+msgstr ""
+"此选项将启用Python / IPython控制台中的 User Module Reloader(UMR)。 当使用"
+"Spyder的内置函数 runfile 运行Python脚本时,UMR强制Python在导入期间重新"
+"加载模块。
1, 启用UMR需要重启现有的控制台,否则它只会在新建"
+"的控制台生效。
2,如果重新运行基于PyQt的程序时发生错误,请检"
+"查 Qt对象被正确销毁(例如,您可能必须在主窗口上使用属性 Qt."
+"WA_DeleteOnClose ,通过 setAttribute 方法设置)"
+
+#: spyder/plugins/maininterpreter.py:130
msgid "Show reloaded modules list"
msgstr "显示重载的模块列表"
+#: spyder/plugins/maininterpreter.py:131
msgid "Please note that these changes will be applied only to new consoles"
msgstr "请注意,这些更改将只适用于新的控制台"
+#: spyder/plugins/maininterpreter.py:135
msgid "Set UMR excluded (not reloaded) modules"
msgstr "设置UMR例外(不重载)模块"
+#: spyder/plugins/maininterpreter.py:163
msgid ""
-"You selected an invalid Python interpreter for the console so the previous interpreter will stay. Please make "
-"sure to select a valid one."
-msgstr "您为控制台选择了一个无效的Python解释器,为使上一个解释器驻留,请务必选择一个有效的。"
-
-msgid ""
-"You selected a Python %d interpreter for the console but Spyder is running on Python %d!."
-"
Although this is possible, we recommend you to install and run Spyder directly with your selected "
-"interpreter, to avoid seeing false warnings and errors due to the incompatible syntax between these two Python "
-"versions."
+"You selected an invalid Python interpreter for the console so the previous "
+"interpreter will stay. Please make sure to select a valid one."
msgstr ""
+"您为控制台选择了一个无效的Python解释器,为使上一个解释器驻留,请务必选择一个"
+"有效的。"
+#: spyder/plugins/maininterpreter.py:184
+msgid ""
+"You selected a Python %d interpreter for the console but Spyder is "
+"running on Python %d!.
Although this is possible, we recommend "
+"you to install and run Spyder directly with your selected interpreter, to "
+"avoid seeing false warnings and errors due to the incompatible syntax "
+"between these two Python versions."
+msgstr ""
+"您为控制台选择了Python %d解释器,但Spyder运行于Python %d ! "
+"
虽然这是可行的,但我们建议您使用您选择的解释器安装和运行Spyder,以避"
+"免由于这两个Python版本之间的语法不兼容而看到错误警告和错误。"
+
+#: spyder/plugins/maininterpreter.py:195 spyder/plugins/maininterpreter.py:222
+#: spyder/plugins/maininterpreter.py:226
msgid "UMR"
msgstr "UMR"
+#: spyder/plugins/maininterpreter.py:196
msgid "Set the list of excluded modules as this: numpy, scipy"
msgstr "设置排除模块的列表,例如:numpy, scipy"
+#: spyder/plugins/maininterpreter.py:213
msgid ""
-"You are working with Python 2, this means that you can not import a module that contains non-ascii characters."
+"You are working with Python 2, this means that you can not import a module "
+"that contains non-ascii characters."
msgstr "您正在使用Python 2,这意味着您不能导入包含非ASCII字符的模块。"
-msgid "Please note that these changes will be applied only to new Python/IPython consoles"
+#: spyder/plugins/maininterpreter.py:223
+msgid ""
+"The following modules are not installed on your machine:\n"
+"%s"
+msgstr ""
+"下面的模块没有在您的计算机上安装:\n"
+"%s"
+
+#: spyder/plugins/maininterpreter.py:227
+msgid ""
+"Please note that these changes will be applied only to new Python/IPython "
+"consoles"
msgstr "请注意,这些变化将只适用于新的Python / IPython控制台"
+#: spyder/plugins/onlinehelp.py:70
msgid "Online help"
msgstr "在线帮助"
+#: spyder/plugins/outlineexplorer.py:48 spyder/widgets/editortools.py:194
msgid "Outline"
-msgstr "概述"
+msgstr "大纲"
+#: spyder/plugins/projects.py:77 spyder/widgets/projects/explorer.py:112
+#: spyder/widgets/projects/explorer.py:126
msgid "Project explorer"
msgstr "项目资源管理器"
+#: spyder/plugins/projects.py:89
msgid "New Project..."
msgstr "新项目…"
+#: spyder/plugins/projects.py:92
msgid "Open Project..."
msgstr "打开项目…"
+#: spyder/plugins/projects.py:95
msgid "Close Project"
msgstr "关闭项目"
+#: spyder/plugins/projects.py:98
msgid "Delete Project"
msgstr "删除项目"
+#: spyder/plugins/projects.py:104
msgid "Project Preferences"
msgstr "项目参数"
+#: spyder/plugins/projects.py:106
msgid "Recent Projects"
msgstr "最近的项目"
+#: spyder/plugins/projects.py:264
msgid "Open project"
msgstr "打开项目"
+#: spyder/plugins/projects.py:270
msgid "%s is not a Spyder project!"
-msgstr "%s不是一个Spyder项目"
+msgstr "%s不是一个Spyder项目!"
-msgid "Execute in current Python or IPython console"
-msgstr "执行当前Python或IPython控制台"
+#: spyder/plugins/runconfig.py:29
+msgid "Execute in current console"
+msgstr "在当前控制台执行"
-msgid "Execute in a new dedicated Python console"
-msgstr "在一个新的专用Python控制台执行"
+#: spyder/plugins/runconfig.py:30
+msgid "Execute in a dedicated console"
+msgstr "在专用控制台执行"
-msgid "Execute in an external System terminal"
-msgstr "在外部系统终端执行"
+#: spyder/plugins/runconfig.py:31
+msgid "Execute in an external system terminal"
+msgstr "在系统终端执行"
+#: spyder/plugins/runconfig.py:42
msgid "Always show %s on a first file run"
msgstr "在第一次执行脚本时总是显示 %s"
-msgid "Clear all variables before execution (IPython consoles)"
-msgstr "执行前清理所有变量(IPython控制台)"
+#: spyder/plugins/runconfig.py:45
+msgid "Remove all variables before execution"
+msgstr "执行前清理所有变量"
+
+#: spyder/plugins/runconfig.py:46
+msgid "Directly enter debugging when errors appear"
+msgstr "出现错误时直接进入调试"
+#: spyder/plugins/runconfig.py:47
+msgid "Interact with the Python console after execution"
+msgstr "执行后保留Python控制台"
+
+#: spyder/plugins/runconfig.py:49
+msgid "The directory of the file being executed"
+msgstr "正在执行的文件所在的目录"
+
+#: spyder/plugins/runconfig.py:50 spyder/plugins/workingdirectory.py:56
+msgid "The current working directory"
+msgstr "当前工作目录"
+
+#: spyder/plugins/runconfig.py:51
+msgid "The following directory:"
+msgstr "指定目录:"
+
+#: spyder/plugins/runconfig.py:184 spyder/plugins/runconfig.py:504
msgid "General settings"
msgstr "一般设置"
+#: spyder/plugins/runconfig.py:194 spyder/plugins/runconfig.py:236
msgid "Command line options:"
msgstr "命令行选项:"
-msgid "Working directory:"
-msgstr "工作目录:"
-
-msgid "Enter debugging mode when errors appear during execution"
-msgstr "在执行过程中出现错误时输入调试模式"
-
-msgid "Dedicated Python console"
-msgstr "专用的Python控制台"
-
-msgid "Interact with the Python console after execution"
-msgstr "与Python控制台执行后"
+#: spyder/plugins/runconfig.py:202 spyder/plugins/runconfig.py:514
+msgid "Working Directory settings"
+msgstr "工作目录设置"
-msgid "Show warning when killing running process"
-msgstr "在运行过程中显示警告"
+#: spyder/plugins/runconfig.py:226 spyder/plugins/runconfig.py:548
+msgid "External system terminal"
+msgstr "系统终端"
+#: spyder/plugins/runconfig.py:241
msgid "-u is added to the other options you set here"
-msgstr "-u已经添加到你设置的其他选项中"
+msgstr "-u已经添加到您设置的其他选项中"
+#: spyder/plugins/runconfig.py:250
msgid "this dialog"
msgstr "这个对话框"
+#: spyder/plugins/runconfig.py:315
msgid "Run configuration"
msgstr "运行配置"
+#: spyder/plugins/runconfig.py:316
msgid "The following working directory is not valid:
%s"
msgstr "以下工作目录不可用:
%s"
+#: spyder/plugins/runconfig.py:394
msgid "Run settings for %s"
msgstr "为%s执行配置"
+#: spyder/plugins/runconfig.py:426
msgid "Select a run configuration:"
msgstr "选择运行配置:"
-msgid "Run Settings"
-msgstr "运行设置"
+#: spyder/plugins/runconfig.py:455
+msgid "Run configuration per file"
+msgstr "单文件运行配置"
+#: spyder/plugins/runconfig.py:480
msgid ""
-"The following are the default %s. These options may be overriden using the %s dialog box (see the "
-"%s menu)"
-msgstr "以下是%s的缺省设置。这些选项可以使用%s对话框来重设。(请看%s 菜单)"
+"The following are the default options for running files.These options may be "
+"overriden using the Configuration per file entry of the Run "
+"menu."
+msgstr ""
+"以下是运行文件的默认选项。可以使用运行菜单的单文件配置覆盖这些"
+"选项。"
+#: spyder/plugins/runconfig.py:516
msgid "Default working directory is:"
msgstr "缺省工作目录是:"
-msgid "the script directory"
-msgstr "剧本目录"
+#: spyder/plugins/runconfig.py:556
+msgid "Run Settings dialog"
+msgstr "运行设置对话框"
-msgid "the following directory:"
-msgstr "以下目录:"
+#: spyder/plugins/shortcuts.py:65
+msgid "Currently used to delete lines on editor/Cut a word"
+msgstr ""
-msgid "Show warning when killing running processes"
-msgstr "结束运行进程时显示警告"
+#: spyder/plugins/shortcuts.py:66
+msgid "Currently used to paste a word"
+msgstr ""
-msgid "Run Settings dialog"
-msgstr "运行设置对话框"
+#: spyder/plugins/shortcuts.py:70
+msgid "We cannot support this shortcut on Windows"
+msgstr "我们无法在windows上支持这个快捷键"
+
+#: spyder/plugins/shortcuts.py:73
+msgid "Shortcuts that use Shift and another key are unsupported"
+msgstr "不支持这个使用了Shift和另一个键的快捷键"
+#: spyder/plugins/shortcuts.py:150
+msgid ""
+"Press the new shortcut and select 'Ok': \n"
+"(Press 'Tab' once to switch focus between the shortcut entry \n"
+"and the buttons below it)"
+msgstr ""
+"按下新快捷键然后选择'Ok':\n"
+"(按下 'Tab' 切换快捷键条目与下面的按钮)"
+
+#: spyder/plugins/shortcuts.py:153
msgid "Current shortcut:"
-msgstr "运行设置对话框"
+msgstr "当前快捷键:"
+#: spyder/plugins/shortcuts.py:155
msgid "New shortcut:"
msgstr "新快捷键:"
+#: spyder/plugins/shortcuts.py:168
msgid "Shortcut: {0}"
msgstr "快捷方式:{0}"
+#: spyder/plugins/shortcuts.py:307
msgid "Please introduce a different shortcut"
msgstr "请引用一个不同的快捷方式"
-msgid "The new shorcut conflicts with:"
-msgstr ""
+#: spyder/plugins/shortcuts.py:344
+msgid "The new shortcut conflicts with:"
+msgstr "快捷键冲突:"
-msgid "A compound sequence can have {break} a maximum of 4 subsequences.{break}"
-msgstr ""
+#: spyder/plugins/shortcuts.py:353 spyder/plugins/shortcuts.py:362
+msgid "Forbidden key sequence!"
+msgstr "禁止的键序列!"
+
+#: spyder/plugins/shortcuts.py:373
+msgid ""
+"A compound sequence can have {break} a maximum of 4 subsequences.{break}"
+msgstr "复合序列可以有{break}最多4个子序列。{break}"
+#: spyder/plugins/shortcuts.py:378
msgid "Invalid key entered"
msgstr "无效键输入"
+#: spyder/plugins/shortcuts.py:585
msgid "Context"
msgstr "语境"
+#: spyder/plugins/shortcuts.py:587
+#: spyder/widgets/variableexplorer/collectionseditor.py:153
msgid "Name"
msgstr "名称"
+#: spyder/plugins/shortcuts.py:589
msgid "Shortcut"
msgstr "快捷方式"
+#: spyder/plugins/shortcuts.py:591
msgid "Score"
msgstr "分数"
+#: spyder/plugins/shortcuts.py:752
msgid "Conflicts"
msgstr "冲突"
+#: spyder/plugins/shortcuts.py:753
msgid "The following conflicts have been detected:"
msgstr "已检测到下列冲突:"
+#: spyder/plugins/shortcuts.py:838
msgid "Keyboard shortcuts"
msgstr "键盘快捷键"
+#: spyder/plugins/shortcuts.py:846
msgid "Search: "
-msgstr "搜索:"
+msgstr "搜索: "
+#: spyder/plugins/shortcuts.py:847
msgid "Reset to default values"
msgstr "重置为默认值"
-msgid "Autorefresh"
-msgstr "自动刷新"
+#: spyder/plugins/shortcuts.py:877
+msgid "Shortcuts reset"
+msgstr "重置快捷键"
-msgid "Enable autorefresh"
-msgstr "启用自动刷新"
+#: spyder/plugins/shortcuts.py:878
+msgid "Do you want to reset to default values?"
+msgstr "您想要重置为默认值吗?"
-msgid "Refresh interval: "
-msgstr "刷新间隔:"
+#: spyder/plugins/variableexplorer.py:24
+msgid "View and edit DataFrames and Series in the Variable Explorer"
+msgstr "在变量管理器里查看和编辑DataFrames与Series"
+
+#: spyder/plugins/variableexplorer.py:29
+msgid "View and edit two and three dimensional arrays in the Variable Explorer"
+msgstr "在变量管理器中查看和编辑二维或三维的数组"
+#: spyder/plugins/variableexplorer.py:37
msgid "Filter"
msgstr "过滤器"
+#: spyder/plugins/variableexplorer.py:39
+#: spyder/widgets/variableexplorer/namespacebrowser.py:203
msgid "Exclude private references"
-msgstr "排除私人资料"
+msgstr "排除私有引用"
+#: spyder/plugins/variableexplorer.py:40
+#: spyder/widgets/variableexplorer/namespacebrowser.py:218
msgid "Exclude capitalized references"
-msgstr "排除投资参考"
+msgstr "排除名字以大写字母开头的引用"
+#: spyder/plugins/variableexplorer.py:41
+#: spyder/widgets/variableexplorer/namespacebrowser.py:211
msgid "Exclude all-uppercase references"
-msgstr "排除所有大写的参考"
+msgstr "排除名字全大写的引用"
+#: spyder/plugins/variableexplorer.py:42
+#: spyder/widgets/variableexplorer/namespacebrowser.py:226
msgid "Exclude unsupported data types"
msgstr "排除不支持的数据类型"
+#: spyder/plugins/variableexplorer.py:48
+#: spyder/widgets/variableexplorer/collectionseditor.py:738
msgid "Show arrays min/max"
-msgstr "显示数组最小/最大"
+msgstr "显示数组最小/最大值"
+#: spyder/plugins/variableexplorer.py:202
msgid "Variable explorer"
-msgstr "变量资源管理器"
+msgstr "变量管理器"
+#: spyder/plugins/workingdirectory.py:39
msgid ""
-"The global working directory is the working directory for newly opened consoles (Python/IPython "
-"consoles and terminals), for the file explorer, for the find in files plugin and for new files "
-"created in the editor."
-msgstr ""
-"对于文件资源管理器,对于在文件中查找插件和在编辑器中新建的文件,全局工作目录是新开"
-"控制台的工作目录(Python/IPython控制台和终端)。"
+"The current working directory is the working directory for IPython "
+"consoles and the current directory for the File Explorer."
+msgstr "当前工作目录是IPython和文件管理器的工作目录。"
-msgid "At startup, the global working directory is:"
-msgstr "启动时,全局工作路径是:"
+#: spyder/plugins/workingdirectory.py:44
+msgid "Console directory"
+msgstr "控制台目录"
-msgid "the same as in last session"
-msgstr "与上次会话相同"
+#: spyder/plugins/workingdirectory.py:45
+msgid "The working directory for new consoles is:"
+msgstr "新终端默认工作目录:"
-msgid "At startup, Spyder will restore the global directory from last session"
-msgstr "在启动时,Spyder将从最后一次会话恢复全局目录"
-
-msgid "At startup, the global working directory will be the specified path"
-msgstr "在启动时,全局工作目录将是指定的路径"
-
-msgid "Files are opened from:"
-msgstr "打开文件自:"
-
-msgid "the current file directory"
-msgstr "当前文件目录"
-
-msgid "the global working directory"
-msgstr "全局工作目录"
-
-msgid "Files are created in:"
-msgstr "文件创建于:"
-
-msgid "Change to file base directory"
-msgstr "更改为文件根目录"
+#: spyder/plugins/workingdirectory.py:49
+msgid ""
+"The current project directory or user home directory (if no project is "
+"active)"
+msgstr "当前项目目录或用户目录(如果没有活动项目)"
-msgid "When opening a file"
-msgstr "打开文件时"
+#: spyder/plugins/workingdirectory.py:62
+msgid "the following directory:"
+msgstr "以下目录:"
-msgid "When saving a file"
-msgstr "保存文件时"
+#: spyder/plugins/workingdirectory.py:64
+msgid "The directory when a new console is open will be the specified path"
+msgstr "打开新控制台时的目录将是指定的路径"
+#: spyder/plugins/workingdirectory.py:124
msgid "Back"
msgstr "后退"
+#: spyder/plugins/workingdirectory.py:130 spyder/widgets/explorer.py:1199
+#: spyder/widgets/variableexplorer/importwizard.py:539
msgid "Next"
msgstr "下一个"
+#: spyder/plugins/workingdirectory.py:141
+msgid ""
+"This is the working directory for newly\n"
+"opened consoles (Python/IPython consoles and\n"
+"terminals), for the file explorer, for the\n"
+"find in files plugin and for new files\n"
+"created in the editor"
+msgstr ""
+"这是新打开的控制台(Python / IPython控制台和终端),\n"
+"文件管理器,“文件中查找”插件和编辑器中新建文件的工作目录"
+
+#: spyder/plugins/workingdirectory.py:166
msgid "Browse a working directory"
msgstr "浏览工作目录"
+#: spyder/plugins/workingdirectory.py:173
msgid "Change to parent directory"
msgstr "更改为父目录"
-msgid "Global working directory"
-msgstr "全局工作目录"
+#: spyder/plugins/workingdirectory.py:180 spyder/widgets/findinfiles.py:240
+msgid "Current working directory"
+msgstr "当前工作目录"
+#: spyder/utils/codeanalysis.py:94
msgid "Real-time code analysis on the Editor"
msgstr "编辑器的实时代码分析"
+#: spyder/utils/codeanalysis.py:98
msgid "Real-time code style analysis on the Editor"
msgstr "编辑器的实时代码风格分析"
+#: spyder/utils/environ.py:48
+msgid "Environment variables"
+msgstr "环境变量"
+
+#: spyder/utils/environ.py:57
msgid ""
-"Module pywin32 was not found.
Please restart this Windows session (not the computer) for changes "
-"to take effect."
-msgstr ""
+"An error occurred while trying to show your environment variables. The error "
+"was
{0}"
+msgstr "尝试显示环境变量时出错:
{0}"
+#: spyder/utils/environ.py:108
msgid ""
-"If you accept changes, this will modify the current user environment variables directly in Windows registry"
-"b>. Use it with precautions, at your own risks.
Note that for changes to take effect, you will need to "
-"restart the parent process of this application (simply restart Spyder if you have executed it from a Windows "
-"shortcut, otherwise restart any application from which you may have executed it, like Python(x,y) Home for "
-"example)"
+"Module pywin32 was not found.
Please restart this Windows "
+"session (not the computer) for changes to take effect."
msgstr ""
+"模块pywin32未找到。
请重启当前Windows会话(而不是重启电脑)"
+"来使改变生效。"
-msgid "It was not possible to generate rich text help for this object.Please see it in plain text."
+#: spyder/utils/environ.py:121
+msgid ""
+"If you accept changes, this will modify the current user environment "
+"variables directly in Windows registry. Use it with precautions, at "
+"your own risks.
Note that for changes to take effect, you will need "
+"to restart the parent process of this application (simply restart Spyder if "
+"you have executed it from a Windows shortcut, otherwise restart any "
+"application from which you may have executed it, like Python(x,y) Home"
+"i> for example)"
+msgstr ""
+"如果您接受更改,这将直接在Windows注册表中修改当前用户环境变量。 使用前"
+"做好准备,风险自负。
请注意,要使更改生效,您需要重新启动此应用程序的"
+"父进程(如果已从Windows快捷方式执行,则只需重新启动Spyder,否则 重新启动您可"
+"能已执行它的任何应用程序,例如 Python(x,y) Home "
+
+#: spyder/utils/help/sphinxify.py:216 spyder/utils/help/sphinxify.py:226
+msgid ""
+"It was not possible to generate rich text help for this object.Please "
+"see it in plain text."
msgstr "无法为该对象生成富文本的帮助。
请以纯文本方式查看它。"
+#: spyder/utils/introspection/manager.py:34
+#: spyder/utils/introspection/manager.py:39
msgid "Editor's code completion, go-to-definition and help"
msgstr "编辑器的代码完成,转到定义和帮助"
-msgid "Supported files"
-msgstr "支持的文件"
-
-msgid "All files (*.*)"
-msgstr "所有文件(*.*)"
-
-msgid "Spyder data files"
-msgstr "Spyder的数据文件"
-
-msgid "NumPy arrays"
-msgstr "NumPy数组"
-
-msgid "NumPy zip arrays"
-msgstr "NumPy压缩阵列"
-
-msgid "Matlab files"
-msgstr "matlab文件"
-
-msgid "CSV text files"
-msgstr "CSV文本文件"
-
-msgid "JPEG images"
-msgstr "JPEG图像"
-
-msgid "PNG images"
-msgstr "PNG图像"
-
-msgid "GIF images"
-msgstr "GIF图像"
-
-msgid "TIFF images"
-msgstr "TIFF图像"
-
-msgid "Pickle files"
-msgstr "pickle文件"
-
-msgid "JSON files"
-msgstr "JSON文件"
-
-msgid "Unsupported file type '%s'"
-msgstr "不支持的文件类型 '%s'"
-
+#: spyder/utils/programs.py:308
msgid "It was not possible to run this file in an external terminal"
msgstr "不能在外部终端上运行该文件"
+#: spyder/utils/syntaxhighlighters.py:35
msgid "Syntax highlighting for Matlab, Julia and other file types"
msgstr "用Matlib、Julia或其他文件类型的语法高亮"
+#: spyder/utils/syntaxhighlighters.py:44
msgid "Background:"
msgstr "背景:"
+#: spyder/utils/syntaxhighlighters.py:45
+#: spyder/widgets/sourcecode/codeeditor.py:107
msgid "Current line:"
msgstr "当前行:"
+#: spyder/utils/syntaxhighlighters.py:46
msgid "Current cell:"
-msgstr "当前单元格:"
+msgstr "当前Cell:"
+#: spyder/utils/syntaxhighlighters.py:47
msgid "Occurrence:"
msgstr "事件:"
+#: spyder/utils/syntaxhighlighters.py:48
msgid "Link:"
msgstr "链接:"
+#: spyder/utils/syntaxhighlighters.py:49
msgid "Side areas:"
msgstr "侧边栏:"
+#: spyder/utils/syntaxhighlighters.py:50
msgid "Matched
parens:"
-msgstr ""
+msgstr "匹配
圆括号:"
+#: spyder/utils/syntaxhighlighters.py:51
msgid "Unmatched
parens:"
-msgstr ""
+msgstr "不匹配
圆括号:"
+#: spyder/utils/syntaxhighlighters.py:52
msgid "Normal text:"
msgstr "普通文本:"
+#: spyder/utils/syntaxhighlighters.py:53
msgid "Keyword:"
msgstr "关键字:"
+#: spyder/utils/syntaxhighlighters.py:54
msgid "Builtin:"
msgstr "内置:"
+#: spyder/utils/syntaxhighlighters.py:55
msgid "Definition:"
msgstr "定义:"
+#: spyder/utils/syntaxhighlighters.py:56
msgid "Comment:"
msgstr "注释:"
+#: spyder/utils/syntaxhighlighters.py:57
msgid "String:"
msgstr "字符串:"
+#: spyder/utils/syntaxhighlighters.py:58
msgid "Number:"
msgstr "数值:"
+#: spyder/utils/syntaxhighlighters.py:59
msgid "Instance:"
msgstr "实例:"
+#: spyder/widgets/arraybuilder.py:179
+msgid ""
+"\n"
+" Numpy Array/Matrix Helper
\n"
+" Type an array in Matlab : [1 2;3 4]
\n"
+" or Spyder simplified syntax : 1 2;3 4
\n"
+"
\n"
+" Hit 'Enter' for array or 'Ctrl+Enter' for matrix.\n"
+"
\n"
+" Hint:
\n"
+" Use two spaces or two tabs to generate a ';'.\n"
+" "
+msgstr ""
+"\n"
+" Numpy 数组/矩阵 助手
\n"
+" 在MATLAB中输入一个数组 : [1 2;3 4]
\n"
+" 或Spyder简化的语法 : 1 2;3 4
\n"
+"
\n"
+" 输入数组时敲 'Enter' ,输入矩阵时敲 'Ctrl+Enter'\n"
+"
\n"
+" 提示:
\n"
+" 使用两个Tab或两个空格来生成 ';'。\n"
+" "
+
+#: spyder/widgets/arraybuilder.py:190
+msgid ""
+"\n"
+" Numpy Array/Matrix Helper
\n"
+" Enter an array in the table.
\n"
+" Use Tab to move between cells.\n"
+"
\n"
+" Hit 'Enter' for array or 'Ctrl+Enter' for matrix.\n"
+"
\n"
+" Hint:
\n"
+" Use two tabs at the end of a row to move to the next row.\n"
+" "
+msgstr ""
+"\n"
+" Numpy 数组/矩阵 助手
\n"
+" 在表格中输入一个数组。
\n"
+" 使用Tab在单元格之间切换。\n"
+"
\n"
+" 输入数组时敲 'Enter' ,输入矩阵时敲 'Ctrl+Enter'\n"
+"
\n"
+" 提示:
\n"
+" 在行末使用两个tab来切换到下一行。\n"
+" "
+
+#: spyder/widgets/arraybuilder.py:365
msgid "Array dimensions not valid"
msgstr "数组尺寸无效"
+#: spyder/widgets/browser.py:58 spyder/widgets/sourcecode/codeeditor.py:2738
msgid "Zoom out"
msgstr "缩小"
+#: spyder/widgets/browser.py:61 spyder/widgets/sourcecode/codeeditor.py:2734
msgid "Zoom in"
msgstr "放大"
+#: spyder/widgets/browser.py:216
msgid "Home"
msgstr "主页"
+#: spyder/widgets/browser.py:252
msgid "Find text"
msgstr "查找文本"
+#: spyder/widgets/browser.py:269
msgid "Address:"
msgstr "地址:"
+#: spyder/widgets/browser.py:305
msgid "Unable to load page"
msgstr "无法加载页面"
+#: spyder/widgets/comboboxes.py:165
msgid "Press enter to validate this entry"
msgstr "按Enter以验证此项"
+#: spyder/widgets/comboboxes.py:166
msgid "This entry is incorrect"
msgstr "此条目不正确"
+#: spyder/widgets/comboboxes.py:209
msgid "Press enter to validate this path"
msgstr "按回车验证路径"
+#: spyder/widgets/dependencies.py:63
msgid " Required "
-msgstr "依赖 "
+msgstr " 依赖于 "
+#: spyder/widgets/dependencies.py:63
msgid "Module"
msgstr "模块"
+#: spyder/widgets/dependencies.py:64
msgid " Installed "
-msgstr "安装"
+msgstr " 已安装 "
+#: spyder/widgets/dependencies.py:64
msgid "Provided features"
msgstr "提供的功能"
+#: spyder/widgets/dependencies.py:134
msgid "Dependencies"
msgstr "依赖"
+#: spyder/widgets/dependencies.py:141
msgid ""
-"Spyder depends on several Python modules to provide the right functionality for all its panes. The table below "
-"shows the required and installed versions (if any) of all of them.
Note: You can safely use Spyder "
-"without the following modules installed: %s and %s.
Please also note that new dependencies "
-"or changed ones will be correctly detected only after Spyder is restarted."
-msgstr ""
-
+"Spyder depends on several Python modules to provide the right functionality "
+"for all its panes. The table below shows the required and installed versions "
+"(if any) of all of them.
Note: You can safely use Spyder "
+"without the following modules installed: %s and %s."
+"
Please also note that new dependencies or changed ones will be "
+"correctly detected only after Spyder is restarted."
+msgstr ""
+"Spyder依赖于几个Python模块来为其所有窗格提供正确的功能。 下表显示了所有版本的"
+"必需和已安装版本(如果有)。
注意:您可以安全地使用Spyder而不安"
+"装以下模块:%s 和%s 。
请注意,只有在重新启动Spyder后"
+"才能正确检测到新的依赖项或已更改的依赖项。"
+
+#: spyder/widgets/dependencies.py:157
msgid "Copy to clipboard"
msgstr "复制到剪贴板"
+#: spyder/widgets/editor.py:511
msgid "Find symbols in file..."
msgstr "在文件中查找定义..."
+#: spyder/widgets/editor.py:514
msgid "Copy path to clipboard"
msgstr "复制路径到剪切板"
+#: spyder/widgets/editor.py:518
msgid "Close all to the right"
msgstr "关闭右侧所有"
+#: spyder/widgets/editor.py:520
msgid "Close all but this"
msgstr "除此以外关闭所有"
+#: spyder/widgets/editor.py:524 spyder/widgets/explorer.py:373
+msgid "Show in Finder"
+msgstr "在文件资源管理器中显示"
+
+#: spyder/widgets/editor.py:526 spyder/widgets/explorer.py:375
+msgid "Show in external file explorer"
+msgstr "用外部文件管理器打开"
+
+#: spyder/widgets/editor.py:1201
msgid "Temporary file"
msgstr "临时文件"
+#: spyder/widgets/editor.py:1287
msgid "New window"
msgstr "新窗口"
+#: spyder/widgets/editor.py:1288
msgid "Create a new editor window"
msgstr "创建一个新的编辑窗"
+#: spyder/widgets/editor.py:1291
msgid "Split vertically"
msgstr "垂直分割"
+#: spyder/widgets/editor.py:1293
msgid "Split vertically this editor window"
msgstr "垂直分割当前编辑窗"
+#: spyder/widgets/editor.py:1295
msgid "Split horizontally"
msgstr "水平分割"
+#: spyder/widgets/editor.py:1297
msgid "Split horizontally this editor window"
msgstr "水平分割当前编辑窗"
+#: spyder/widgets/editor.py:1299
msgid "Close this panel"
-msgstr "关闭当前面板"
+msgstr "关闭当前窗格"
+#: spyder/widgets/editor.py:1534
msgid "%s has been modified.
Do you want to save changes?"
msgstr "%s 已被修改
是否保存?"
-msgid "Save"
-msgstr "保存"
+#: spyder/widgets/editor.py:1620 spyder/widgets/editor.py:1783
+#: spyder/widgets/explorer.py:82
+msgid "Save Error"
+msgstr "保存错误"
-msgid "Unable to save script '%s'
Error message:
%s"
-msgstr "无法保存脚本 '%s'
错误信息:
%s"
+#: spyder/widgets/editor.py:1621 spyder/widgets/editor.py:1784
+#: spyder/widgets/explorer.py:83
+msgid "Unable to save file '%s'
Error message:
%s"
+msgstr "无法保存文件 '%s'
错误信息:
%s"
+#: spyder/widgets/editor.py:1971
msgid ""
-"%s is unavailable (this file may have been removed, moved or renamed outside Spyder).
Do you want to "
-"close it?"
-msgstr "%s 不可用(该文件已被移除、移动或在Spyder之外被重命名).
你想关闭它吗?"
+"%s is unavailable (this file may have been removed, moved or renamed "
+"outside Spyder).
Do you want to close it?"
+msgstr ""
+"%s 不可用(该文件已被移除、移动或在Spyder之外被重命名).
您想关闭它"
+"吗?"
-msgid "%s has been modified outside Spyder.
Do you want to reload it and lose all your changes?"
+#: spyder/widgets/editor.py:1994
+msgid ""
+"%s has been modified outside Spyder.
Do you want to reload it and "
+"lose all your changes?"
msgstr "%s 在Spyder之外被修改.
是否重新加载并丢弃当前所有更改?"
-msgid "All changes to %s will be lost.
Do you want to revert file from disk?"
+#: spyder/widgets/editor.py:2104
+msgid ""
+"All changes to %s will be lost.
Do you want to revert file from "
+"disk?"
msgstr "%s所有更改 都将丢失!
是否从磁盘恢复文件?"
+#: spyder/widgets/editor.py:2250
msgid "Loading %s..."
msgstr "载入 %s..."
-msgid "%s contains mixed end-of-line characters.
Spyder will fix this automatically."
-msgstr ""
+#: spyder/widgets/editor.py:2262
+msgid ""
+"%s contains mixed end-of-line characters.
Spyder will fix this "
+"automatically."
+msgstr "%s包含多种换行符。
Spyder将会自动修复这个问题。"
+#: spyder/widgets/editor.py:2672
msgid "Close window"
msgstr "关闭窗口"
+#: spyder/widgets/editor.py:2674
msgid "Close this window"
msgstr "关闭当前窗口"
+#: spyder/widgets/editortools.py:94 spyder/widgets/editortools.py:130
msgid "Line %s"
msgstr "行 %s"
+#: spyder/widgets/editortools.py:99
msgid "Class defined at line %s"
msgstr "类定义于行 %s"
+#: spyder/widgets/editortools.py:107
msgid "Method defined at line %s"
msgstr "方法定义于行 %s"
+#: spyder/widgets/editortools.py:117
msgid "Function defined at line %s"
msgstr "函数定义于行 %s"
+#: spyder/widgets/editortools.py:149
msgid "Cell starts at line %s"
-msgstr "单元开始于行 %s"
+msgstr "Cell开始于行 %s"
+#: spyder/widgets/editortools.py:201 spyder/widgets/editortools.py:527
msgid "Go to cursor position"
msgstr "转到光标位置"
+#: spyder/widgets/editortools.py:204
msgid "Show absolute path"
msgstr "显示绝对路径"
+#: spyder/widgets/editortools.py:207 spyder/widgets/explorer.py:286
msgid "Show all files"
msgstr "显示所有文件"
+#: spyder/widgets/editortools.py:210
msgid "Show special comments"
msgstr "显示特殊的注释"
+#: spyder/widgets/editortools.py:500
+msgid "Show/hide outline explorer"
+msgstr "显示/隐藏大纲浏览器"
+
+#: spyder/widgets/explorer.py:282
msgid "Edit filename filters..."
msgstr "编辑文件过滤器..."
+#: spyder/widgets/explorer.py:296
msgid "Edit filename filters"
msgstr "编辑文件过滤器"
+#: spyder/widgets/explorer.py:297
msgid "Name filters:"
msgstr "名称过滤器:"
+#: spyder/widgets/explorer.py:316
msgid "File..."
msgstr "文件..."
+#: spyder/widgets/explorer.py:320
msgid "Module..."
msgstr "模块..."
+#: spyder/widgets/explorer.py:324
msgid "Folder..."
msgstr "文件夹..."
+#: spyder/widgets/explorer.py:328
msgid "Package..."
msgstr "包..."
+#: spyder/widgets/explorer.py:349
+#: spyder/widgets/variableexplorer/collectionseditor.py:713
msgid "Edit"
msgstr "编辑"
+#: spyder/widgets/explorer.py:351
msgid "Move..."
msgstr "移动..."
+#: spyder/widgets/explorer.py:354
msgid "Delete..."
msgstr "删除..."
+#: spyder/widgets/explorer.py:357
msgid "Rename..."
msgstr "重命名..."
+#: spyder/widgets/explorer.py:360
msgid "Open"
msgstr "打开"
+#: spyder/widgets/explorer.py:361 spyder/widgets/sourcecode/codeeditor.py:2706
msgid "Convert to Python script"
msgstr "转换为Python脚本"
+#: spyder/widgets/explorer.py:393
msgid "Commit"
msgstr "提交"
+#: spyder/widgets/explorer.py:396
msgid "Browse repository"
msgstr "库浏览器"
+#: spyder/widgets/explorer.py:407
msgid "Open command prompt here"
msgstr "在此打开命令提示符"
+#: spyder/widgets/explorer.py:409
msgid "Open terminal here"
msgstr "在此打开终端"
-msgid "Open Python console here"
-msgstr "在此打开Python控制台"
+#: spyder/widgets/explorer.py:410
+msgid "Open IPython console here"
+msgstr "在此打开IPython控制台"
+#: spyder/widgets/explorer.py:424
msgid "New"
msgstr "新建"
+#: spyder/widgets/explorer.py:432
msgid "Import"
msgstr "导入"
+#: spyder/widgets/explorer.py:583
msgid "Do you really want to delete %s?"
-msgstr "你确定要删除%s?"
+msgstr "您确定要删除%s?"
+#: spyder/widgets/explorer.py:601
msgid "delete"
msgstr "删除"
+#: spyder/widgets/explorer.py:602 spyder/widgets/projects/explorer.py:148
+#: spyder/widgets/projects/explorer.py:256
msgid "Project Explorer"
-msgstr "项目管理器"
+msgstr "项目资源管理器"
+#: spyder/widgets/explorer.py:603 spyder/widgets/projects/explorer.py:149
msgid "Unable to %s %s
Error message:
%s"
msgstr "不能 %s %s
错误信息:
%s"
+#: spyder/widgets/explorer.py:618
msgid "File Explorer"
msgstr "文件管理器"
+#: spyder/widgets/explorer.py:619
msgid ""
-"The current directory contains a project.
If you want to delete the project, please go to Projects "
-"» Delete Project"
+"The current directory contains a project.
If you want to delete the "
+"project, please go to Projects » Delete Project"
msgstr ""
+"当前目录包含一个项目。
如果要删除项目,请转到项目&raquo; "
+"删除项目"
+#: spyder/widgets/explorer.py:636 spyder/widgets/sourcecode/codeeditor.py:2167
msgid "Conversion error"
msgstr "转换错误"
+#: spyder/widgets/explorer.py:637 spyder/widgets/sourcecode/codeeditor.py:2168
+msgid ""
+"It was not possible to convert this notebook. The error is:\n"
+"\n"
+msgstr ""
+"无法转换notebook,错误:\n"
+"\n"
+"\n"
+
+#: spyder/widgets/explorer.py:654 spyder/widgets/explorer.py:662
+#: spyder/widgets/explorer.py:676
+#: spyder/widgets/variableexplorer/collectionseditor.py:742
+#: spyder/widgets/variableexplorer/collectionseditor.py:988
msgid "Rename"
msgstr "重命名"
+#: spyder/widgets/explorer.py:655
msgid "New name:"
msgstr "新名称:"
-msgid "Do you really want to rename %s and overwrite the existing file %s?"
-msgstr ""
+#: spyder/widgets/explorer.py:663
+msgid ""
+"Do you really want to rename %s and overwrite the existing file "
+"%s?"
+msgstr "您确实想要重命名%s并覆盖已存在的文件%s吗?"
+#: spyder/widgets/explorer.py:677
msgid "Unable to rename file %s
Error message:
%s"
-msgstr ""
+msgstr "无法重命名文件%s
错误信息:
%s"
+#: spyder/widgets/explorer.py:724
msgid "Unable to move %s
Error message:
%s"
-msgstr ""
+msgstr "无法移动%s
错误信息:
%s"
+#: spyder/widgets/explorer.py:742
msgid "Unable to create folder %s
Error message:
%s"
-msgstr ""
+msgstr "无法创建目录%s
错误信息:
%s"
+#: spyder/widgets/explorer.py:755 spyder/widgets/explorer.py:789
msgid "Unable to create file %s
Error message:
%s"
-msgstr ""
+msgstr "无法创建文件%s
错误信息:
%s"
+#: spyder/widgets/explorer.py:763
msgid "New folder"
msgstr "新文件夹"
+#: spyder/widgets/explorer.py:764
msgid "Folder name:"
msgstr "文件夹名:"
+#: spyder/widgets/explorer.py:769
msgid "New package"
msgstr "新的包"
+#: spyder/widgets/explorer.py:770
msgid "Package name:"
msgstr "包的名:"
+#: spyder/widgets/explorer.py:810
msgid "New module"
msgstr "新的模块"
-msgid "For %s support, please install one of the
following tools:
%s"
-msgstr ""
+#: spyder/widgets/explorer.py:825
+msgid ""
+"For %s support, please install one of the
following tools:
%s"
+msgstr "需要安装下面的工具来支持%s功能:
%s"
+#: spyder/widgets/explorer.py:829
msgid "Unable to find external program.
%s"
-msgstr ""
+msgstr "找不到外部程序。
%s"
+#: spyder/widgets/explorer.py:1049
msgid "Show current directory only"
msgstr "仅显示当前目录"
+#: spyder/widgets/explorer.py:1163
msgid "You don't have the right permissions to open this directory"
msgstr "您没有权限打开此目录"
+#: spyder/widgets/explorer.py:1194
+msgid "Show icons and text"
+msgstr "显示图标和文本"
+
+#: spyder/widgets/explorer.py:1196
+#: spyder/widgets/variableexplorer/importwizard.py:535
msgid "Previous"
msgstr "以前的"
-msgid "Parent"
-msgstr ""
-
-msgid "Run again this program"
-msgstr "再次运行此程序"
-
-msgid "Kill"
-msgstr "结束"
-
-msgid "Kills the current process, causing it to exit immediately"
-msgstr "结束当前进程,使其立刻退出"
-
-msgid "Running..."
-msgstr "运行中..."
-
-msgid "Terminated."
-msgstr "终止。"
-
-msgid "Arguments"
-msgstr ""
-
-msgid "Command line arguments:"
-msgstr "命令行参数:"
-
-msgid "Variables"
-msgstr "变量"
-
-msgid "Show/hide global variables explorer"
-msgstr "显示/隐藏全局变量资源管理器"
-
-msgid "Terminate"
-msgstr "终止"
-
-msgid "Interact"
-msgstr "互动"
-
-msgid "Debug"
-msgstr "调试"
-
-msgid "Arguments..."
-msgstr ""
+#: spyder/widgets/fileswitcher.py:110
+msgid "unsaved file"
+msgstr "未保存文件"
-msgid "Post Mortem Debug"
-msgstr ""
+#: spyder/widgets/fileswitcher.py:249
+msgid ""
+"Press Enter to switch files or Esc to cancel.
Type to "
+"filter filenames.
Use :number to go to a line, e.g. "
+"main:42
Use @symbol_text to go to a symbol, e."
+"g. @init
Press Ctrl+W to close current "
+"tab.
"
+msgstr ""
+"按Enter切换文件,Esc取消。
输入以过滤文件名。
使"
+"用:number跳转到指定行。例如main:42
使用"
+"@symbol_text跳转到符号。例如@init
按Ctrl+W"
+"b>关闭当前标签。
"
+
+#: spyder/widgets/fileswitcher.py:663
+msgid "lines"
+msgstr "行"
-msgid "Working directory"
-msgstr ""
+#: spyder/widgets/findinfiles.py:121
+msgid "Unexpected error: see internal console"
+msgstr "预料外的错误:请查看内部终端"
-msgid "Set current working directory"
-msgstr ""
+#: spyder/widgets/findinfiles.py:158
+msgid "invalid regular expression"
+msgstr "无效的正则表达式"
-msgid "Environment variables"
-msgstr ""
+#: spyder/widgets/findinfiles.py:217
+msgid "permission denied errors were encountered"
+msgstr "遭遇错误:权限不足 Permission denied"
-msgid "Show sys.path contents"
-msgstr ""
+#: spyder/widgets/findinfiles.py:232
+msgid "Search directory"
+msgstr "搜索目录"
-msgid "Arguments: %s"
-msgstr ""
+#: spyder/widgets/findinfiles.py:245
+msgid "Project"
+msgstr "项目"
-msgid "No argument"
-msgstr ""
+#: spyder/widgets/findinfiles.py:246
+msgid ""
+"Search in all files and directories present on the current project path (if "
+"opened)"
+msgstr "在项目路径下所有文件和目录里搜索"
-msgid "A Python console failed to start!"
-msgstr ""
+#: spyder/widgets/findinfiles.py:251
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "File"
+msgstr "文件"
-msgid "Process failed to start"
-msgstr ""
+#: spyder/widgets/findinfiles.py:252
+msgid "Search in current opened file"
+msgstr "在打开的文件里搜索"
-msgid "unsaved file"
-msgstr ""
+#: spyder/widgets/findinfiles.py:257
+msgid "Select other directory"
+msgstr "选择其他目录"
-msgid ""
-"Press Enter to switch files or Esc to cancel.
Type to filter filenames.
Use :"
-"number to go to a line, e.g. main:42
Use @symbol_text to go to a symbol, e.g. "
-"@init
Press Ctrl+W to close current tab.
"
-msgstr ""
+#: spyder/widgets/findinfiles.py:258
+msgid "Search in other folder present on the file system"
+msgstr "在文件系统的其他目录里搜索"
-msgid "lines"
-msgstr ""
+#: spyder/widgets/findinfiles.py:262
+msgid "Clear the list of other directories"
+msgstr "清除其他目录列表"
-msgid "Unexpected error: see internal console"
-msgstr ""
+#: spyder/widgets/findinfiles.py:333
+msgid "Clear other directories"
+msgstr "清除其他目录"
-msgid "invalid regular expression"
-msgstr ""
+#: spyder/widgets/findinfiles.py:334
+msgid "Do you want to clear the list of other directories?"
+msgstr "您想关闭其他目录列表么?"
-msgid "permission denied errors were encountered"
-msgstr ""
+#: spyder/widgets/findinfiles.py:404 spyder/widgets/findreplace.py:52
+msgid "Regular expression error"
+msgstr "正则表达式错误"
+#: spyder/widgets/findinfiles.py:427
msgid "Search pattern"
-msgstr ""
+msgstr "搜索模式串"
+#: spyder/widgets/findinfiles.py:430 spyder/widgets/findinfiles.py:470
+#: spyder/widgets/findreplace.py:100
msgid "Regular expression"
-msgstr ""
+msgstr "正则表达式"
+
+#: spyder/widgets/findinfiles.py:433 spyder/widgets/findreplace.py:106
+msgid "Case Sensitive"
+msgstr "区分大小写"
+#: spyder/widgets/findinfiles.py:444
msgid "Search"
-msgstr ""
+msgstr "搜索"
+#: spyder/widgets/findinfiles.py:447
msgid "Start search"
msgstr "开始查找"
+#: spyder/widgets/findinfiles.py:454
msgid "Stop search"
msgstr "停止查找"
-msgid "Included filenames pattern"
-msgstr "包含文件名模式"
-
-msgid "Include:"
-msgstr "包含:"
-
-msgid "Excluded filenames pattern"
-msgstr "排除文件名模式"
+#: spyder/widgets/findinfiles.py:464
+msgid "Exclude pattern"
+msgstr "排除模式"
+#: spyder/widgets/findinfiles.py:473
msgid "Exclude:"
msgstr "例外:"
-msgid "PYTHONPATH"
-msgstr "PYTHONPATH"
-
-msgid "Search in all directories listed in sys.path which are outside the Python installation directory"
-msgstr ""
-
-msgid "Hg repository"
-msgstr "Hg仓库"
-
-msgid "Search in current directory hg repository"
-msgstr "在当前hg仓库目录中搜索"
-
-msgid "Here:"
-msgstr ""
-
-msgid "Search recursively in this directory"
-msgstr "在这个目录中递归搜索"
-
-msgid "Browse a search directory"
-msgstr "浏览搜索目录"
+#: spyder/widgets/findinfiles.py:482
+msgid "Search in:"
+msgstr "搜索于:"
+#: spyder/widgets/findinfiles.py:511
msgid "Hide advanced options"
msgstr "隐藏高级选项"
+#: spyder/widgets/findinfiles.py:514
msgid "Show advanced options"
msgstr "显示高级选项"
-msgid "Search canceled"
-msgstr "搜索取消"
-
+#: spyder/widgets/findinfiles.py:790 spyder/widgets/findinfiles.py:877
msgid "String not found"
msgstr "没有找到字符串"
+#: spyder/widgets/findinfiles.py:879
msgid "matches in"
-msgstr ""
+msgstr "匹配于"
+#: spyder/widgets/findinfiles.py:880
msgid "file"
msgstr "文件"
-msgid "interrupted"
-msgstr "暂停"
+#: spyder/widgets/findinfiles.py:912
+msgid " Scanning: {0}"
+msgstr " 扫描中:{0}"
+
+#: spyder/widgets/findinfiles.py:914
+msgid " Searching for files in folder: {0}"
+msgstr " 在目录里搜索:{0}"
+
+#: spyder/widgets/findinfiles.py:918
+msgid " Searching for files..."
+msgstr " 正在搜索文件..."
+
+#: spyder/widgets/findreplace.py:49
+msgid "No matches"
+msgstr "无匹配"
+#: spyder/widgets/findreplace.py:50 spyder/widgets/findreplace.py:51
+#: spyder/widgets/findreplace.py:73
msgid "Search string"
msgstr "查找字符串"
-msgid "Case Sensitive"
-msgstr "区分大小写"
-
+#: spyder/widgets/findreplace.py:112
msgid "Whole words"
msgstr "全词"
+#: spyder/widgets/findreplace.py:118
msgid "Highlight matches"
msgstr "高亮匹配"
+#: spyder/widgets/findreplace.py:132
msgid "Replace with:"
msgstr "替换为:"
+#: spyder/widgets/findreplace.py:134
msgid "Replace string"
msgstr "替换字符串"
-msgid "Replace/find"
-msgstr "替换/查找"
+#: spyder/widgets/findreplace.py:138
+msgid "Replace/find next"
+msgstr "替换/查找 下一个"
+
+#: spyder/widgets/findreplace.py:143
+msgid "Replace selection"
+msgstr "替换选择"
+#: spyder/widgets/findreplace.py:151
msgid "Replace all"
msgstr "替换所有"
+#: spyder/widgets/findreplace.py:583
+msgid "of"
+msgstr ""
+
+#: spyder/widgets/findreplace.py:587
+msgid "matches"
+msgstr "匹配于"
+
+#: spyder/widgets/findreplace.py:590
+msgid "no matches"
+msgstr "无匹配"
+
+#: spyder/widgets/github/backend.py:151
+msgid "Invalid credentials"
+msgstr "无效凭据"
+
+#: spyder/widgets/github/backend.py:152
+msgid "Failed to create Github issue, invalid credentials..."
+msgstr "创建GitHub issue失败,无效凭据..."
+
+#: spyder/widgets/github/backend.py:159
+msgid "Failed to create issue"
+msgstr "创建issue失败"
+
+#: spyder/widgets/github/backend.py:160
+msgid "Failed to create Github issue. Error %d"
+msgstr "创建GitHub issue失败,错误 %d"
+
+#: spyder/widgets/github/backend.py:167
+msgid "Issue created on Github"
+msgstr "已在GitHub创建Issue"
+
+#: spyder/widgets/github/backend.py:168
+msgid ""
+"Issue successfully created. Would you like to open the issue in your web "
+"browser?"
+msgstr "Issue创建成功。想要立即在浏览器里打开吗?"
+
+#: spyder/widgets/github/backend.py:195
+msgid "Failed to store password"
+msgstr "保存密码失败"
+
+#: spyder/widgets/github/backend.py:196
+msgid ""
+"It was not possible to securely save your password. You will be prompted for "
+"your Github credentials next time you want to report an issue."
+msgstr "不能安全地保存密码。您会在下次报告issue时再次被询问凭据。"
+
+#: spyder/widgets/github/backend.py:212
+msgid "Failed to store token"
+msgstr "无法保存token"
+
+#: spyder/widgets/github/backend.py:213
+msgid ""
+"It was not possible to securely save your token. You will be prompted for "
+"your Github token next time you want to report an issue."
+msgstr "不能安全地保存token。您会在下次报告issue时再次被询问凭据。"
+
+#: spyder/widgets/github/backend.py:237
+msgid "Failed to retrieve password"
+msgstr "无法获取密码"
+
+#: spyder/widgets/github/backend.py:238
+msgid ""
+"It was not possible to retrieve your password. Please introduce it again."
+msgstr "不能获取您的密码。请重新输入。"
+
+#: spyder/widgets/github/backend.py:249
+msgid "Failed to retrieve token"
+msgstr "无法获取token"
+
+#: spyder/widgets/github/backend.py:250
+msgid "It was not possible to retrieve your token. Please introduce it again."
+msgstr "不能获取您的token,请重新输入。"
+
+#: spyder/widgets/github/gh_login.py:38
+msgid "Sign in to Github"
+msgstr "登陆GitHub"
+
+#: spyder/widgets/github/gh_login.py:57
+msgid ""
+"For regular users, i.e. users without two-factor authentication "
+"enabled"
+msgstr "对于普通用户,即没有启用两步验证的用户"
+
+#: spyder/widgets/github/gh_login.py:62
+msgid "Username:"
+msgstr "用户名:"
+
+#: spyder/widgets/github/gh_login.py:69
+msgid "Password: "
+msgstr "密码: "
+
+#: spyder/widgets/github/gh_login.py:81
+msgid "Remember me"
+msgstr "记住我"
+
+#: spyder/widgets/github/gh_login.py:82
+msgid "Spyder will save your credentials safely"
+msgstr "Spyder将会安全地保存您的凭据"
+
+#: spyder/widgets/github/gh_login.py:99
+msgid "Password Only"
+msgstr "仅密码"
+
+#: spyder/widgets/github/gh_login.py:105
+msgid ""
+"For users with two-factor authentication enabled, or who prefer a per-"
+"app token authentication.
You can go here "
+"and click \"Generate token\" at the bottom to create a new token to use for "
+"this, with the appropriate permissions."
+msgstr ""
+"对于启用了两步验证或独立应用令牌验证的用户,可以在这里"
+"b>点击\"generate token\"来创建具有适当权限的新令牌。"
+
+#: spyder/widgets/github/gh_login.py:127
+msgid "Remember token"
+msgstr "记住令牌"
+
+#: spyder/widgets/github/gh_login.py:128
+msgid "Spyder will save your token safely"
+msgstr "Spyder将会安全保存您的令牌"
+
+#: spyder/widgets/github/gh_login.py:145
+msgid "Access Token"
+msgstr "访问令牌"
+
+#: spyder/widgets/github/gh_login.py:148
+msgid "Sign in"
+msgstr "登陆"
+
+#: spyder/widgets/internalshell.py:263
msgid "Help..."
msgstr "帮助..."
+#: spyder/widgets/internalshell.py:280
msgid "Shell special commands:"
msgstr "Shell特殊命令:"
+#: spyder/widgets/internalshell.py:281
msgid "Internal editor:"
msgstr "内部编辑器:"
+#: spyder/widgets/internalshell.py:282
msgid "External editor:"
msgstr "附加编辑器:"
+#: spyder/widgets/internalshell.py:283
msgid "Run script:"
msgstr "执行脚本:"
+#: spyder/widgets/internalshell.py:284
msgid "Remove references:"
msgstr "移除引用:"
+#: spyder/widgets/internalshell.py:285
msgid "System commands:"
-msgstr "系统命令行"
+msgstr "系统命令:"
+#: spyder/widgets/internalshell.py:286
msgid "Python help:"
msgstr "Python帮助:"
+#: spyder/widgets/internalshell.py:287
msgid "GUI-based editor:"
msgstr "GUI-based编辑器:"
+#: spyder/widgets/internalshell.py:418
+msgid ""
+"In order to use commands like \"raw_input\" or \"input\" run Spyder with the "
+"multithread option (--multithread) from a system terminal"
+msgstr ""
+"为了使用像“raw_input”或“input”这样的命令,使用来自系统终端的多线程选项(--"
+"multithread)运行Spyder"
+
+#: spyder/widgets/ipythonconsole/client.py:308
msgid "An error ocurred while starting the kernel"
-msgstr "启动内核时出现了一个错误"
+msgstr "启动 IPython kernel 时出现了一个错误"
+
+#: spyder/widgets/ipythonconsole/client.py:352
+#: spyder/widgets/ipythonconsole/client.py:408
+#: spyder/widgets/ipythonconsole/client.py:441
+#: spyder/widgets/ipythonconsole/shell.py:234
+#: spyder/widgets/variableexplorer/namespacebrowser.py:196
+msgid "Remove all variables"
+msgstr "删除所有变量"
+
+#: spyder/widgets/ipythonconsole/client.py:361
+msgid "Show environment variables"
+msgstr "显示环境变量"
+
+#: spyder/widgets/ipythonconsole/client.py:368
+msgid "Show sys.path contents"
+msgstr "显示 sys.path 内容"
+#: spyder/widgets/ipythonconsole/client.py:395
msgid "Stop the current command"
msgstr "停止当前命令"
+#: spyder/widgets/ipythonconsole/client.py:406
+#: spyder/widgets/variableexplorer/collectionseditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:970
+msgid "Remove"
+msgstr "移除"
+
+#: spyder/widgets/ipythonconsole/client.py:429
msgid "Inspect current object"
msgstr "检查当前对象"
+#: spyder/widgets/ipythonconsole/client.py:435
msgid "Clear line or block"
msgstr "清除行或块"
-msgid "Reset namespace"
-msgstr "重置命名空间"
-
+#: spyder/widgets/ipythonconsole/client.py:448
msgid "Clear console"
msgstr "清空控制台"
+#: spyder/widgets/ipythonconsole/client.py:507
msgid "Are you sure you want to restart the kernel?"
-msgstr "你确定重启内核吗?"
+msgstr "您确定重启 IPython kernel 吗?"
+#: spyder/widgets/ipythonconsole/client.py:509
msgid "Restart kernel?"
-msgstr "重启内核?"
+msgstr "重启 IPython kernel?"
+
+#: spyder/widgets/ipythonconsole/client.py:526
+msgid "Error restarting kernel: %s\n"
+msgstr "重启 IPython kernel 错误:%s\n"
+
+#: spyder/widgets/ipythonconsole/client.py:534
+msgid ""
+"
Restarting kernel...\n"
+"
"
+msgstr ""
+"
重启 IPython kernel...\n"
+"
"
-msgid "Changing backend to Qt for Mayavi"
-msgstr "为Mayavi改变后端到Qt"
+#: spyder/widgets/ipythonconsole/client.py:538
+msgid "Cannot restart a kernel not started by Spyder\n"
+msgstr "无法重启非Spyder启动的 IPython kernel \n"
+#: spyder/widgets/ipythonconsole/client.py:649
msgid "Connecting to kernel..."
-msgstr "连接到内核..."
+msgstr "连接到 IPython kernel..."
-msgid "Inspecting and setting values while debugging in IPython consoles is not supported yet by Spyder."
-msgstr ""
+#: spyder/widgets/ipythonconsole/help.py:128 spyder/widgets/mixins.py:726
+msgid "Arguments"
+msgstr "参数"
+
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:138
+msgid "Loading this kind of data while debugging is not supported."
+msgstr "不支持在调试时加载此类数据。"
+
+#: spyder/widgets/ipythonconsole/namespacebrowser.py:157
+msgid "Saving data while debugging is not supported."
+msgstr "不支持在调试时保存数据。"
-msgid "Reset IPython namespace"
-msgstr "重置IPython命名空间"
+#: spyder/widgets/ipythonconsole/shell.py:235
+msgid ""
+"All user-defined variables will be removed. Are you sure you want to proceed?"
+msgstr "将删除所有用户定义的变量。 您确定要继续吗?"
+
+#: spyder/widgets/ipythonconsole/shell.py:241
+msgid "Don't show again."
+msgstr "不再显示。"
-msgid "All user-defined variables will be removed.
Are you sure you want to reset the namespace?"
+#: spyder/widgets/ipythonconsole/shell.py:266
+msgid ""
+"
Removing all variables...\n"
+"
"
msgstr ""
+"
删除所有变量...\n"
+"
"
+
+#: spyder/widgets/ipythonconsole/shell.py:432
+msgid "Changing backend to Qt4 for Mayavi"
+msgstr "为Mayavi使用Qt4"
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel died, restarting"
-msgstr "内核挂了,重启中"
+msgstr "IPython kernel 已死亡,重启中"
+#: spyder/widgets/ipythonconsole/shell.py:477
msgid "Kernel restarting"
-msgstr "内核重启中"
+msgstr "IPython kernel 重启中"
+#: spyder/widgets/onecolumntree.py:52
msgid "Collapse all"
msgstr "全部折叠"
+#: spyder/widgets/onecolumntree.py:56
msgid "Expand all"
msgstr "全部展开"
+#: spyder/widgets/onecolumntree.py:60
msgid "Restore"
msgstr "恢复"
+#: spyder/widgets/onecolumntree.py:61
msgid "Restore original tree layout"
msgstr "恢复原来的树状布局"
+#: spyder/widgets/onecolumntree.py:65
msgid "Collapse selection"
msgstr "折叠所选"
+#: spyder/widgets/onecolumntree.py:69
msgid "Expand selection"
msgstr "展开所选"
+#: spyder/widgets/pathmanager.py:98
msgid "Move to top"
msgstr "移动到顶部"
+#: spyder/widgets/pathmanager.py:104
msgid "Move up"
msgstr "上移"
+#: spyder/widgets/pathmanager.py:110
msgid "Move down"
msgstr "下移"
+#: spyder/widgets/pathmanager.py:116
msgid "Move to bottom"
msgstr "移动到底部"
+#: spyder/widgets/pathmanager.py:127 spyder/widgets/pathmanager.py:270
+#: spyder/widgets/pathmanager.py:282
msgid "Add path"
msgstr "添加路径"
+#: spyder/widgets/pathmanager.py:132 spyder/widgets/pathmanager.py:247
msgid "Remove path"
msgstr "移除路径"
+#: spyder/widgets/pathmanager.py:142
msgid "Synchronize..."
msgstr "同步..."
+#: spyder/widgets/pathmanager.py:144
msgid "Synchronize Spyder's path list with PYTHONPATH environment variable"
msgstr "同步Spyder的路径列表和PYTHONPATH环境变量"
+#: spyder/widgets/pathmanager.py:156
msgid "Synchronize"
msgstr "同步"
+#: spyder/widgets/pathmanager.py:157
msgid ""
-"This will synchronize Spyder's path list with PYTHONPATH environment variable for current user, allowing "
-"you to run your Python modules outside Spyder without having to configure sys.path.
Do you want to clear "
+"This will synchronize Spyder's path list with PYTHONPATH environment "
+"variable for current user, allowing you to run your Python modules outside "
+"Spyder without having to configure sys.path.
Do you want to clear "
"contents of PYTHONPATH before adding Spyder's path list?"
msgstr ""
+"这将会使用当前用户的PYTHONPATH环境变量同步Spyder的path列表,以允许您不"
+"配置 sys.path 而运行您的Python模块。
您想要在Spyder将它们添加到path列表之"
+"前清除PYTHONPATH吗?"
+#: spyder/widgets/pathmanager.py:248
msgid "Do you really want to remove selected path?"
msgstr "是否真的要删除选定的路径?"
-msgid "This directory is already included in Spyder path list.
Do you want to move it to the top of the list?"
-msgstr ""
+#: spyder/widgets/pathmanager.py:271
+msgid ""
+"You are using Python 2 and the path selected has Unicode characters. The new "
+"path will not be added."
+msgstr "您正在使用Python 2,并且所选路径具有Unicode字符。 新路径不会被添加。"
+#: spyder/widgets/pathmanager.py:283
+msgid ""
+"This directory is already included in Spyder path list.
Do you want to "
+"move it to the top of the list?"
+msgstr "这个目录已经包含在Spyder的path列表中。
您确定要移动它到列表头部吗?"
+
+#: spyder/widgets/projects/configdialog.py:30
msgid "Project preferences"
msgstr "项目偏好"
+#: spyder/widgets/projects/configdialog.py:82
+#: spyder/widgets/projects/configdialog.py:119
msgid "Restore data on startup"
msgstr "启动时恢复数据"
+#: spyder/widgets/projects/configdialog.py:84
+#: spyder/widgets/projects/configdialog.py:121
msgid "Save data on exit"
msgstr "退出时保存数据"
+#: spyder/widgets/projects/configdialog.py:86
+#: spyder/widgets/projects/configdialog.py:123
msgid "Save history"
msgstr "保存历史"
+#: spyder/widgets/projects/configdialog.py:88
+#: spyder/widgets/projects/configdialog.py:125
msgid "Save non project files opened"
msgstr "保存打开的非项目文件"
+#: spyder/widgets/projects/configdialog.py:111
msgid "Code"
msgstr "代码"
+#: spyder/widgets/projects/configdialog.py:118
msgid "Workspace"
msgstr "工作空间"
+#: spyder/widgets/projects/configdialog.py:148
+#: spyder/widgets/projects/configdialog.py:155
msgid "Version control"
msgstr "版本控制"
+#: spyder/widgets/projects/configdialog.py:156
msgid "Use version control"
msgstr "使用版本控制"
+#: spyder/widgets/projects/configdialog.py:161
msgid "Version control system"
msgstr "版本控制系统"
+#: spyder/widgets/projects/explorer.py:51
msgid "Show horizontal scrollbar"
msgstr "显示水平滚动条"
+#: spyder/widgets/projects/explorer.py:113
msgid "File %s already exists.
Do you want to overwrite it?"
-msgstr "文件 %s已存在。
你确定要覆盖它吗?"
+msgstr "文件 %s已存在。
您确定要覆盖它吗?"
+#: spyder/widgets/projects/explorer.py:127
msgid "Folder %s already exists."
msgstr "文件夹%s已存在。"
+#: spyder/widgets/projects/explorer.py:145
msgid "copy"
msgstr "复制"
+#: spyder/widgets/projects/explorer.py:147
msgid "move"
msgstr "移动"
+#: spyder/widgets/projects/explorer.py:244
msgid ""
-"Do you really want to delete {filename}?
Note: This action will only delete the project. Its "
-"files are going to be preserved on disk."
-msgstr "你确定要删除 {filename}?
提示: 本操作只会删除项目,它的文件仍将保存在磁盘上。"
+"Do you really want to delete {filename}?
Note: This "
+"action will only delete the project. Its files are going to be preserved on "
+"disk."
+msgstr ""
+"您确定要删除 {filename}?
提示: 本操作只会删除项目,它的"
+"文件仍将保存在磁盘上。"
-msgid "Unable to delete {varpath}
The error message was:
{error}"
+#: spyder/widgets/projects/explorer.py:257
+msgid ""
+"Unable to delete {varpath}
The error message was:"
+"
{error}"
msgstr "无法删除 {varpath}
错误信息为:
{error}"
+#: spyder/widgets/projects/projectdialog.py:69
msgid "New directory"
msgstr "新的目录"
+#: spyder/widgets/projects/projectdialog.py:70
msgid "Existing directory"
msgstr "现有的目录"
+#: spyder/widgets/projects/projectdialog.py:72
msgid "Project name"
msgstr "项目名称"
+#: spyder/widgets/projects/projectdialog.py:73
msgid "Location"
msgstr "位置"
+#: spyder/widgets/projects/projectdialog.py:74
msgid "Project type"
msgstr "项目类型"
+#: spyder/widgets/projects/projectdialog.py:75
msgid "Python version"
msgstr "Python版本"
+#: spyder/widgets/projects/projectdialog.py:83
+#: spyder/widgets/variableexplorer/importwizard.py:529
msgid "Cancel"
msgstr "取消"
+#: spyder/widgets/projects/projectdialog.py:84
msgid "Create"
msgstr "创建"
+#: spyder/widgets/projects/projectdialog.py:102
msgid "Create new project"
msgstr "创建新的项目"
+#: spyder/widgets/projects/type/__init__.py:223
msgid "Empty project"
msgstr "空项目"
+#: spyder/widgets/projects/type/python.py:20
msgid "Python project"
msgstr "Python项目"
+#: spyder/widgets/projects/type/python.py:76
msgid "Python package"
msgstr "Python包"
+#: spyder/widgets/pydocgui.py:117
msgid "Module or package:"
msgstr "模块或包:"
+#: spyder/widgets/reporterror.py:128
+msgid "Issue reporter"
+msgstr "问题报告"
+
+#: spyder/widgets/reporterror.py:136
+msgid "Please fill the following information"
+msgstr "请填充下面的信息"
+
+#: spyder/widgets/reporterror.py:138
+msgid "Spyder has encountered an internal problem!"
+msgstr "Spyder遇到了内部错误!"
+
+#: spyder/widgets/reporterror.py:140
+msgid ""
+"{title}
Before reporting this problem, please consult our "
+"comprehensive Troubleshooting Guide "
+"which should help solve most issues, and search for known bugs matching your error message or problem "
+"description for a quicker solution."
+msgstr ""
+" {title}
在报告此问题之前,请查阅我们的故障排除指南。 这应该有助于解决大多数问题,并搜索"
+"已知错误以匹配您的错误消息或问题描述,以"
+"获得更快速的解决方案。"
+
+#: spyder/widgets/reporterror.py:158 spyder/widgets/reporterror.py:190
+msgid "{} more characters to go..."
+msgstr "还有 {} 个字符..."
+
+#: spyder/widgets/reporterror.py:162
+msgid "Title: {}"
+msgstr "标题:{}"
+
+#: spyder/widgets/reporterror.py:168
+msgid "Steps to reproduce: {}"
+msgstr "重现的步骤: {}"
+
+#: spyder/widgets/reporterror.py:169
+msgid ""
+"Please enter a detailed step-by-step description (in English) of what led up "
+"to the problem below. Issue reports without a clear way to reproduce them "
+"will be closed."
+msgstr ""
+"请输入导致以下问题的详细逐步说明(英文)。 没有明确的方法来重现的问题报告会被"
+"关闭。"
+
+#: spyder/widgets/reporterror.py:194
+msgid "Hide all future errors during this session"
+msgstr "在此会话期间隐藏所有错误"
+
+#: spyder/widgets/reporterror.py:201
+msgid "Submit to Github"
+msgstr "提交至GitHub"
+
+#: spyder/widgets/reporterror.py:205 spyder/widgets/reporterror.py:312
+msgid "Show details"
+msgstr "显示细节"
+
+#: spyder/widgets/reporterror.py:210
+#: spyder/widgets/variableexplorer/arrayeditor.py:740
+#: spyder/widgets/variableexplorer/collectionseditor.py:1397
+#: spyder/widgets/variableexplorer/dataframeeditor.py:756
+#: spyder/widgets/variableexplorer/texteditor.py:72
+msgid "Close"
+msgstr "关闭"
+
+#: spyder/widgets/reporterror.py:286
+msgid ""
+"An error occurred while trying to send the issue to Github automatically. "
+"Would you like to open it manually?
If so, please make sure to paste "
+"your clipboard into the issue report box that will appear in a new browser "
+"tab before clicking Submit on that page."
+msgstr ""
+"尝试自动将问题发送到Github时发生错误。您想手动打开吗?
如果是这样,请"
+"确保将剪贴板粘贴到问题报告框中,该框将显示在新的浏览器选项卡中,然后单击该页"
+"面上的Submit。"
+
+#: spyder/widgets/reporterror.py:320
+msgid "Hide details"
+msgstr "隐藏细节"
+
+#: spyder/widgets/reporterror.py:329 spyder/widgets/reporterror.py:337
+msgid "more characters to go..."
+msgstr "还有一些字符..."
+
+#: spyder/widgets/reporterror.py:331
+msgid "Description complete; thanks!"
+msgstr "完成描述;谢谢!"
+
+#: spyder/widgets/reporterror.py:339
+msgid "Title complete; thanks!"
+msgstr "完成标题;谢谢!"
+
+#: spyder/widgets/shell.py:131
msgid "Save history log..."
msgstr "保存历史记录…"
+#: spyder/widgets/shell.py:133
msgid "Save current history log (i.e. all inputs and outputs) in a text file"
-msgstr "保存当前历史日志(即所有输入和输出)到一个文本文件。"
+msgstr "保存当前历史日志(即所有输入和输出)到一个文本文件"
+#: spyder/widgets/shell.py:253
msgid "Save history log"
msgstr "保存历史记录"
+#: spyder/widgets/shell.py:256
msgid "History logs"
msgstr "历史记录"
-msgid "Unable to save file '%s'
Error message:
%s"
-msgstr "无法保存文件 '%s'
错误信息:
%s"
-
+#: spyder/widgets/shell.py:670
msgid "Copy without prompts"
msgstr "复制但不提示"
+#: spyder/widgets/shell.py:673 spyder/widgets/shell.py:677
msgid "Clear line"
msgstr "清除行"
+#: spyder/widgets/shell.py:679
msgid "Clear shell"
msgstr "清除shell"
+#: spyder/widgets/shell.py:683
msgid "Clear shell contents ('cls' command)"
-msgstr ""
+msgstr "清除终端内容('cls'命令)"
+#: spyder/widgets/shortcutssummary.py:42
+msgid "Spyder Keyboard ShortCuts"
+msgstr "Spyder快捷键"
+
+#: spyder/widgets/sourcecode/codeeditor.py:101
msgid "Go to line:"
msgstr "转到行:"
+#: spyder/widgets/sourcecode/codeeditor.py:109
msgid "Line count:"
msgstr "行计数:"
+#: spyder/widgets/sourcecode/codeeditor.py:1334
msgid "Breakpoint"
msgstr "断点"
+#: spyder/widgets/sourcecode/codeeditor.py:1335
msgid "Condition:"
msgstr "状态:"
+#: spyder/widgets/sourcecode/codeeditor.py:1740
msgid "Code analysis"
msgstr "代码分析"
+#: spyder/widgets/sourcecode/codeeditor.py:1794
msgid "To do"
msgstr "To do"
+#: spyder/widgets/sourcecode/codeeditor.py:2154
msgid "Removal error"
msgstr "移除错误"
+#: spyder/widgets/sourcecode/codeeditor.py:2155
+msgid ""
+"It was not possible to remove outputs from this notebook. The error is:\n"
+"\n"
+msgstr ""
+"不能移除这个notebook的输出。错误:\n"
+"\n"
+
+#: spyder/widgets/sourcecode/codeeditor.py:2703
msgid "Clear all ouput"
msgstr "清除所有输出"
+#: spyder/widgets/sourcecode/codeeditor.py:2709
msgid "Go to definition"
msgstr "转到定义"
+#: spyder/widgets/sourcecode/codeeditor.py:2742
msgid "Zoom reset"
msgstr "重置缩放"
+#: spyder/widgets/status.py:25
msgid "CPU and memory usage info in the status bar"
msgstr "状态栏中的CPU和内存使用信息"
+#: spyder/widgets/status.py:117
msgid "Memory:"
-msgstr "内存"
+msgstr "内存:"
-msgid "Memory usage status: requires the `psutil` (>=v0.3) library on non-Windows platforms"
+#: spyder/widgets/status.py:118
+msgid ""
+"Memory usage status: requires the `psutil` (>=v0.3) library on non-Windows "
+"platforms"
msgstr "内存使用情况:在非Windows平台上依赖`psutil` (>=v0.3) 库"
+#: spyder/widgets/status.py:134
msgid "CPU:"
-msgstr "CPU"
+msgstr "CPU:"
+#: spyder/widgets/status.py:135
msgid "CPU usage status: requires the `psutil` (>=v0.3) library"
msgstr "CPU使用情况:在非Windows平台上依赖`psutil` (>=v0.3) 库"
+#: spyder/widgets/status.py:162
msgid "Permissions:"
msgstr "权限:"
+#: spyder/widgets/status.py:189
msgid "End-of-lines:"
msgstr "行尾:"
+#: spyder/widgets/status.py:216
msgid "Encoding:"
msgstr "编码:"
+#: spyder/widgets/status.py:242
msgid "Line:"
msgstr "行:"
+#: spyder/widgets/status.py:243
msgid "Column:"
msgstr "列:"
+#: spyder/widgets/tabs.py:274
msgid "Browse tabs"
-msgstr "浏览标签:"
+msgstr "浏览标签"
+#: spyder/widgets/tabs.py:413
msgid "Close current tab"
msgstr "关闭当前标签"
+#: spyder/widgets/variableexplorer/arrayeditor.py:509
msgid "It was not possible to copy values for this array"
msgstr "无法复制此数组的值"
+#: spyder/widgets/variableexplorer/arrayeditor.py:545
+#: spyder/widgets/variableexplorer/arrayeditor.py:578
+#: spyder/widgets/variableexplorer/dataframeeditor.py:728
+#: spyder/widgets/variableexplorer/dataframeeditor.py:787
msgid "Format"
msgstr "格式化"
+#: spyder/widgets/variableexplorer/arrayeditor.py:550
+#: spyder/widgets/variableexplorer/dataframeeditor.py:732
msgid "Resize"
msgstr "调整大小"
+#: spyder/widgets/variableexplorer/arrayeditor.py:553
+#: spyder/widgets/variableexplorer/dataframeeditor.py:736
+msgid "Background color"
+msgstr "背景色"
+
+#: spyder/widgets/variableexplorer/arrayeditor.py:579
+#: spyder/widgets/variableexplorer/dataframeeditor.py:788
msgid "Float formatting"
msgstr "浮点格式化"
+#: spyder/widgets/variableexplorer/arrayeditor.py:587
msgid "Format (%s) is incorrect"
-msgstr "格式化(%s)是不正确的"
+msgstr "格式(%s)不正确"
+#: spyder/widgets/variableexplorer/arrayeditor.py:625
msgid "Arrays with more than 3 dimensions are not supported"
-msgstr "不支持超过3个维度的数组"
+msgstr "不支持三维以上的数组"
+#: spyder/widgets/variableexplorer/arrayeditor.py:629
msgid "The 'xlabels' argument length do no match array column number"
msgstr "“xlabels”参数长度不匹配数组的列数"
+#: spyder/widgets/variableexplorer/arrayeditor.py:633
msgid "The 'ylabels' argument length do no match array row number"
msgstr "“ylabels”参数长度不匹配的数组的行数"
+#: spyder/widgets/variableexplorer/arrayeditor.py:640
msgid "%s arrays"
msgstr "%s 阵列"
+#: spyder/widgets/variableexplorer/arrayeditor.py:641
msgid "%s are currently not supported"
msgstr "%s目前不支持"
+#: spyder/widgets/variableexplorer/arrayeditor.py:648
msgid "NumPy array"
msgstr "NumPy数组"
+#: spyder/widgets/variableexplorer/arrayeditor.py:650
+#: spyder/widgets/variableexplorer/arrayeditor.py:828
msgid "Array editor"
msgstr "数组编辑器"
+#: spyder/widgets/variableexplorer/arrayeditor.py:652
msgid "read only"
msgstr "只读"
+#: spyder/widgets/variableexplorer/arrayeditor.py:685
msgid "Record array fields:"
-msgstr ""
+msgstr "记录数组字段:"
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Data"
msgstr "数据"
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Mask"
msgstr ""
+#: spyder/widgets/variableexplorer/arrayeditor.py:697
msgid "Masked data"
msgstr ""
+#: spyder/widgets/variableexplorer/arrayeditor.py:708
msgid "Axis:"
-msgstr ""
+msgstr "轴:"
+#: spyder/widgets/variableexplorer/arrayeditor.py:713
msgid "Index:"
-msgstr ""
+msgstr "索引:"
+#: spyder/widgets/variableexplorer/arrayeditor.py:726
msgid "Warning: changes are applied separately"
-msgstr ""
+msgstr "警告:修改被单独应用"
+#: spyder/widgets/variableexplorer/arrayeditor.py:727
msgid ""
-"For performance reasons, changes applied to masked array won't be reflected in array's data (and vice-versa)."
+"For performance reasons, changes applied to masked array won't be reflected "
+"in array's data (and vice-versa)."
msgstr ""
+#: spyder/widgets/variableexplorer/arrayeditor.py:735
+#: spyder/widgets/variableexplorer/collectionseditor.py:1392
+#: spyder/widgets/variableexplorer/dataframeeditor.py:751
+#: spyder/widgets/variableexplorer/texteditor.py:67
+msgid "Save and Close"
+msgstr "保存并关闭"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:151
msgid "Index"
msgstr "索引"
+#: spyder/widgets/variableexplorer/collectionseditor.py:156
msgid "Tuple"
msgstr "元组"
+#: spyder/widgets/variableexplorer/collectionseditor.py:159
msgid "List"
msgstr "列表"
+#: spyder/widgets/variableexplorer/collectionseditor.py:162
msgid "Dictionary"
msgstr "目录"
+#: spyder/widgets/variableexplorer/collectionseditor.py:164
msgid "Key"
msgstr "关键字"
+#: spyder/widgets/variableexplorer/collectionseditor.py:169
msgid "Attribute"
msgstr "属性"
+#: spyder/widgets/variableexplorer/collectionseditor.py:173
msgid "elements"
msgstr "元素"
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Size"
msgstr "尺寸"
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Type"
msgstr "类型"
+#: spyder/widgets/variableexplorer/collectionseditor.py:350
msgid "Value"
msgstr "值"
+#: spyder/widgets/variableexplorer/collectionseditor.py:450
msgid ""
-"Spyder was unable to retrieve the value of this variable from the console.
The error mesage was:
%s"
-"i>"
+"Opening this variable can be slow\n"
+"\n"
+"Do you want to continue anyway?"
msgstr ""
+"打开这个变量可能很慢\n"
+"\n"
+"您想要继续吗?"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:461
+msgid ""
+"Spyder was unable to retrieve the value of this variable from the console."
+"
The error mesage was:
%s"
+msgstr "Spyder无法从控制台检索此变量的值。
错误消息是:
%s "
+#: spyder/widgets/variableexplorer/collectionseditor.py:643
msgid "Edit item"
msgstr "编辑条目"
+#: spyder/widgets/variableexplorer/collectionseditor.py:644
msgid "Unable to assign data to item.
Error message:
%s"
-msgstr ""
+msgstr "无法将数据赋值给项目。
错误消息:
%s"
+#: spyder/widgets/variableexplorer/collectionseditor.py:705
msgid "Resize rows to contents"
msgstr "调整行到内容大小"
+#: spyder/widgets/variableexplorer/collectionseditor.py:716
+#: spyder/widgets/variableexplorer/collectionseditor.py:1066
+#: spyder/widgets/variableexplorer/collectionseditor.py:1083
msgid "Plot"
msgstr "制图"
+#: spyder/widgets/variableexplorer/collectionseditor.py:720
msgid "Histogram"
msgstr "直方图"
+#: spyder/widgets/variableexplorer/collectionseditor.py:724
msgid "Show image"
msgstr "显示图片"
+#: spyder/widgets/variableexplorer/collectionseditor.py:728
+#: spyder/widgets/variableexplorer/collectionseditor.py:1091
msgid "Save array"
msgstr "保存数组"
+#: spyder/widgets/variableexplorer/collectionseditor.py:732
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Insert"
msgstr "插入"
-msgid "Remove"
-msgstr "移除"
-
+#: spyder/widgets/variableexplorer/collectionseditor.py:745
+#: spyder/widgets/variableexplorer/collectionseditor.py:991
msgid "Duplicate"
msgstr "重复"
+#: spyder/widgets/variableexplorer/collectionseditor.py:968
msgid "Do you want to remove the selected item?"
-msgstr "你确定要删除所选条目吗?"
+msgstr "您确定要删除所选条目吗?"
+#: spyder/widgets/variableexplorer/collectionseditor.py:969
msgid "Do you want to remove all selected items?"
-msgstr "你确定要删除所有选中的条目吗?"
+msgstr "您确定要删除所有选中的条目吗?"
+#: spyder/widgets/variableexplorer/collectionseditor.py:989
msgid "New variable name:"
msgstr "新变量名:"
+#: spyder/widgets/variableexplorer/collectionseditor.py:992
msgid "Variable name:"
msgstr "变量名:"
+#: spyder/widgets/variableexplorer/collectionseditor.py:1030
msgid "Key:"
msgstr "键:"
+#: spyder/widgets/variableexplorer/collectionseditor.py:1038
msgid "Value:"
msgstr "键值:"
+#: spyder/widgets/variableexplorer/collectionseditor.py:1054
msgid "Import error"
msgstr "导入错误"
+#: spyder/widgets/variableexplorer/collectionseditor.py:1055
msgid "Please install matplotlib or guiqwt."
-msgstr ""
+msgstr "请安装matplotlib或guiqwt。"
+#: spyder/widgets/variableexplorer/collectionseditor.py:1067
msgid "Unable to plot data.
Error message:
%s"
-msgstr ""
+msgstr "无法绘制数据。
错误信息:
%s"
+#: spyder/widgets/variableexplorer/collectionseditor.py:1084
msgid "Unable to show image.
Error message:
%s"
-msgstr ""
+msgstr "无法显示图像。
错误信息:
%s"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1097
+msgid "NumPy arrays"
+msgstr "NumPy数组"
+#: spyder/widgets/variableexplorer/collectionseditor.py:1107
msgid "Unable to save array
Error message:
%s"
-msgstr ""
+msgstr "无法保存数组
错误消息:
%s"
+#: spyder/widgets/variableexplorer/collectionseditor.py:1132
msgid "It was not possible to copy this array"
-msgstr ""
+msgstr "不可能复制这个数组"
+#: spyder/widgets/variableexplorer/collectionseditor.py:1144
+msgid "It was not possible to copy this dataframe"
+msgstr "无法复制dataframe"
+
+#: spyder/widgets/variableexplorer/collectionseditor.py:1166
msgid "Clipboard contents"
msgstr "剪贴板内容"
+#: spyder/widgets/variableexplorer/collectionseditor.py:1181
msgid "Import from clipboard"
msgstr "从剪贴板导入"
+#: spyder/widgets/variableexplorer/collectionseditor.py:1183
msgid "Empty clipboard"
msgstr "空剪切板"
+#: spyder/widgets/variableexplorer/collectionseditor.py:1184
msgid "Nothing to be imported from clipboard."
-msgstr "没有从剪贴板导入任何内容"
+msgstr "没有从剪贴板导入任何内容。"
+
+#: spyder/widgets/variableexplorer/dataframeeditor.py:321
+msgid ""
+"It is not possible to display this value because\n"
+"an error ocurred while trying to do it"
+msgstr "由于尝试执行此操作时发生错误,因此无法显示此值"
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To bool"
msgstr "转为布尔值"
+#: spyder/widgets/variableexplorer/dataframeeditor.py:621
msgid "To complex"
-msgstr ""
+msgstr "转为复数"
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To float"
msgstr "转为浮点"
+#: spyder/widgets/variableexplorer/dataframeeditor.py:622
msgid "To int"
msgstr "转为整型"
+#: spyder/widgets/variableexplorer/dataframeeditor.py:623
msgid "To str"
msgstr "转为字符串"
+#: spyder/widgets/variableexplorer/dataframeeditor.py:707
msgid "%s editor"
-msgstr ""
+msgstr "%s 编辑器"
+#: spyder/widgets/variableexplorer/dataframeeditor.py:742
msgid "Column min/max"
-msgstr ""
+msgstr "最大/最小列"
+#: spyder/widgets/variableexplorer/dataframeeditor.py:796
msgid "Format ({}) is incorrect"
-msgstr ""
+msgstr "格式({})不正确"
+#: spyder/widgets/variableexplorer/dataframeeditor.py:800
msgid "Format ({}) should start with '%'"
-msgstr ""
+msgstr "格式({})应当以'%'开头"
+#: spyder/widgets/variableexplorer/importwizard.py:118
+#: spyder/widgets/variableexplorer/importwizard.py:438
msgid "Import as"
msgstr "导入为"
+#: spyder/widgets/variableexplorer/importwizard.py:120
msgid "data"
-msgstr ""
+msgstr "数据"
+#: spyder/widgets/variableexplorer/importwizard.py:124
msgid "code"
msgstr "代码"
+#: spyder/widgets/variableexplorer/importwizard.py:127
+#: spyder/widgets/variableexplorer/importwizard.py:514
msgid "text"
msgstr "文本"
+#: spyder/widgets/variableexplorer/importwizard.py:140
msgid "Column separator:"
msgstr "列分隔符:"
+#: spyder/widgets/variableexplorer/importwizard.py:144
msgid "Tab"
-msgstr ""
+msgstr "Tab"
+#: spyder/widgets/variableexplorer/importwizard.py:147
+msgid "Whitespace"
+msgstr "空白"
+
+#: spyder/widgets/variableexplorer/importwizard.py:150
+#: spyder/widgets/variableexplorer/importwizard.py:168
msgid "other"
-msgstr ""
+msgstr "其他"
+#: spyder/widgets/variableexplorer/importwizard.py:161
msgid "Row separator:"
-msgstr ""
+msgstr "行分隔符:"
+#: spyder/widgets/variableexplorer/importwizard.py:165
msgid "EOL"
-msgstr ""
+msgstr "行尾EOL"
+#: spyder/widgets/variableexplorer/importwizard.py:180
msgid "Additional options"
-msgstr ""
+msgstr "更多选项"
+#: spyder/widgets/variableexplorer/importwizard.py:184
msgid "Skip rows:"
-msgstr ""
+msgstr "跳过行:"
+#: spyder/widgets/variableexplorer/importwizard.py:195
msgid "Comments:"
-msgstr ""
+msgstr "注释:"
+#: spyder/widgets/variableexplorer/importwizard.py:201
msgid "Transpose"
-msgstr ""
+msgstr "颠倒"
+#: spyder/widgets/variableexplorer/importwizard.py:441
msgid "array"
-msgstr ""
+msgstr "数组"
+#: spyder/widgets/variableexplorer/importwizard.py:446
msgid "list"
-msgstr ""
+msgstr "列表"
+#: spyder/widgets/variableexplorer/importwizard.py:451
msgid "DataFrame"
msgstr "DataFrame"
+#: spyder/widgets/variableexplorer/importwizard.py:497
+#: spyder/widgets/variableexplorer/importwizard.py:581
msgid "Import wizard"
-msgstr ""
+msgstr "导入向导"
+#: spyder/widgets/variableexplorer/importwizard.py:502
msgid "Raw text"
msgstr "原始文本"
+#: spyder/widgets/variableexplorer/importwizard.py:505
msgid "variable_name"
msgstr ""
+#: spyder/widgets/variableexplorer/importwizard.py:516
msgid "table"
-msgstr ""
+msgstr "表"
+#: spyder/widgets/variableexplorer/importwizard.py:517
msgid "Preview"
msgstr "预览"
+#: spyder/widgets/variableexplorer/importwizard.py:521
msgid "Variable Name"
msgstr "变量名"
+#: spyder/widgets/variableexplorer/importwizard.py:544
msgid "Done"
msgstr "完成"
-msgid "Unable to proceed to next step
Please check your entries.
Error message:
%s"
+#: spyder/widgets/variableexplorer/importwizard.py:582
+msgid ""
+"Unable to proceed to next step
Please check your entries."
+"
Error message:
%s"
msgstr ""
+"无法继续下一步
请检查您填写的条目是否正确。
错误信息:"
+"
%s"
-msgid "Refresh"
-msgstr "刷新"
-
-msgid "Refresh periodically"
-msgstr "定期刷新"
-
+#: spyder/widgets/variableexplorer/namespacebrowser.py:184
+#: spyder/widgets/variableexplorer/namespacebrowser.py:397
msgid "Import data"
msgstr "导入数据"
+#: spyder/widgets/variableexplorer/namespacebrowser.py:187
+#: spyder/widgets/variableexplorer/namespacebrowser.py:477
+#: spyder/widgets/variableexplorer/namespacebrowser.py:491
+#: spyder/plugins/profiler/widgets/profilergui.py:121
msgid "Save data"
msgstr "保存数据"
+#: spyder/widgets/variableexplorer/namespacebrowser.py:192
msgid "Save data as..."
msgstr "数据另存为..."
+#: spyder/widgets/variableexplorer/namespacebrowser.py:204
msgid "Exclude references which name starts with an underscore"
-msgstr ""
+msgstr "排除以下划线开头的名字"
+#: spyder/widgets/variableexplorer/namespacebrowser.py:212
msgid "Exclude references which name is uppercase"
-msgstr ""
+msgstr "排除全大写的名字"
+#: spyder/widgets/variableexplorer/namespacebrowser.py:219
msgid "Exclude references which name starts with an uppercase character"
-msgstr ""
+msgstr "排除以大写字母开头的名字"
+
+#: spyder/widgets/variableexplorer/namespacebrowser.py:227
+msgid ""
+"Exclude references to unsupported data types (i.e. which won't be handled/"
+"saved correctly)"
+msgstr "排除具有不支持数据类型的名字(因为无法被正确处理和保存)"
-msgid "Exclude references to unsupported data types (i.e. which won't be handled/saved correctly)"
+#: spyder/widgets/variableexplorer/namespacebrowser.py:306
+msgid ""
+"The object you are trying to modify is too big to be sent back to the "
+"kernel. Therefore, your modifications won't take place."
msgstr ""
+"您尝试修改的对象太大而无法发送回 IPython kernel。因此,您的修改不会生效。"
+#: spyder/widgets/variableexplorer/namespacebrowser.py:417
msgid ""
-"Unsupported file extension '%s'
Would you like to import it anyway (by selecting a known file "
-"format)?"
+"Unsupported file extension '%s'
Would you like to import it "
+"anyway (by selecting a known file format)?"
msgstr ""
+"不支持的文件扩展名 '%s'
无论如何都要导入吗?(需要手动指定它为"
+"一种已知的文件格式)"
+#: spyder/widgets/variableexplorer/namespacebrowser.py:425
msgid "Open file as:"
msgstr "文件打开为:"
+#: spyder/widgets/variableexplorer/namespacebrowser.py:459
msgid "Unable to load '%s'
Error message:
%s"
-msgstr ""
+msgstr "无法加载:'%s'
错误信息:
%s"
+#: spyder/widgets/variableexplorer/namespacebrowser.py:492
msgid "Unable to save current workspace
Error message:
%s"
-msgstr ""
+msgstr "无法保存当前工作区
错误信息:
%s"
+#: spyder/widgets/variableexplorer/texteditor.py:84
msgid "Text editor"
-msgstr ""
+msgstr "文本编辑器"
-msgid "View and edit DataFrames and Series in the Variable Explorer"
-msgstr ""
+#: spyder/workers/updates.py:128 spyder/workers/updates.py:130
+msgid "Unable to retrieve information."
+msgstr "无法获取信息。"
-msgid "View and edit two and three dimensional arrays in the Variable Explorer"
-msgstr ""
+#: spyder/workers/updates.py:132
+msgid ""
+"Unable to connect to the internet.
Make sure the connection is "
+"working properly."
+msgstr "无法连接到互联网。
请确保您的网络工作正常。"
-msgid "Unable to retrieve information."
+#: spyder/workers/updates.py:135
+msgid "Unable to check for updates."
+msgstr "检查更新失败。"
+
+#: spyder/plugins/breakpoints/plugin.py:45
+msgid "Breakpoints"
+msgstr "断点"
+
+#: spyder/plugins/breakpoints/plugin.py:80
+msgid "List breakpoints"
+msgstr "列出所有断点"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "Condition"
+msgstr "条件"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:97
+msgid "Line"
+msgstr "行"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:201
+msgid "Clear this breakpoint"
+msgstr "清除断点"
+
+#: spyder/plugins/breakpoints/widgets/breakpointsgui.py:206
+msgid "Edit this breakpoint"
+msgstr "编辑断点"
+
+#: spyder/plugins/profiler/plugin.py:33 spyder/plugins/pylint/plugin.py:47
+msgid "Results"
+msgstr "结果"
+
+#: spyder/plugins/profiler/plugin.py:34
+msgid ""
+"Profiler plugin results (the output of python's profile/cProfile)\n"
+"are stored here:"
+msgstr "Profiler插件生成的结果(profiler/cprofiler的输出)存储于此:"
+
+#: spyder/plugins/profiler/plugin.py:75
+msgid "Profiler"
+msgstr "性能分析"
+
+#: spyder/plugins/profiler/plugin.py:104
+#: spyder/plugins/profiler/widgets/profilergui.py:81
+msgid "Profile"
+msgstr "性能分析"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:82
+msgid "Run profiler"
+msgstr "运行Profiler"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:88
+msgid "Stop current profiling"
+msgstr "停止当前Profiler"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:96
+#: spyder/plugins/profiler/widgets/profilergui.py:219
+msgid "Select Python script"
+msgstr "选择Python脚本"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:102
+#: spyder/plugins/pylint/widgets/pylintgui.py:224
+msgid "Output"
+msgstr "输出"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:104
+msgid "Show program's output"
+msgstr "显示程序输出"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:113
+msgid "Collapse one level up"
+msgstr "折叠一级"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:118
+msgid "Expand one level down"
+msgstr "展开一级"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:124
+msgid "Save profiling data"
+msgstr "保存性能分析数据"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:126
+msgid "Load data"
+msgstr "加载数据"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:129
+msgid "Load profiling data for comparison"
+msgstr "加载性能分析数据以比较"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:131
+msgid "Clear comparison"
+msgstr "清空比较"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:171
+msgid "Please install"
+msgstr "请安装"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:172
+msgid "the Python profiler modules"
+msgstr "python profiler 模块"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:179
+msgid "Save profiler result"
+msgstr "保存性能分析数据"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:182
+#: spyder/plugins/profiler/widgets/profilergui.py:188
+msgid "Profiler result"
+msgstr "性能分析结果"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:187
+msgid "Select script to compare"
+msgstr "选择脚本以比较"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:227
+#: spyder/plugins/profiler/widgets/profilergui.py:232
+msgid "Profiler output"
+msgstr "性能分析输出"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:251
+msgid "Profiling, please wait..."
+msgstr "性能分析中,请等待..."
+
+#: spyder/plugins/profiler/widgets/profilergui.py:343
+msgid "Sorting data, please wait..."
+msgstr "排序数据,请等待..."
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Function/Module"
+msgstr "函数/模块"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+msgid "Total Time"
+msgstr "总时长"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:389
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Diff"
+msgstr "差异"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Calls"
+msgstr "调用"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:390
+msgid "Local Time"
+msgstr "局部时长"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:391
+msgid "File:line"
msgstr ""
-msgid "Unable to connect to the internet.
Make sure the connection is working properly."
+#: spyder/plugins/profiler/widgets/profilergui.py:565
+msgid "Function or module name"
+msgstr "函数或模块名"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:569
+msgid "Time in function (including sub-functions)"
+msgstr "函数耗时(包括子函数调用)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:578
+msgid "Local time in function (not in sub-functions)"
+msgstr "函数局部耗时(不包括子函数调用)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:588
+msgid "Total number of calls (including recursion)"
+msgstr "总调用次数(包括递归调用)"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:598
+msgid "File:line where function is defined"
+msgstr "File:line 函数定义位置"
+
+#: spyder/plugins/profiler/widgets/profilergui.py:603
+msgid "recursion"
+msgstr "递归"
+
+#: spyder/plugins/pylint/plugin.py:36
+msgid "Save file before analyzing it"
+msgstr "分析前保存文件"
+
+#: spyder/plugins/pylint/plugin.py:40
+msgid "The following option will be applied at next startup."
+msgstr "下面的选项会在下次启动时应用。"
+
+#: spyder/plugins/pylint/plugin.py:43
+msgid "History: "
+msgstr "历史: "
+
+#: spyder/plugins/pylint/plugin.py:44
+msgid " results"
+msgstr " 结果"
+
+#: spyder/plugins/pylint/plugin.py:48
+msgid "Results are stored here:"
+msgstr "结果保存于:"
+
+#: spyder/plugins/pylint/plugin.py:98
+#: spyder/plugins/pylint/widgets/pylintgui.py:83
+msgid "Static code analysis"
+msgstr "静态代码分析"
+
+#: spyder/plugins/pylint/plugin.py:133
+msgid "Run static code analysis"
+msgstr "运行静态代码分析"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:117
+msgid "Results for "
msgstr ""
-msgid "Unable to check for updates."
-msgstr "检查更新失败"
+#: spyder/plugins/pylint/widgets/pylintgui.py:122
+msgid "Convention"
+msgstr "约定"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:124
+msgid "Refactor"
+msgstr "重构"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:206
+msgid "Analyze"
+msgstr "分析"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:207
+msgid "Run analysis"
+msgstr "运行分析"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:212
+msgid "Stop current analysis"
+msgstr "停止分析"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:218
+#: spyder/plugins/pylint/widgets/pylintgui.py:288
+msgid "Select Python file"
+msgstr "选择Python文件"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:226
+msgid "Complete output"
+msgstr "完整输出"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:260
+msgid "Pylint script was not found. Please add \"%s\" to PATH."
+msgstr "找不到Pylint脚本,请添加 \"%s\" 到 PATH。"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:263
+msgid "Please install pylint:"
+msgstr "请安装pylint:"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:326
+msgid "Pylint output"
+msgstr "Pylint输出"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:465
+msgid "Source code has not been rated yet."
+msgstr "源码尚未评估。"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:471
+msgid "Analysis did not succeed (see output for more details)."
+msgstr "分析未完成(查看输出了解更多细节)。"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:484
+msgid "Global evaluation:"
+msgstr "全局求值:"
+
+#: spyder/plugins/pylint/widgets/pylintgui.py:488
+msgid "previous run:"
+msgstr "上次运行:"
+
+#~ msgid "Qt examples"
+#~ msgstr "Qt例子"
+
+#~ msgid "ViTables"
+#~ msgstr "ViTables"
+
+#~ msgid "Loading external console..."
+#~ msgstr "加载外部控制台…"
+
+#~ msgid "The Python console"
+#~ msgstr "Python控制台"
+
+#~ msgid ""
+#~ "You can also run your code on a Python console. These consoles are useful "
+#~ "because they let you run a file in a console dedicated only to it.To "
+#~ "select this behavior, please press the F6 key.
By pressing "
+#~ "the button below and then focusing the Variable Explorer, you will notice "
+#~ "that Python consoles are also connected to that pane, and that the "
+#~ "Variable Explorer only shows the variables of the currently focused "
+#~ "console."
+#~ msgstr ""
+#~ "你也可以在Python控制台里执行你的代码。你可以在一个终端里专门执行一个文件。"
+#~ "你可以按F6选择这个行为。
按下下面的按钮,然后注意变量资源管"
+#~ "理器,你会发现Python终端同时与变量资源管理器联动了,变量资源管理器中仅展示"
+#~ "焦点所在Python终端内的变量。"
+
+#~ msgid ""
+#~ "Update LANGUAGE_CODES (inside config/base.py) if a new translation has "
+#~ "been added to Spyder"
+#~ msgstr ""
+#~ "在为 Spyder 加入新的语言后,请更新 LANGUAGE_CODES(在 config/base.py)"
+
+#~ msgid "Pop up internal console when internal errors appear"
+#~ msgstr "出现内部错误时弹出内部控制台"
+
+#~ msgid "Sort files according to full path"
+#~ msgstr "按完整路径排序文件"
+
+#~ msgid "&Configure..."
+#~ msgstr "配置(&C)"
+
+#~ msgid "Show TODO/FIXME/XXX/HINT/TIP/@todo comments list"
+#~ msgstr "显示TODO/FIXME/XXX/HINT/TIP/@todo注释列表"
+
+#~ msgid "Interactive data plotting in the consoles"
+#~ msgstr "控制台中的交互式数据绘图"
+
+#~ msgid "Python console"
+#~ msgstr "Python控制台"
+
+#~ msgid "One tab per script"
+#~ msgstr "每个脚本一个标签"
+
+#~ msgid "Buffer: "
+#~ msgstr "缓冲区: "
+
+#~ msgid "Merge process standard output/error channels"
+#~ msgstr "合并进程标准输出/错误通道"
+
+#~ msgid "Colorize standard error channel using ANSI escape codes"
+#~ msgstr "使用标准误差通道使用ANSI转义码"
+
+#~ msgid ""
+#~ "This option will be applied the next time a Python console or a terminal "
+#~ "is opened."
+#~ msgstr "下次打开Python控制台或终端时,将应用此选项。"
+
+#~ msgid "Light background (white color)"
+#~ msgstr "浅色背景(白色)"
+
+#~ msgid "PYTHONSTARTUP replacement"
+#~ msgstr "PYTHONSTARTUP替代"
+
+#~ msgid "Default PYTHONSTARTUP script"
+#~ msgstr "默认PYTHONSTARTUP脚本"
+
+#~ msgid "Use the following startup script:"
+#~ msgstr "使用以下启动脚本:"
+
+#~ msgid "Monitor"
+#~ msgstr "监控"
+
+#~ msgid ""
+#~ "The monitor provides introspection features to console: code completion, "
+#~ "calltips and variable explorer. Because it relies on several modules, "
+#~ "disabling the monitor may be useful to accelerate console startup."
+#~ msgstr ""
+#~ "显示器提供用于控制台的自省功能︰ 代码完成、 调用提示 和变量资源管理器。因"
+#~ "为它依赖于几个模块,禁用显示器可能有助于加速控制台启动。"
+
+#~ msgid "Enable monitor"
+#~ msgstr "启用监视器"
+
+#~ msgid "Default library"
+#~ msgstr "缺省库"
+
+#~ msgid "Qt-Python Bindings"
+#~ msgstr "Qt-Python绑定"
+
+#~ msgid "Library:"
+#~ msgstr "库:"
+
+#~ msgid ""
+#~ "This option will act on
libraries such as Matplotlib, guidata or ETS"
+#~ msgstr "该选项将作用于 Matplotlib, guidata 或 ETS等库"
+
+#~ msgid ""
+#~ "Decide which backend to use to display graphics. If unsure, please select "
+#~ "the Automatic backend.
Note: We support a very "
+#~ "limited number of backends in our Python consoles. If you prefer to work "
+#~ "with a different one, please use an IPython console."
+#~ msgstr ""
+#~ "决定使用哪个后台来显示图形。如果未能确定,请选择自动后端。"
+#~ "
提示:我们在Python控制台上支持有限数量的后台。如果你希望用不"
+#~ "同的后端工作,请使用IPython控制台。"
+
+#~ msgid "None"
+#~ msgstr "None"
+
+#~ msgid "Enthought Tool Suite"
+#~ msgstr "Enthought工具套件"
+
+#~ msgid ""
+#~ "Enthought Tool Suite (ETS) supports PyQt4 (qt4) and wxPython (wx) "
+#~ "graphical user interfaces."
+#~ msgstr ""
+#~ "Enthought工具套件(ETS)支持PyQt4(Qt4)和wxPython(Wx)图形用户界面。"
+
+#~ msgid "ETS_TOOLKIT:"
+#~ msgstr "ETS_TOOLKIT:"
+
+#~ msgid "External modules"
+#~ msgstr "外部模块"
+
+#~ msgid ""
+#~ "No Python console is currently selected to run %s.
Please "
+#~ "select or open a new Python console and try again."
+#~ msgstr ""
+#~ "当前没有为运行%s选择Python控制台.
请选择或打开一个新的Python"
+#~ "控制台并尝试重新运行。"
+
+#~ msgid "Command Window"
+#~ msgstr "命令窗口"
+
+#~ msgid "Open a &Python console"
+#~ msgstr "打开一个Python控制台(&P)"
+
+#~ msgid "Open &command prompt"
+#~ msgstr "打开命令提示符(&C)"
+
+#~ msgid "Open a Windows command prompt"
+#~ msgstr "打开一个Windows命令提示符"
+
+#~ msgid "Open a &terminal"
+#~ msgstr "打开一个终端(&T)"
+
+#~ msgid "Open a terminal window"
+#~ msgstr "打开一个终端窗口"
+
+#~ msgid "Python Console"
+#~ msgstr "Python控制台"
+
+#~ msgid ""
+#~ "Please enter the connection info of the kernel you want to connect to. "
+#~ "For that you can either select its JSON connection file using the "
+#~ "Browse button, or write directly its id, in case it's a local "
+#~ "kernel (for example kernel-3764.json or just 3764)."
+#~ msgstr ""
+#~ "请输入要连接的核心的连接信息。 为此,您可以使用 Browse 按钮选择其"
+#~ "JSON连接文件,或直接写入其ID,以防它是本地核心(例如 kernel-3764.json "
+#~ "或 只是 3764 )。"
+
+#~ msgid "Connection info:"
+#~ msgstr "连接信息:"
+
+#~ msgid "Ssh key"
+#~ msgstr "SSH密钥"
+
+#~ msgid "Select ssh key"
+#~ msgstr "选择SSH密钥"
+
+#~ msgid "Light background"
+#~ msgstr "浅背景"
+
+#~ msgid "Dark background"
+#~ msgstr "深色背景"
+
+#~ msgid "Use the greedy completer"
+#~ msgstr "使用贪心补全"
+
+#~ msgid "Working directory:"
+#~ msgstr "工作目录:"
+
+#~ msgid "Dedicated Python console"
+#~ msgstr "专用的Python控制台"
+
+#~ msgid "Show warning when killing running process"
+#~ msgstr "在运行过程中显示警告"
+
+#~ msgid "Run Settings"
+#~ msgstr "运行设置"
+
+#~ msgid "the script directory"
+#~ msgstr "剧本目录"
+
+#~ msgid "Show warning when killing running processes"
+#~ msgstr "结束运行进程时显示警告"
+
+#~ msgid "Autorefresh"
+#~ msgstr "自动刷新"
+
+#~ msgid "Enable autorefresh"
+#~ msgstr "启用自动刷新"
+
+#~ msgid "Refresh interval: "
+#~ msgstr "刷新间隔: "
+
+#~ msgid "At startup, the global working directory is:"
+#~ msgstr "启动时,全局工作路径是:"
+
+#~ msgid "the same as in last session"
+#~ msgstr "与上次会话相同"
+
+#~ msgid ""
+#~ "At startup, Spyder will restore the global directory from last session"
+#~ msgstr "在启动时,Spyder将从最后一次会话恢复全局目录"
+
+#~ msgid "Files are opened from:"
+#~ msgstr "打开文件自:"
+
+#~ msgid "the current file directory"
+#~ msgstr "当前文件目录"
+
+#~ msgid "the global working directory"
+#~ msgstr "全局工作目录"
+
+#~ msgid "Change to file base directory"
+#~ msgstr "更改为文件根目录"
+
+#~ msgid "When opening a file"
+#~ msgstr "打开文件时"
+
+#~ msgid "When saving a file"
+#~ msgstr "保存文件时"
+
+#~ msgid "Global working directory"
+#~ msgstr "全局工作目录"
+
+#~ msgid "Supported files"
+#~ msgstr "支持的文件"
+
+#~ msgid "All files (*.*)"
+#~ msgstr "所有文件(*.*)"
+
+#~ msgid "Spyder data files"
+#~ msgstr "Spyder的数据文件"
+
+#~ msgid "NumPy zip arrays"
+#~ msgstr "NumPy压缩阵列"
+
+#~ msgid "Matlab files"
+#~ msgstr "Matlab文件"
+
+#~ msgid "CSV text files"
+#~ msgstr "CSV文本文件"
+
+#~ msgid "JPEG images"
+#~ msgstr "JPEG图像"
+
+#~ msgid "PNG images"
+#~ msgstr "PNG图像"
+
+#~ msgid "GIF images"
+#~ msgstr "GIF图像"
+
+#~ msgid "TIFF images"
+#~ msgstr "TIFF图像"
+
+#~ msgid "Pickle files"
+#~ msgstr "Pickle文件"
+
+#~ msgid "JSON files"
+#~ msgstr "JSON文件"
+
+#~ msgid "Unsupported file type '%s'"
+#~ msgstr "不支持的文件类型 '%s'"
+
+#~ msgid "Save"
+#~ msgstr "保存"
+
+#~ msgid "Unable to save script '%s'
Error message:
%s"
+#~ msgstr "无法保存脚本 '%s'
错误信息:
%s"
+
+#~ msgid "Parent"
+#~ msgstr "上一层"
+
+#~ msgid "Run again this program"
+#~ msgstr "再次运行此程序"
+
+#~ msgid "Kill"
+#~ msgstr "结束"
+
+#~ msgid "Kills the current process, causing it to exit immediately"
+#~ msgstr "结束当前进程,使其立刻退出"
+
+#~ msgid "Running..."
+#~ msgstr "运行中..."
+
+#~ msgid "Terminated."
+#~ msgstr "终止。"
+
+#~ msgid "Command line arguments:"
+#~ msgstr "命令行参数:"
+
+#~ msgid "Variables"
+#~ msgstr "变量"
+
+#~ msgid "Show/hide global variables explorer"
+#~ msgstr "显示/隐藏全局变量资源管理器"
+
+#~ msgid "Terminate"
+#~ msgstr "终止"
+
+#~ msgid "Interact"
+#~ msgstr "互动"
+
+#~ msgid "Debug"
+#~ msgstr "调试"
+
+#~ msgid "Arguments..."
+#~ msgstr "参数..."
+
+#~ msgid "Arguments: %s"
+#~ msgstr "参数:%s"
+
+#~ msgid "No argument"
+#~ msgstr "无参数"
+
+#~ msgid "A Python console failed to start!"
+#~ msgstr "一个Python控制台启动失败!"
+
+#~ msgid "Process failed to start"
+#~ msgstr "进程启动失败"
+
+#~ msgid "Included filenames pattern"
+#~ msgstr "包含文件名模式"
+
+#~ msgid "Include:"
+#~ msgstr "包含:"
+
+#~ msgid "PYTHONPATH"
+#~ msgstr "PYTHONPATH"
+
+#~ msgid ""
+#~ "Search in all directories listed in sys.path which are outside the Python "
+#~ "installation directory"
+#~ msgstr "在所有 sys.path 里,Python安装目录外的目录里搜索"
+
+#~ msgid "Hg repository"
+#~ msgstr "Hg仓库"
+
+#~ msgid "Search in current directory hg repository"
+#~ msgstr "在当前hg仓库目录中搜索"
+
+#~ msgid "Here:"
+#~ msgstr "在这:"
+
+#~ msgid "Search recursively in this directory"
+#~ msgstr "在这个目录中递归搜索"
+
+#~ msgid "Browse a search directory"
+#~ msgstr "浏览搜索目录"
+
+#~ msgid "Search canceled"
+#~ msgstr "搜索取消"
+
+#~ msgid "interrupted"
+#~ msgstr "暂停"
+
+#~ msgid "Reset namespace"
+#~ msgstr "重置命名空间"
+
+#~ msgid ""
+#~ "Inspecting and setting values while debugging in IPython consoles is not "
+#~ "supported yet by Spyder."
+#~ msgstr "Spyder暂不支持在IPython终端调试时查看和设置值"
+
+#~ msgid "Reset IPython namespace"
+#~ msgstr "重置IPython命名空间"
+
+#~ msgid "Refresh"
+#~ msgstr "刷新"
+
+#~ msgid "Refresh periodically"
+#~ msgstr "定期刷新"
diff --git a/spyder/otherplugins.py b/spyder/otherplugins.py
index 664b722c337..6be35ce9236 100644
--- a/spyder/otherplugins.py
+++ b/spyder/otherplugins.py
@@ -60,7 +60,8 @@ def _get_spyderplugins(plugin_path, is_io, modnames, modlist):
continue
# Skip names that end in certain suffixes
- forbidden_suffixes = ['dist-info', 'egg.info', 'egg-info', 'egg-link']
+ forbidden_suffixes = ['dist-info', 'egg.info', 'egg-info', 'egg-link',
+ 'kernels']
if any([name.endswith(s) for s in forbidden_suffixes]):
continue
@@ -87,7 +88,7 @@ def _import_plugin(module_name, plugin_path, modnames, modlist):
module = None
# Then restore the actual loaded module instead of the mock
- if module:
+ if module and getattr(module, 'PLUGIN_CLASS', False):
sys.modules[module_name] = module
modlist.append(module)
modnames.append(module_name)
@@ -103,27 +104,20 @@ def _import_module_from_path(module_name, plugin_path):
Return None if no module is found.
"""
module = None
- if PY2:
- info = imp.find_module(module_name, [plugin_path])
- if info:
- module = imp.load_module(module_name, *info)
- elif sys.version_info[0:2] <= (3, 3):
- loader = importlib.machinery.PathFinder.find_module(
- module_name,
- [plugin_path])
- if loader:
- module = loader.load_module(module_name)
- else: # Python 3.4+
- spec = importlib.machinery.PathFinder.find_spec(
- module_name,
- [plugin_path])
- if spec:
- # Needed to prevent an error when 'spec.loader' is None
- # See issue 6518
- try:
+ try:
+ if PY2:
+ info = imp.find_module(module_name, [plugin_path])
+ if info:
+ module = imp.load_module(module_name, *info)
+ else: # Python 3.4+
+ spec = importlib.machinery.PathFinder.find_spec(
+ module_name,
+ [plugin_path])
+ if spec:
module = spec.loader.load_module(module_name)
- except AttributeError:
- module = None
+ except Exception:
+ pass
+
return module
diff --git a/spyder/pil_patch.py b/spyder/pil_patch.py
index 885c5a219d7..289a4343649 100644
--- a/spyder/pil_patch.py
+++ b/spyder/pil_patch.py
@@ -24,7 +24,7 @@
===============================================================================
Another example on Windows (actually that's the same, but this is the exact
-case encountered with Spyder when the global working directory is the
+case encountered with Spyder when the global working directory is the
site-packages directory):
===============================================================================
C:\Python27\Lib\site-packages>python
diff --git a/spyder/plugins/__init__.py b/spyder/plugins/__init__.py
index a7c7deb3373..ac3ff3e9b67 100644
--- a/spyder/plugins/__init__.py
+++ b/spyder/plugins/__init__.py
@@ -7,6 +7,3 @@
"""
Spyder core plugins
"""
-
-# For backwards compatibility with Spyder 3.0
-from spyder.api.plugins import SpyderPluginWidget # analysis:ignore
diff --git a/spyder/plugins/base.py b/spyder/plugins/base.py
index cf1092538fe..dab94740fb9 100644
--- a/spyder/plugins/base.py
+++ b/spyder/plugins/base.py
@@ -9,44 +9,69 @@
"""
# Third party imports
+import qdarkstyle
from qtpy.QtCore import Qt, Slot
from qtpy.QtGui import QKeySequence
-from qtpy.QtWidgets import QDockWidget, QMainWindow, QShortcut, QWidget
+from qtpy.QtWidgets import QDockWidget, QMainWindow, QShortcut
# Local imports
from spyder.config.base import _
-from spyder.config.gui import get_font
+from spyder.config.gui import is_dark_interface, get_font
from spyder.config.main import CONF
+from spyder.py3compat import is_text_string
from spyder.utils import icon_manager as ima
from spyder.utils.qthelpers import create_action
from spyder.widgets.dock import SpyderDockWidget
+class PluginWindow(QMainWindow):
+ """MainWindow subclass that contains a Spyder Plugin."""
-class PluginMainWindow(QMainWindow):
- """Spyder Plugin MainWindow class."""
def __init__(self, plugin):
QMainWindow.__init__(self)
self.plugin = plugin
+ # Setting interface theme
+ if is_dark_interface():
+ self.setStyleSheet(qdarkstyle.load_stylesheet_from_environment())
+
def closeEvent(self, event):
"""Reimplement Qt method."""
self.plugin.dockwidget.setWidget(self.plugin)
self.plugin.dockwidget.setVisible(True)
- self.plugin.undock_action.setDisabled(False)
self.plugin.switch_to_plugin()
QMainWindow.closeEvent(self, event)
+ self.plugin.undocked_window = None
-
-class BasePluginWidget(QWidget):
- """
- Basic functionality for Spyder plugin widgets
- """
+class BasePluginMixin(object):
+ """Basic functionality for Spyder plugin widgets."""
ALLOWED_AREAS = Qt.AllDockWidgetAreas
LOCATION = Qt.LeftDockWidgetArea
- FEATURES = QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetFloatable
+ FEATURES = QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetMovable
+
+ def __init__(self, parent=None):
+ super(BasePluginMixin, self).__init__()
+
+ # Additional actions
+ self.dock_action = create_action(self,
+ _("Dock"),
+ icon=ima.icon('dock'),
+ tip=_("Dock the pane"),
+ triggered=self.close_window)
+
+ self.undock_action = create_action(self,
+ _("Undock"),
+ icon=ima.icon('undock'),
+ tip=_("Undock the pane"),
+ triggered=self.create_window)
+
+ self.close_plugin_action = create_action(self,
+ _("Close"),
+ icon=ima.icon('close_pane'),
+ tip=_("Close the pane"),
+ triggered=self.plugin_closed)
def initialize_plugin_in_mainwindow_layout(self):
"""
@@ -75,38 +100,30 @@ def update_margins(self):
layout.setContentsMargins(*self.default_margins)
def update_plugin_title(self):
- """Update plugin title, i.e. dockwidget or mainwindow title"""
+ """Update plugin title, i.e. dockwidget or window title"""
if self.dockwidget is not None:
win = self.dockwidget
- elif self.mainwindow is not None:
- win = self.mainwindow
+ elif self.undocked_window is not None:
+ win = self.undocked_window
else:
return
win.setWindowTitle(self.get_plugin_title())
def create_dockwidget(self):
"""Add to parent QMainWindow as a dock widget"""
+ # Creating dock widget
+ dock = SpyderDockWidget(self.get_plugin_title(), self.main)
- # This is not clear yet why the following do not work...
- # (see Issue #880)
-## # Using Qt.Window window flags solves Issue #880 (detached dockwidgets
-## # are not painted after restarting Spyder and restoring their hexstate)
-## # but it does not work with PyQt <=v4.7 (dockwidgets can't be docked)
-## # or non-Windows platforms (lot of warnings are printed out)
-## # (so in those cases, we use the default window flags: Qt.Widget):
-## flags = Qt.Widget if is_old_pyqt or os.name != 'nt' else Qt.Window
- dock = SpyderDockWidget(self.get_plugin_title(), self.main)#, flags)
-
+ # Set properties
dock.setObjectName(self.__class__.__name__+"_dw")
dock.setAllowedAreas(self.ALLOWED_AREAS)
dock.setFeatures(self.FEATURES)
dock.setWidget(self)
self.update_margins()
dock.visibilityChanged.connect(self.visibility_changed)
- dock.topLevelChanged.connect(self.create_window)
- dock.plugin_closed.connect(self.plugin_closed)
+ dock.topLevelChanged.connect(self.on_top_level_changed)
+ dock.sig_plugin_closed.connect(self.plugin_closed)
self.dockwidget = dock
- self.undocked = False
if self.shortcut is not None:
sc = QShortcut(QKeySequence(self.shortcut), self.main,
self.switch_to_plugin)
@@ -121,14 +138,16 @@ def create_configwidget(self, parent):
return configwidget
def switch_to_plugin(self):
- """Switch to plugin
- This method is called when pressing plugin's shortcut key"""
- if not self.ismaximized:
- self.dockwidget.show()
+ """Switch to plugin."""
+ if (self.main.last_plugin is not None and
+ self.main.last_plugin.ismaximized and
+ self.main.last_plugin is not self):
+ self.main.maximize_dockwidget()
if not self.toggle_view_action.isChecked():
self.toggle_view_action.setChecked(True)
self.visibility_changed(True)
+ @Slot()
def plugin_closed(self):
"""DockWidget was closed"""
self.toggle_view_action.setChecked(False)
@@ -190,38 +209,41 @@ def toggle_view(self, checked):
else:
self.dockwidget.hide()
+ @Slot()
+ def close_window(self):
+ """Close QMainWindow instance that contains this plugin."""
+ if self.undocked_window is not None:
+ self.undocked_window.close()
+ self.undocked_window = None
+
+ # Oddly, these actions can appear disabled after the Dock
+ # action is pressed
+ self.undock_action.setDisabled(False)
+ self.close_plugin_action.setDisabled(False)
+
@Slot()
def create_window(self):
- """Open a window of the plugin instead of undocking it."""
- if (self.dockwidget.isFloating() and not self.undocked and
- self.dockwidget.main.dockwidgets_locked):
- self.dockwidget.setFloating(False)
- self.dockwidget.setVisible(False)
- self.undock_action.setDisabled(True)
- window = self.create_mainwindow()
- window.show()
- elif self.undocked:
+ """Create a QMainWindow instance containing this plugin."""
+ self.undocked_window = window = PluginWindow(self)
+ window.setAttribute(Qt.WA_DeleteOnClose)
+ icon = self.get_plugin_icon()
+ if is_text_string(icon):
+ icon = self.get_icon(icon)
+ window.setWindowIcon(icon)
+ window.setWindowTitle(self.get_plugin_title())
+ window.setCentralWidget(self)
+ window.resize(self.size())
+ self.refresh_plugin()
+
+ self.dockwidget.setFloating(False)
+ self.dockwidget.setVisible(False)
+
+ window.show()
+
+ @Slot(bool)
+ def on_top_level_changed(self, top_level):
+ """Actions to perform when a plugin is undocked to be moved."""
+ if top_level:
self.undock_action.setDisabled(True)
else:
self.undock_action.setDisabled(False)
- self.undocked = False
-
- def create_mainwindow(self):
- """
- Create a QMainWindow instance containing this plugin.
- """
- raise NotImplementedError
-
- def create_undock_action(self):
- """Create the undock action for the plugin."""
- self.undock_action = create_action(self,
- _("Undock"),
- icon=ima.icon('newwindow'),
- tip=_("Undock the plugin"),
- triggered=self.undock_plugin)
-
- def undock_plugin(self):
- """Undocks the plugin from the MainWindow."""
- self.undocked = True
- self.dockwidget.setFloating(True)
- self.undock_action.setDisabled(True)
diff --git a/spyder/plugins/breakpoints/__init__.py b/spyder/plugins/breakpoints/__init__.py
new file mode 100644
index 00000000000..5037e7dfb26
--- /dev/null
+++ b/spyder/plugins/breakpoints/__init__.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+
+# =============================================================================
+# The following statement is required to register this 3rd party plugin:
+# =============================================================================
+
+from .plugin import Breakpoints as PLUGIN_CLASS
diff --git a/spyder/plugins/breakpoints/plugin.py b/spyder/plugins/breakpoints/plugin.py
new file mode 100644
index 00000000000..4e6bbad888d
--- /dev/null
+++ b/spyder/plugins/breakpoints/plugin.py
@@ -0,0 +1,112 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+
+"""Breakpoint Plugin."""
+
+
+# pylint: disable=C0103
+# pylint: disable=R0903
+# pylint: disable=R0911
+# pylint: disable=R0201
+
+# Standard library imports
+import os.path as osp
+
+# Third party imports
+from qtpy.QtWidgets import QVBoxLayout
+
+# Local imports
+from spyder.config.base import _
+from spyder.utils import icon_manager as ima
+from spyder.utils.qthelpers import create_action
+from spyder.api.plugins import SpyderPluginWidget
+
+from .widgets.breakpointsgui import BreakpointWidget
+
+
+class Breakpoints(SpyderPluginWidget):
+ """Breakpoint list"""
+ CONF_SECTION = 'breakpoints'
+
+ def __init__(self, parent=None):
+ """Initialization."""
+ SpyderPluginWidget.__init__(self, parent)
+
+ self.breakpoints = BreakpointWidget(self,
+ options_button=self.options_button)
+
+ layout = QVBoxLayout()
+ layout.addWidget(self.breakpoints)
+ self.setLayout(layout)
+
+ # Initialize plugin
+ self.initialize_plugin()
+ self.breakpoints.set_data()
+
+ #------ SpyderPluginWidget API --------------------------------------------
+ def get_plugin_title(self):
+ """Return widget title"""
+ return _("Breakpoints")
+
+ def get_plugin_icon(self):
+ """Return widget icon"""
+ path = osp.join(self.PLUGIN_PATH, self.IMG_PATH)
+ return ima.icon('profiler', icon_path=path)
+
+ def get_focus_widget(self):
+ """
+ Return the widget to give focus to when
+ this plugin's dockwidget is raised on top-level
+ """
+ return self.breakpoints.dictwidget
+
+ def get_plugin_actions(self):
+ """Return a list of actions related to plugin"""
+ return []
+
+ def on_first_registration(self):
+ """Action to be performed on first plugin registration"""
+ self.main.tabify_plugins(self.main.help, self)
+
+ def register_plugin(self):
+ """Register plugin in Spyder's main window"""
+ self.breakpoints.edit_goto.connect(self.main.editor.load)
+ #self.redirect_stdio.connect(self.main.redirect_internalshell_stdio)
+ self.breakpoints.clear_all_breakpoints.connect(
+ self.main.editor.clear_all_breakpoints)
+ self.breakpoints.clear_breakpoint.connect(
+ self.main.editor.clear_breakpoint)
+ self.main.editor.breakpoints_saved.connect(self.breakpoints.set_data)
+ self.breakpoints.set_or_edit_conditional_breakpoint.connect(
+ self.main.editor.set_or_edit_conditional_breakpoint)
+
+ self.main.add_dockwidget(self)
+
+ list_action = create_action(self, _("List breakpoints"),
+ triggered=self.show)
+ list_action.setEnabled(True)
+ pos = self.main.debug_menu_actions.index('list_breakpoints')
+ self.main.debug_menu_actions.insert(pos, list_action)
+ self.main.editor.pythonfile_dependent_actions += [list_action]
+
+ def refresh_plugin(self):
+ """Refresh widget"""
+ pass
+
+ def closing_plugin(self, cancelable=False):
+ """Perform actions before parent main window is closed"""
+ return True
+
+ def apply_plugin_settings(self, options):
+ """Apply configuration file's plugin settings"""
+ pass
+
+ def show(self):
+ """Show the breakpoints dockwidget"""
+ self.switch_to_plugin()
diff --git a/spyder/plugins/breakpoints/widgets/__init__.py b/spyder/plugins/breakpoints/widgets/__init__.py
new file mode 100644
index 00000000000..839eae7ce43
--- /dev/null
+++ b/spyder/plugins/breakpoints/widgets/__init__.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
diff --git a/spyder_breakpoints/widgets/breakpointsgui.py b/spyder/plugins/breakpoints/widgets/breakpointsgui.py
similarity index 91%
rename from spyder_breakpoints/widgets/breakpointsgui.py
rename to spyder/plugins/breakpoints/widgets/breakpointsgui.py
index 5f69a0bfc48..14cd4a61759 100644
--- a/spyder_breakpoints/widgets/breakpointsgui.py
+++ b/spyder/plugins/breakpoints/widgets/breakpointsgui.py
@@ -44,7 +44,7 @@
class BreakpointTableModel(QAbstractTableModel):
"""
Table model for breakpoints dictionary
-
+
"""
def __init__(self, parent, data):
QAbstractTableModel.__init__(self, parent)
@@ -52,8 +52,8 @@ def __init__(self, parent, data):
data = {}
self._data = None
self.breakpoints = None
- self.set_data(data)
-
+ self.set_data(data)
+
def set_data(self, data):
"""Set model data"""
self._data = data
@@ -64,12 +64,12 @@ def set_data(self, data):
if bp_list:
for item in data[key]:
self.breakpoints.append((key, item[0], item[1], ""))
- self.reset()
-
+ self.reset()
+
def rowCount(self, qindex=QModelIndex()):
"""Array row number"""
return len(self.breakpoints)
-
+
def columnCount(self, qindex=QModelIndex()):
"""Array column count"""
return 4
@@ -99,11 +99,11 @@ def headerData(self, section, orientation, role=Qt.DisplayRole):
return to_qvariant( headers[i_column] )
else:
return to_qvariant()
-
+
def get_value(self, index):
"""Return current value"""
- return self.breakpoints[index.row()][index.column()]
-
+ return self.breakpoints[index.row()][index.column()]
+
def data(self, index, role=Qt.DisplayRole):
"""Return data at table index"""
if not index.isValid():
@@ -128,7 +128,7 @@ def reset(self):
self.beginResetModel()
self.endResetModel()
-
+
class BreakpointDelegate(QItemDelegate):
def __init__(self, parent=None):
QItemDelegate.__init__(self, parent)
@@ -139,7 +139,7 @@ class BreakpointTableView(QTableView):
clear_breakpoint = Signal(str, int)
clear_all_breakpoints = Signal()
set_or_edit_conditional_breakpoint = Signal()
-
+
def __init__(self, parent, data):
QTableView.__init__(self, parent)
self.model = BreakpointTableModel(self, data)
@@ -148,7 +148,7 @@ def __init__(self, parent, data):
self.setItemDelegate(self.delegate)
self.setup_table()
-
+
def setup_table(self):
"""Setup table"""
self.horizontalHeader().setStretchLastSection(True)
@@ -157,12 +157,12 @@ def setup_table(self):
# Sorting columns
self.setSortingEnabled(False)
self.sortByColumn(0, Qt.DescendingOrder)
-
+
def adjust_columns(self):
"""Resize three first columns to contents"""
for col in range(3):
- self.resizeColumnToContents(col)
-
+ self.resizeColumnToContents(col)
+
def mouseDoubleClickEvent(self, event):
"""Reimplement Qt method"""
index_clicked = self.indexAt(event.pos())
@@ -172,12 +172,12 @@ def mouseDoubleClickEvent(self, event):
self.edit_goto.emit(filename, int(line_number_str), '')
if index_clicked.column()==2:
self.set_or_edit_conditional_breakpoint.emit()
-
+
def contextMenuEvent(self, event):
index_clicked = self.indexAt(event.pos())
actions = []
self.popup_menu = QMenu(self)
- clear_all_breakpoints_action = create_action(self,
+ clear_all_breakpoints_action = create_action(self,
_("Clear breakpoints in all files"),
triggered=lambda: self.clear_all_breakpoints.emit())
actions.append(clear_all_breakpoints_action)
@@ -207,7 +207,7 @@ def contextMenuEvent(self, event):
_("Edit this breakpoint"),
triggered=edit_slot)
actions.append(edit_breakpoint_action)
- add_actions(self.popup_menu, actions)
+ add_actions(self.popup_menu, actions)
self.popup_menu.popup(event.globalPos())
event.accept()
@@ -221,12 +221,12 @@ class BreakpointWidget(QWidget):
set_or_edit_conditional_breakpoint = Signal()
clear_breakpoint = Signal(str, int)
edit_goto = Signal(str, int, str)
-
+
def __init__(self, parent, options_button=None):
QWidget.__init__(self, parent)
-
- self.setWindowTitle("Breakpoints")
- self.dictwidget = BreakpointTableView(self,
+
+ self.setWindowTitle("Breakpoints")
+ self.dictwidget = BreakpointTableView(self,
self._load_all_breakpoints())
if options_button:
btn_layout = QHBoxLayout()
@@ -246,17 +246,17 @@ def __init__(self, parent, options_button=None):
lambda s1, lino, s2: self.edit_goto.emit(s1, lino, s2))
self.dictwidget.set_or_edit_conditional_breakpoint.connect(
lambda: self.set_or_edit_conditional_breakpoint.emit())
-
+
def _load_all_breakpoints(self):
bp_dict = CONF.get('run', 'breakpoints', {})
for filename in list(bp_dict.keys()):
if not osp.isfile(filename):
bp_dict.pop(filename)
- return bp_dict
-
+ return bp_dict
+
def get_data(self):
pass
-
+
def set_data(self):
bp_dict = self._load_all_breakpoints()
self.dictwidget.model.set_data(bp_dict)
diff --git a/spyder/plugins/configdialog.py b/spyder/plugins/configdialog.py
deleted file mode 100644
index 171e15bc7ad..00000000000
--- a/spyder/plugins/configdialog.py
+++ /dev/null
@@ -1,1539 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright © Spyder Project Contributors
-# Licensed under the terms of the MIT License
-# (see spyder/__init__.py for details)
-
-"""
-Configuration dialog / Preferences.
-"""
-
-# Standard library imports
-import os.path as osp
-
-# Third party imports
-from qtpy import API
-from qtpy.compat import (getexistingdirectory, getopenfilename, from_qvariant,
- to_qvariant)
-from qtpy.QtCore import QSize, Qt, Signal, Slot, QRegExp
-from qtpy.QtGui import QColor, QRegExpValidator
-from qtpy.QtWidgets import (QButtonGroup, QCheckBox, QComboBox, QDialog,
- QDialogButtonBox, QDoubleSpinBox, QFontComboBox,
- QGridLayout, QGroupBox, QHBoxLayout, QLabel,
- QLineEdit, QListView, QListWidget, QListWidgetItem,
- QMessageBox, QPushButton, QRadioButton,
- QScrollArea, QSpinBox, QSplitter, QStackedWidget,
- QStyleFactory, QTabWidget, QVBoxLayout, QWidget,
- QApplication)
-
-# Local imports
-from spyder.config.base import (_, LANGUAGE_CODES, load_lang_conf,
- running_in_mac_app, save_lang_conf)
-from spyder.config.gui import get_font, set_font
-from spyder.config.main import CONF
-from spyder.config.user import NoDefault
-from spyder.config.utils import is_gtk_desktop
-from spyder.py3compat import to_text_string, is_text_string
-from spyder.utils import icon_manager as ima
-from spyder.utils import syntaxhighlighters
-from spyder.utils.misc import getcwd_or_home
-from spyder.widgets.colors import ColorLayout
-from spyder.widgets.sourcecode.codeeditor import CodeEditor
-
-
-HDPI_QT_PAGE = "http://doc.qt.io/qt-5/highdpi.html"
-
-
-class ConfigAccessMixin(object):
- """Namespace for methods that access config storage"""
- CONF_SECTION = None
-
- def set_option(self, option, value):
- CONF.set(self.CONF_SECTION, option, value)
-
- def get_option(self, option, default=NoDefault):
- return CONF.get(self.CONF_SECTION, option, default)
-
-
-class ConfigPage(QWidget):
- """Base class for configuration page in Preferences"""
-
- # Signals
- apply_button_enabled = Signal(bool)
- show_this_page = Signal()
-
- def __init__(self, parent, apply_callback=None):
- QWidget.__init__(self, parent)
- self.apply_callback = apply_callback
- self.is_modified = False
-
- def initialize(self):
- """
- Initialize configuration page:
- * setup GUI widgets
- * load settings and change widgets accordingly
- """
- self.setup_page()
- self.load_from_conf()
-
- def get_name(self):
- """Return configuration page name"""
- raise NotImplementedError
-
- def get_icon(self):
- """Return configuration page icon (24x24)"""
- raise NotImplementedError
-
- def setup_page(self):
- """Setup configuration page widget"""
- raise NotImplementedError
-
- def set_modified(self, state):
- self.is_modified = state
- self.apply_button_enabled.emit(state)
-
- def is_valid(self):
- """Return True if all widget contents are valid"""
- raise NotImplementedError
-
- def apply_changes(self):
- """Apply changes callback"""
- if self.is_modified:
- self.save_to_conf()
- if self.apply_callback is not None:
- self.apply_callback()
-
- # Since the language cannot be retrieved by CONF and the language
- # is needed before loading CONF, this is an extra method needed to
- # ensure that when changes are applied, they are copied to a
- # specific file storing the language value. This only applies to
- # the main section config.
- if self.CONF_SECTION == u'main':
- self._save_lang()
-
- for restart_option in self.restart_options:
- if restart_option in self.changed_options:
- self.prompt_restart_required()
- break # Ensure a single popup is displayed
- self.set_modified(False)
-
- def load_from_conf(self):
- """Load settings from configuration file"""
- raise NotImplementedError
-
- def save_to_conf(self):
- """Save settings to configuration file"""
- raise NotImplementedError
-
-
-class ConfigDialog(QDialog):
- """Spyder configuration ('Preferences') dialog box"""
-
- # Signals
- check_settings = Signal()
- size_change = Signal(QSize)
-
- def __init__(self, parent=None):
- QDialog.__init__(self, parent)
-
- self.main = parent
-
- # Widgets
- self.pages_widget = QStackedWidget()
- self.contents_widget = QListWidget()
- self.button_reset = QPushButton(_('Reset to defaults'))
-
- bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Apply |
- QDialogButtonBox.Cancel)
- self.apply_btn = bbox.button(QDialogButtonBox.Apply)
-
- # Widgets setup
- # Destroying the C++ object right after closing the dialog box,
- # otherwise it may be garbage-collected in another QThread
- # (e.g. the editor's analysis thread in Spyder), thus leading to
- # a segmentation fault on UNIX or an application crash on Windows
- self.setAttribute(Qt.WA_DeleteOnClose)
- self.setWindowTitle(_('Preferences'))
- self.setWindowIcon(ima.icon('configure'))
- self.contents_widget.setMovement(QListView.Static)
- self.contents_widget.setSpacing(1)
- self.contents_widget.setCurrentRow(0)
-
- # Layout
- hsplitter = QSplitter()
- hsplitter.addWidget(self.contents_widget)
- hsplitter.addWidget(self.pages_widget)
-
- btnlayout = QHBoxLayout()
- btnlayout.addWidget(self.button_reset)
- btnlayout.addStretch(1)
- btnlayout.addWidget(bbox)
-
- vlayout = QVBoxLayout()
- vlayout.addWidget(hsplitter)
- vlayout.addLayout(btnlayout)
-
- self.setLayout(vlayout)
-
- # Signals and slots
- if self.main:
- self.button_reset.clicked.connect(self.main.reset_spyder)
- self.pages_widget.currentChanged.connect(self.current_page_changed)
- self.contents_widget.currentRowChanged.connect(
- self.pages_widget.setCurrentIndex)
- bbox.accepted.connect(self.accept)
- bbox.rejected.connect(self.reject)
- bbox.clicked.connect(self.button_clicked)
-
- # Ensures that the config is present on spyder first run
- CONF.set('main', 'interface_language', load_lang_conf())
-
- def get_current_index(self):
- """Return current page index"""
- return self.contents_widget.currentRow()
-
- def set_current_index(self, index):
- """Set current page index"""
- self.contents_widget.setCurrentRow(index)
-
- def get_page(self, index=None):
- """Return page widget"""
- if index is None:
- widget = self.pages_widget.currentWidget()
- else:
- widget = self.pages_widget.widget(index)
- return widget.widget()
-
- @Slot()
- def accept(self):
- """Reimplement Qt method"""
- for index in range(self.pages_widget.count()):
- configpage = self.get_page(index)
- if not configpage.is_valid():
- return
- configpage.apply_changes()
- QDialog.accept(self)
-
- def button_clicked(self, button):
- if button is self.apply_btn:
- # Apply button was clicked
- configpage = self.get_page()
- if not configpage.is_valid():
- return
- configpage.apply_changes()
-
- def current_page_changed(self, index):
- widget = self.get_page(index)
- self.apply_btn.setVisible(widget.apply_callback is not None)
- self.apply_btn.setEnabled(widget.is_modified)
-
- def add_page(self, widget):
- self.check_settings.connect(widget.check_settings)
- widget.show_this_page.connect(lambda row=self.contents_widget.count():
- self.contents_widget.setCurrentRow(row))
- widget.apply_button_enabled.connect(self.apply_btn.setEnabled)
- scrollarea = QScrollArea(self)
- scrollarea.setWidgetResizable(True)
- scrollarea.setWidget(widget)
- self.pages_widget.addWidget(scrollarea)
- item = QListWidgetItem(self.contents_widget)
- try:
- item.setIcon(widget.get_icon())
- except TypeError:
- pass
- item.setText(widget.get_name())
- item.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled)
- item.setSizeHint(QSize(0, 25))
-
- def check_all_settings(self):
- """This method is called to check all configuration page settings
- after configuration dialog has been shown"""
- self.check_settings.emit()
-
- def resizeEvent(self, event):
- """
- Reimplement Qt method to be able to save the widget's size from the
- main application
- """
- QDialog.resizeEvent(self, event)
- self.size_change.emit(self.size())
-
-
-class SpyderConfigPage(ConfigPage, ConfigAccessMixin):
- """Plugin configuration dialog box page widget"""
- CONF_SECTION = None
-
- def __init__(self, parent):
- ConfigPage.__init__(self, parent,
- apply_callback=lambda:
- self.apply_settings(self.changed_options))
- self.checkboxes = {}
- self.radiobuttons = {}
- self.lineedits = {}
- self.validate_data = {}
- self.spinboxes = {}
- self.comboboxes = {}
- self.fontboxes = {}
- self.coloredits = {}
- self.scedits = {}
- self.changed_options = set()
- self.restart_options = dict() # Dict to store name and localized text
- self.default_button_group = None
-
- def apply_settings(self, options):
- raise NotImplementedError
-
- def check_settings(self):
- """This method is called to check settings after configuration
- dialog has been shown"""
- pass
-
- def set_modified(self, state):
- ConfigPage.set_modified(self, state)
- if not state:
- self.changed_options = set()
-
- def is_valid(self):
- """Return True if all widget contents are valid"""
- for lineedit in self.lineedits:
- if lineedit in self.validate_data and lineedit.isEnabled():
- validator, invalid_msg = self.validate_data[lineedit]
- text = to_text_string(lineedit.text())
- if not validator(text):
- QMessageBox.critical(self, self.get_name(),
- "%s:
%s" % (invalid_msg, text),
- QMessageBox.Ok)
- return False
- return True
-
- def load_from_conf(self):
- """Load settings from configuration file"""
- for checkbox, (option, default) in list(self.checkboxes.items()):
- checkbox.setChecked(self.get_option(option, default))
- # QAbstractButton works differently for PySide and PyQt
- if not API == 'pyside':
- checkbox.clicked.connect(lambda _foo, opt=option:
- self.has_been_modified(opt))
- else:
- checkbox.clicked.connect(lambda opt=option:
- self.has_been_modified(opt))
- for radiobutton, (option, default) in list(self.radiobuttons.items()):
- radiobutton.setChecked(self.get_option(option, default))
- radiobutton.toggled.connect(lambda _foo, opt=option:
- self.has_been_modified(opt))
- if radiobutton.restart_required:
- self.restart_options[option] = radiobutton.label_text
- for lineedit, (option, default) in list(self.lineedits.items()):
- lineedit.setText(self.get_option(option, default))
- lineedit.textChanged.connect(lambda _foo, opt=option:
- self.has_been_modified(opt))
- if lineedit.restart_required:
- self.restart_options[option] = lineedit.label_text
- for spinbox, (option, default) in list(self.spinboxes.items()):
- spinbox.setValue(self.get_option(option, default))
- spinbox.valueChanged.connect(lambda _foo, opt=option:
- self.has_been_modified(opt))
- for combobox, (option, default) in list(self.comboboxes.items()):
- value = self.get_option(option, default)
- for index in range(combobox.count()):
- data = from_qvariant(combobox.itemData(index), to_text_string)
- # For PyQt API v2, it is necessary to convert `data` to
- # unicode in case the original type was not a string, like an
- # integer for example (see qtpy.compat.from_qvariant):
- if to_text_string(data) == to_text_string(value):
- break
- combobox.setCurrentIndex(index)
- combobox.currentIndexChanged.connect(lambda _foo, opt=option:
- self.has_been_modified(opt))
- if combobox.restart_required:
- self.restart_options[option] = combobox.label_text
-
- for (fontbox, sizebox), option in list(self.fontboxes.items()):
- font = self.get_font(option)
- fontbox.setCurrentFont(font)
- sizebox.setValue(font.pointSize())
- if option is None:
- property = 'plugin_font'
- else:
- property = option
- fontbox.currentIndexChanged.connect(lambda _foo, opt=property:
- self.has_been_modified(opt))
- sizebox.valueChanged.connect(lambda _foo, opt=property:
- self.has_been_modified(opt))
- for clayout, (option, default) in list(self.coloredits.items()):
- property = to_qvariant(option)
- edit = clayout.lineedit
- btn = clayout.colorbtn
- edit.setText(self.get_option(option, default))
- # QAbstractButton works differently for PySide and PyQt
- if not API == 'pyside':
- btn.clicked.connect(lambda _foo, opt=option:
- self.has_been_modified(opt))
- else:
- btn.clicked.connect(lambda opt=option:
- self.has_been_modified(opt))
- edit.textChanged.connect(lambda _foo, opt=option:
- self.has_been_modified(opt))
- for (clayout, cb_bold, cb_italic
- ), (option, default) in list(self.scedits.items()):
- edit = clayout.lineedit
- btn = clayout.colorbtn
- color, bold, italic = self.get_option(option, default)
- edit.setText(color)
- cb_bold.setChecked(bold)
- cb_italic.setChecked(italic)
- edit.textChanged.connect(lambda _foo, opt=option:
- self.has_been_modified(opt))
- # QAbstractButton works differently for PySide and PyQt
- if not API == 'pyside':
- btn.clicked.connect(lambda _foo, opt=option:
- self.has_been_modified(opt))
- cb_bold.clicked.connect(lambda _foo, opt=option:
- self.has_been_modified(opt))
- cb_italic.clicked.connect(lambda _foo, opt=option:
- self.has_been_modified(opt))
- else:
- btn.clicked.connect(lambda opt=option:
- self.has_been_modified(opt))
- cb_bold.clicked.connect(lambda opt=option:
- self.has_been_modified(opt))
- cb_italic.clicked.connect(lambda opt=option:
- self.has_been_modified(opt))
-
- def save_to_conf(self):
- """Save settings to configuration file"""
- for checkbox, (option, _default) in list(self.checkboxes.items()):
- self.set_option(option, checkbox.isChecked())
- for radiobutton, (option, _default) in list(self.radiobuttons.items()):
- self.set_option(option, radiobutton.isChecked())
- for lineedit, (option, _default) in list(self.lineedits.items()):
- self.set_option(option, to_text_string(lineedit.text()))
- for spinbox, (option, _default) in list(self.spinboxes.items()):
- self.set_option(option, spinbox.value())
- for combobox, (option, _default) in list(self.comboboxes.items()):
- data = combobox.itemData(combobox.currentIndex())
- self.set_option(option, from_qvariant(data, to_text_string))
- for (fontbox, sizebox), option in list(self.fontboxes.items()):
- font = fontbox.currentFont()
- font.setPointSize(sizebox.value())
- self.set_font(font, option)
- for clayout, (option, _default) in list(self.coloredits.items()):
- self.set_option(option, to_text_string(clayout.lineedit.text()))
- for (clayout, cb_bold, cb_italic), (option, _default) in list(self.scedits.items()):
- color = to_text_string(clayout.lineedit.text())
- bold = cb_bold.isChecked()
- italic = cb_italic.isChecked()
- self.set_option(option, (color, bold, italic))
-
- @Slot(str)
- def has_been_modified(self, option):
- self.set_modified(True)
- self.changed_options.add(option)
-
- def create_checkbox(self, text, option, default=NoDefault,
- tip=None, msg_warning=None, msg_info=None,
- msg_if_enabled=False):
- checkbox = QCheckBox(text)
- if tip is not None:
- checkbox.setToolTip(tip)
- self.checkboxes[checkbox] = (option, default)
- if msg_warning is not None or msg_info is not None:
- def show_message(is_checked=False):
- if is_checked or not msg_if_enabled:
- if msg_warning is not None:
- QMessageBox.warning(self, self.get_name(),
- msg_warning, QMessageBox.Ok)
- if msg_info is not None:
- QMessageBox.information(self, self.get_name(),
- msg_info, QMessageBox.Ok)
- checkbox.clicked.connect(show_message)
- return checkbox
-
- def create_radiobutton(self, text, option, default=NoDefault,
- tip=None, msg_warning=None, msg_info=None,
- msg_if_enabled=False, button_group=None,
- restart=False):
- radiobutton = QRadioButton(text)
- if button_group is None:
- if self.default_button_group is None:
- self.default_button_group = QButtonGroup(self)
- button_group = self.default_button_group
- button_group.addButton(radiobutton)
- if tip is not None:
- radiobutton.setToolTip(tip)
- self.radiobuttons[radiobutton] = (option, default)
- if msg_warning is not None or msg_info is not None:
- def show_message(is_checked):
- if is_checked or not msg_if_enabled:
- if msg_warning is not None:
- QMessageBox.warning(self, self.get_name(),
- msg_warning, QMessageBox.Ok)
- if msg_info is not None:
- QMessageBox.information(self, self.get_name(),
- msg_info, QMessageBox.Ok)
- radiobutton.toggled.connect(show_message)
- radiobutton.restart_required = restart
- radiobutton.label_text = text
- return radiobutton
-
- def create_lineedit(self, text, option, default=NoDefault,
- tip=None, alignment=Qt.Vertical, regex=None,
- restart=False):
- label = QLabel(text)
- label.setWordWrap(True)
- edit = QLineEdit()
- layout = QVBoxLayout() if alignment == Qt.Vertical else QHBoxLayout()
- layout.addWidget(label)
- layout.addWidget(edit)
- layout.setContentsMargins(0, 0, 0, 0)
- if tip:
- edit.setToolTip(tip)
- if regex:
- edit.setValidator(QRegExpValidator(QRegExp(regex)))
- self.lineedits[edit] = (option, default)
- widget = QWidget(self)
- widget.label = label
- widget.textbox = edit
- widget.setLayout(layout)
- edit.restart_required = restart
- edit.label_text = text
- return widget
-
- def create_browsedir(self, text, option, default=NoDefault, tip=None):
- widget = self.create_lineedit(text, option, default,
- alignment=Qt.Horizontal)
- for edit in self.lineedits:
- if widget.isAncestorOf(edit):
- break
- msg = _("Invalid directory path")
- self.validate_data[edit] = (osp.isdir, msg)
- browse_btn = QPushButton(ima.icon('DirOpenIcon'), '', self)
- browse_btn.setToolTip(_("Select directory"))
- browse_btn.clicked.connect(lambda: self.select_directory(edit))
- layout = QHBoxLayout()
- layout.addWidget(widget)
- layout.addWidget(browse_btn)
- layout.setContentsMargins(0, 0, 0, 0)
- browsedir = QWidget(self)
- browsedir.setLayout(layout)
- return browsedir
-
- def select_directory(self, edit):
- """Select directory"""
- basedir = to_text_string(edit.text())
- if not osp.isdir(basedir):
- basedir = getcwd_or_home()
- title = _("Select directory")
- directory = getexistingdirectory(self, title, basedir)
- if directory:
- edit.setText(directory)
-
- def create_browsefile(self, text, option, default=NoDefault, tip=None,
- filters=None):
- widget = self.create_lineedit(text, option, default,
- alignment=Qt.Horizontal)
- for edit in self.lineedits:
- if widget.isAncestorOf(edit):
- break
- msg = _('Invalid file path')
- self.validate_data[edit] = (osp.isfile, msg)
- browse_btn = QPushButton(ima.icon('FileIcon'), '', self)
- browse_btn.setToolTip(_("Select file"))
- browse_btn.clicked.connect(lambda: self.select_file(edit, filters))
- layout = QHBoxLayout()
- layout.addWidget(widget)
- layout.addWidget(browse_btn)
- layout.setContentsMargins(0, 0, 0, 0)
- browsedir = QWidget(self)
- browsedir.setLayout(layout)
- return browsedir
-
- def select_file(self, edit, filters=None):
- """Select File"""
- basedir = osp.dirname(to_text_string(edit.text()))
- if not osp.isdir(basedir):
- basedir = getcwd_or_home()
- if filters is None:
- filters = _("All files (*)")
- title = _("Select file")
- filename, _selfilter = getopenfilename(self, title, basedir, filters)
- if filename:
- edit.setText(filename)
-
- def create_spinbox(self, prefix, suffix, option, default=NoDefault,
- min_=None, max_=None, step=None, tip=None):
- widget = QWidget(self)
- if prefix:
- plabel = QLabel(prefix)
- widget.plabel = plabel
- else:
- plabel = None
- if suffix:
- slabel = QLabel(suffix)
- widget.slabel = slabel
- else:
- slabel = None
- if step is not None:
- if type(step) is int:
- spinbox = QSpinBox()
- else:
- spinbox = QDoubleSpinBox()
- spinbox.setDecimals(1)
- spinbox.setSingleStep(step)
- else:
- spinbox = QSpinBox()
- if min_ is not None:
- spinbox.setMinimum(min_)
- if max_ is not None:
- spinbox.setMaximum(max_)
- if tip is not None:
- spinbox.setToolTip(tip)
- self.spinboxes[spinbox] = (option, default)
- layout = QHBoxLayout()
- for subwidget in (plabel, spinbox, slabel):
- if subwidget is not None:
- layout.addWidget(subwidget)
- layout.addStretch(1)
- layout.setContentsMargins(0, 0, 0, 0)
- widget.spinbox = spinbox
- widget.setLayout(layout)
- return widget
-
- def create_coloredit(self, text, option, default=NoDefault, tip=None,
- without_layout=False):
- label = QLabel(text)
- clayout = ColorLayout(QColor(Qt.black), self)
- clayout.lineedit.setMaximumWidth(80)
- if tip is not None:
- clayout.setToolTip(tip)
- self.coloredits[clayout] = (option, default)
- if without_layout:
- return label, clayout
- layout = QHBoxLayout()
- layout.addWidget(label)
- layout.addLayout(clayout)
- layout.addStretch(1)
- layout.setContentsMargins(0, 0, 0, 0)
- widget = QWidget(self)
- widget.setLayout(layout)
- return widget
-
- def create_scedit(self, text, option, default=NoDefault, tip=None,
- without_layout=False):
- label = QLabel(text)
- clayout = ColorLayout(QColor(Qt.black), self)
- clayout.lineedit.setMaximumWidth(80)
- if tip is not None:
- clayout.setToolTip(tip)
- cb_bold = QCheckBox()
- cb_bold.setIcon(ima.icon('bold'))
- cb_bold.setToolTip(_("Bold"))
- cb_italic = QCheckBox()
- cb_italic.setIcon(ima.icon('italic'))
- cb_italic.setToolTip(_("Italic"))
- self.scedits[(clayout, cb_bold, cb_italic)] = (option, default)
- if without_layout:
- return label, clayout, cb_bold, cb_italic
- layout = QHBoxLayout()
- layout.addWidget(label)
- layout.addLayout(clayout)
- layout.addSpacing(10)
- layout.addWidget(cb_bold)
- layout.addWidget(cb_italic)
- layout.addStretch(1)
- layout.setContentsMargins(0, 0, 0, 0)
- widget = QWidget(self)
- widget.setLayout(layout)
- return widget
-
- def create_combobox(self, text, choices, option, default=NoDefault,
- tip=None, restart=False):
- """choices: couples (name, key)"""
- label = QLabel(text)
- combobox = QComboBox()
- if tip is not None:
- combobox.setToolTip(tip)
- for name, key in choices:
- if not (name is None and key is None):
- combobox.addItem(name, to_qvariant(key))
- # Insert separators
- count = 0
- for index, item in enumerate(choices):
- name, key = item
- if name is None and key is None:
- combobox.insertSeparator(index + count)
- count += 1
- self.comboboxes[combobox] = (option, default)
- layout = QHBoxLayout()
- layout.addWidget(label)
- layout.addWidget(combobox)
- layout.addStretch(1)
- layout.setContentsMargins(0, 0, 0, 0)
- widget = QWidget(self)
- widget.label = label
- widget.combobox = combobox
- widget.setLayout(layout)
- combobox.restart_required = restart
- combobox.label_text = text
- return widget
-
- def create_fontgroup(self, option=None, text=None, title=None,
- tip=None, fontfilters=None, without_group=False):
- """Option=None -> setting plugin font"""
-
- if title:
- fontlabel = QLabel(title)
- else:
- fontlabel = QLabel(_("Font: "))
- fontbox = QFontComboBox()
-
- if fontfilters is not None:
- fontbox.setFontFilters(fontfilters)
-
- sizelabel = QLabel(" "+_("Size: "))
- sizebox = QSpinBox()
- sizebox.setRange(7, 100)
- self.fontboxes[(fontbox, sizebox)] = option
- layout = QHBoxLayout()
-
- for subwidget in (fontlabel, fontbox, sizelabel, sizebox):
- layout.addWidget(subwidget)
- layout.addStretch(1)
-
- widget = QWidget(self)
- widget.fontlabel = fontlabel
- widget.sizelabel = sizelabel
- widget.fontbox = fontbox
- widget.sizebox = sizebox
- widget.setLayout(layout)
-
- if not without_group:
- if text is None:
- text = _("Font style")
-
- group = QGroupBox(text)
- group.setLayout(layout)
-
- if tip is not None:
- group.setToolTip(tip)
-
- return group
- else:
- return widget
-
- def create_button(self, text, callback):
- btn = QPushButton(text)
- btn.clicked.connect(callback)
- btn.clicked.connect(lambda checked=False, opt='': self.has_been_modified(opt))
- return btn
-
- def create_tab(self, *widgets):
- """Create simple tab widget page: widgets added in a vertical layout"""
- widget = QWidget()
- layout = QVBoxLayout()
- for widg in widgets:
- layout.addWidget(widg)
- layout.addStretch(1)
- widget.setLayout(layout)
- return widget
-
-
-class GeneralConfigPage(SpyderConfigPage):
- """Config page that maintains reference to main Spyder window
- and allows to specify page name and icon declaratively
- """
- CONF_SECTION = None
-
- NAME = None # configuration page name, e.g. _("General")
- ICON = None # name of icon resource (24x24)
-
- def __init__(self, parent, main):
- SpyderConfigPage.__init__(self, parent)
- self.main = main
-
- def get_name(self):
- """Configuration page name"""
- return self.NAME
-
- def get_icon(self):
- """Loads page icon named by self.ICON"""
- return self.ICON
-
- def apply_settings(self, options):
- raise NotImplementedError
-
- def prompt_restart_required(self):
- """Prompt the user with a request to restart."""
- restart_opts = self.restart_options
- changed_opts = self.changed_options
- options = [restart_opts[o] for o in changed_opts if o in restart_opts]
-
- if len(options) == 1:
- msg_start = _("Spyder needs to restart to change the following "
- "setting:")
- else:
- msg_start = _("Spyder needs to restart to change the following "
- "settings:")
- msg_end = _("Do you wish to restart now?")
-
- msg_options = u""
- for option in options:
- msg_options += u"{0} ".format(option)
-
- msg_title = _("Information")
- msg = u"{0}{1}
{2}".format(msg_start, msg_options, msg_end)
- answer = QMessageBox.information(self, msg_title, msg,
- QMessageBox.Yes | QMessageBox.No)
- if answer == QMessageBox.Yes:
- self.restart()
-
- def restart(self):
- """Restart Spyder."""
- self.main.restart()
-
-
-class MainConfigPage(GeneralConfigPage):
- CONF_SECTION = "main"
- NAME = _("General")
-
- def setup_page(self):
- self.ICON = ima.icon('genprefs')
- newcb = self.create_checkbox
-
- # --- Interface
- general_group = QGroupBox(_("General"))
- languages = LANGUAGE_CODES.items()
- language_choices = sorted([(val, key) for key, val in languages])
- language_combo = self.create_combobox(_('Language'), language_choices,
- 'interface_language',
- restart=True)
- single_instance_box = newcb(_("Use a single instance"),
- 'single_instance',
- tip=_("Set this to open external
"
- "Python files in an already running "
- "instance (Requires a restart)"))
- prompt_box = newcb(_("Prompt when exiting"), 'prompt_on_exit')
- popup_console_box = newcb(_("Show internal Spyder errors to report "
- "them to Github"), 'show_internal_errors')
- check_updates = newcb(_("Check for updates on startup"),
- 'check_updates_on_startup')
-
- # Decide if it's possible to activate or not single instance mode
- if running_in_mac_app():
- self.set_option("single_instance", True)
- single_instance_box.setEnabled(False)
-
- general_layout = QVBoxLayout()
- general_layout.addWidget(language_combo)
- general_layout.addWidget(single_instance_box)
- general_layout.addWidget(prompt_box)
- general_layout.addWidget(popup_console_box)
- general_layout.addWidget(check_updates)
- general_group.setLayout(general_layout)
-
- # --- Theme
- interface_group = QGroupBox(_("Interface"))
- styles = [str(txt) for txt in list(QStyleFactory.keys())]
- # Don't offer users the possibility to change to a different
- # style in Gtk-based desktops
- # Fixes Issue 2036
- if is_gtk_desktop() and ('GTK+' in styles):
- styles = ['GTK+']
- choices = list(zip(styles, [style.lower() for style in styles]))
- style_combo = self.create_combobox(_('Qt windows style'), choices,
- 'windows_style',
- default=self.main.default_style)
-
- themes = ['Spyder 2', 'Spyder 3']
- icon_choices = list(zip(themes, [theme.lower() for theme in themes]))
- icons_combo = self.create_combobox(_('Icon theme'), icon_choices,
- 'icon_theme', restart=True)
-
-
- vertdock_box = newcb(_("Vertical title bars in panes"),
- 'vertical_dockwidget_titlebars')
- verttabs_box = newcb(_("Vertical tabs in panes"),
- 'vertical_tabs')
- animated_box = newcb(_("Animated toolbars and panes"),
- 'animated_docks')
- tear_off_box = newcb(_("Tear off menus"), 'tear_off_menus',
- tip=_("Set this to detach any
"
- "menu from the main window"))
- margin_box = newcb(_("Custom margin for panes:"),
- 'use_custom_margin')
- margin_spin = self.create_spinbox("", _("pixels"), 'custom_margin',
- 0, 0, 30)
- margin_box.toggled.connect(margin_spin.spinbox.setEnabled)
- margin_box.toggled.connect(margin_spin.slabel.setEnabled)
- margin_spin.spinbox.setEnabled(self.get_option('use_custom_margin'))
- margin_spin.slabel.setEnabled(self.get_option('use_custom_margin'))
-
- cursor_box = newcb(_("Cursor blinking:"),
- 'use_custom_cursor_blinking')
- cursor_spin = self.create_spinbox("", _("ms"), 'custom_cursor_blinking',
- default = QApplication.cursorFlashTime(),
- min_=0, max_=5000, step=100)
- cursor_box.toggled.connect(cursor_spin.spinbox.setEnabled)
- cursor_box.toggled.connect(cursor_spin.slabel.setEnabled)
- cursor_spin.spinbox.setEnabled(
- self.get_option('use_custom_cursor_blinking'))
- cursor_spin.slabel.setEnabled(
- self.get_option('use_custom_cursor_blinking'))
-
- margins_cursor_layout = QGridLayout()
- margins_cursor_layout.addWidget(margin_box, 0, 0)
- margins_cursor_layout.addWidget(margin_spin.spinbox, 0, 1)
- margins_cursor_layout.addWidget(margin_spin.slabel, 0, 2)
- margins_cursor_layout.addWidget(cursor_box, 1, 0)
- margins_cursor_layout.addWidget(cursor_spin.spinbox, 1, 1)
- margins_cursor_layout.addWidget(cursor_spin.slabel, 1, 2)
- margins_cursor_layout.setColumnStretch(2, 100)
-
- # Layout interface
- comboboxes_layout = QHBoxLayout()
- cbs_layout = QGridLayout()
- cbs_layout.addWidget(style_combo.label, 0, 0)
- cbs_layout.addWidget(style_combo.combobox, 0, 1)
- cbs_layout.addWidget(icons_combo.label, 1, 0)
- cbs_layout.addWidget(icons_combo.combobox, 1, 1)
- comboboxes_layout.addLayout(cbs_layout)
- comboboxes_layout.addStretch(1)
-
- interface_layout = QVBoxLayout()
- interface_layout.addLayout(comboboxes_layout)
- interface_layout.addWidget(vertdock_box)
- interface_layout.addWidget(verttabs_box)
- interface_layout.addWidget(animated_box)
- interface_layout.addWidget(tear_off_box)
- interface_layout.addLayout(margins_cursor_layout)
- interface_group.setLayout(interface_layout)
-
- # --- Status bar
- sbar_group = QGroupBox(_("Status bar"))
- show_status_bar = newcb(_("Show status bar"), 'show_status_bar')
-
- memory_box = newcb(_("Show memory usage every"), 'memory_usage/enable',
- tip=self.main.mem_status.toolTip())
- memory_spin = self.create_spinbox("", _(" ms"), 'memory_usage/timeout',
- min_=100, max_=1000000, step=100)
- memory_box.toggled.connect(memory_spin.setEnabled)
- memory_spin.setEnabled(self.get_option('memory_usage/enable'))
- memory_box.setEnabled(self.main.mem_status.is_supported())
- memory_spin.setEnabled(self.main.mem_status.is_supported())
-
- cpu_box = newcb(_("Show CPU usage every"), 'cpu_usage/enable',
- tip=self.main.cpu_status.toolTip())
- cpu_spin = self.create_spinbox("", _(" ms"), 'cpu_usage/timeout',
- min_=100, max_=1000000, step=100)
- cpu_box.toggled.connect(cpu_spin.setEnabled)
- cpu_spin.setEnabled(self.get_option('cpu_usage/enable'))
-
- cpu_box.setEnabled(self.main.cpu_status.is_supported())
- cpu_spin.setEnabled(self.main.cpu_status.is_supported())
-
- status_bar_o = self.get_option('show_status_bar')
- show_status_bar.toggled.connect(memory_box.setEnabled)
- show_status_bar.toggled.connect(memory_spin.setEnabled)
- show_status_bar.toggled.connect(cpu_box.setEnabled)
- show_status_bar.toggled.connect(cpu_spin.setEnabled)
- memory_box.setEnabled(status_bar_o)
- memory_spin.setEnabled(status_bar_o)
- cpu_box.setEnabled(status_bar_o)
- cpu_spin.setEnabled(status_bar_o)
-
- # Layout status bar
- cpu_memory_layout = QGridLayout()
- cpu_memory_layout.addWidget(memory_box, 0, 0)
- cpu_memory_layout.addWidget(memory_spin, 0, 1)
- cpu_memory_layout.addWidget(cpu_box, 1, 0)
- cpu_memory_layout.addWidget(cpu_spin, 1, 1)
-
- sbar_layout = QVBoxLayout()
- sbar_layout.addWidget(show_status_bar)
- sbar_layout.addLayout(cpu_memory_layout)
- sbar_group.setLayout(sbar_layout)
-
- # --- Screen resolution Group (hidpi)
- screen_resolution_group = QGroupBox(_("Screen resolution"))
- screen_resolution_bg = QButtonGroup(screen_resolution_group)
- screen_resolution_label = QLabel(_("Configuration for high DPI "
- "screens
"
- "Please see "
- "{0}<> "
- "for more information about "
- "these options (in "
- "English).").format(HDPI_QT_PAGE))
- screen_resolution_label.setWordWrap(True)
-
- normal_radio = self.create_radiobutton(
- _("Normal"),
- 'normal_screen_resolution',
- button_group=screen_resolution_bg)
- auto_scale_radio = self.create_radiobutton(
- _("Enable auto high DPI scaling"),
- 'high_dpi_scaling',
- button_group=screen_resolution_bg,
- tip=_("Set this for high DPI displays"),
- restart=True)
-
- custom_scaling_radio = self.create_radiobutton(
- _("Set a custom high DPI scaling"),
- 'high_dpi_custom_scale_factor',
- button_group=screen_resolution_bg,
- tip=_("Set this for high DPI displays when "
- "auto scaling does not work"),
- restart=True)
-
- custom_scaling_edit = self.create_lineedit("",
- 'high_dpi_custom_scale_factors',
- tip=_("Enter values for different screens "
- "separated by semicolons ';', "
- "float values are supported"),
- alignment=Qt.Horizontal,
- regex="[0-9]+(?:\.[0-9]*)(;[0-9]+(?:\.[0-9]*))*",
- restart=True)
-
- normal_radio.toggled.connect(custom_scaling_edit.setDisabled)
- auto_scale_radio.toggled.connect(custom_scaling_edit.setDisabled)
- custom_scaling_radio.toggled.connect(custom_scaling_edit.setEnabled)
-
- # Layout Screen resolution
- screen_resolution_layout = QVBoxLayout()
- screen_resolution_layout.addWidget(screen_resolution_label)
-
- screen_resolution_inner_layout = QGridLayout()
- screen_resolution_inner_layout.addWidget(normal_radio, 0, 0)
- screen_resolution_inner_layout.addWidget(auto_scale_radio, 1, 0)
- screen_resolution_inner_layout.addWidget(custom_scaling_radio, 2, 0)
- screen_resolution_inner_layout.addWidget(custom_scaling_edit, 2, 1)
-
- screen_resolution_layout.addLayout(screen_resolution_inner_layout)
- screen_resolution_group.setLayout(screen_resolution_layout)
-
- # --- Theme and fonts
- plain_text_font = self.create_fontgroup(
- option='font',
- title=_("Plain text font"),
- fontfilters=QFontComboBox.MonospacedFonts,
- without_group=True)
-
- rich_text_font = self.create_fontgroup(
- option='rich_font',
- title=_("Rich text font"),
- without_group=True)
-
- fonts_group = QGroupBox(_("Fonts"))
- fonts_layout = QGridLayout()
- fonts_layout.addWidget(plain_text_font.fontlabel, 0, 0)
- fonts_layout.addWidget(plain_text_font.fontbox, 0, 1)
- fonts_layout.addWidget(plain_text_font.sizelabel, 0, 2)
- fonts_layout.addWidget(plain_text_font.sizebox, 0, 3)
- fonts_layout.addWidget(rich_text_font.fontlabel, 1, 0)
- fonts_layout.addWidget(rich_text_font.fontbox, 1, 1)
- fonts_layout.addWidget(rich_text_font.sizelabel, 1, 2)
- fonts_layout.addWidget(rich_text_font.sizebox, 1, 3)
- fonts_group.setLayout(fonts_layout)
-
- tabs = QTabWidget()
- tabs.addTab(self.create_tab(fonts_group, screen_resolution_group,
- interface_group), _("Appearance"))
- tabs.addTab(self.create_tab(general_group, sbar_group),
- _("Advanced Settings"))
-
- vlayout = QVBoxLayout()
- vlayout.addWidget(tabs)
- self.setLayout(vlayout)
-
- def get_font(self, option):
- """Return global font used in Spyder."""
- return get_font(option=option)
-
- def set_font(self, font, option):
- """Set global font used in Spyder."""
- # Update fonts in all plugins
- set_font(font, option=option)
- plugins = self.main.widgetlist + self.main.thirdparty_plugins
- for plugin in plugins:
- plugin.update_font()
-
- def apply_settings(self, options):
- self.main.apply_settings()
-
- def _save_lang(self):
- """
- Get selected language setting and save to language configuration file.
- """
- for combobox, (option, _default) in list(self.comboboxes.items()):
- if option == 'interface_language':
- data = combobox.itemData(combobox.currentIndex())
- value = from_qvariant(data, to_text_string)
- break
- save_lang_conf(value)
- self.set_option('interface_language', value)
-
-
-class ColorSchemeConfigPage(GeneralConfigPage):
- CONF_SECTION = "color_schemes"
- NAME = _("Syntax coloring")
-
- def setup_page(self):
- self.ICON = ima.icon('eyedropper')
-
- names = self.get_option("names")
- try:
- names.pop(names.index(u'Custom'))
- except ValueError:
- pass
- custom_names = self.get_option("custom_names", [])
-
- # Widgets
- about_label = QLabel(_("Here you can select the color scheme used in "
- "the Editor and all other Spyder plugins.
"
- "You can also edit the color schemes provided "
- "by Spyder or create your own ones by using "
- "the options provided below.
"))
- edit_button = QPushButton(_("Edit selected"))
- create_button = QPushButton(_("Create new scheme"))
- self.delete_button = QPushButton(_("Delete"))
- self.preview_editor = CodeEditor(self)
- self.stacked_widget = QStackedWidget(self)
- self.reset_button = QPushButton(_("Reset"))
- self.scheme_editor_dialog = SchemeEditor(parent=self,
- stack=self.stacked_widget)
-
- # Widget setup
- self.scheme_choices_dict = {}
- about_label.setWordWrap(True)
- schemes_combobox_widget = self.create_combobox(_('Scheme:'),
- [('', '')],
- 'selected')
- self.schemes_combobox = schemes_combobox_widget.combobox
-
- # Layouts
- vlayout = QVBoxLayout()
-
- manage_layout = QVBoxLayout()
- manage_layout.addWidget(about_label)
-
- combo_layout = QHBoxLayout()
- combo_layout.addWidget(schemes_combobox_widget.label)
- combo_layout.addWidget(schemes_combobox_widget.combobox)
-
- buttons_layout = QVBoxLayout()
- buttons_layout.addLayout(combo_layout)
- buttons_layout.addWidget(edit_button)
- buttons_layout.addWidget(self.reset_button)
- buttons_layout.addWidget(self.delete_button)
- buttons_layout.addStretch(1)
- buttons_layout.addWidget(create_button)
-
- preview_layout = QVBoxLayout()
- preview_layout.addWidget(self.preview_editor)
-
- buttons_preview_layout = QHBoxLayout()
- buttons_preview_layout.addLayout(buttons_layout)
- buttons_preview_layout.addLayout(preview_layout)
-
- manage_layout.addLayout(buttons_preview_layout)
- manage_group = QGroupBox(_("Manage color schemes"))
- manage_group.setLayout(manage_layout)
-
- vlayout.addWidget(manage_group)
- self.setLayout(vlayout)
-
- # Signals and slots
- create_button.clicked.connect(self.create_new_scheme)
- edit_button.clicked.connect(self.edit_scheme)
- self.reset_button.clicked.connect(self.reset_to_default)
- self.delete_button.clicked.connect(self.delete_scheme)
- self.schemes_combobox.currentIndexChanged.connect(self.update_preview)
- self.schemes_combobox.currentIndexChanged.connect(self.update_buttons)
-
- # Setup
- for name in names:
- self.scheme_editor_dialog.add_color_scheme_stack(name)
-
- for name in custom_names:
- self.scheme_editor_dialog.add_color_scheme_stack(name, custom=True)
-
- self.update_combobox()
- self.update_preview()
-
- def apply_settings(self, options):
- self.set_option('selected', self.current_scheme)
- self.main.editor.apply_plugin_settings(['color_scheme_name'])
- if self.main.ipyconsole is not None:
- self.main.ipyconsole.apply_plugin_settings(['color_scheme_name'])
- if self.main.historylog is not None:
- self.main.historylog.apply_plugin_settings(['color_scheme_name'])
- if self.main.help is not None:
- self.main.help.apply_plugin_settings(['color_scheme_name'])
- self.update_combobox()
- self.update_preview()
-
- # Helpers
- # -------------------------------------------------------------------------
- @property
- def current_scheme_name(self):
- return self.schemes_combobox.currentText()
-
- @property
- def current_scheme(self):
- return self.scheme_choices_dict[self.current_scheme_name]
-
- @property
- def current_scheme_index(self):
- return self.schemes_combobox.currentIndex()
-
- def update_combobox(self):
- """Recreates the combobox contents."""
- index = self.current_scheme_index
- self.schemes_combobox.blockSignals(True)
- names = self.get_option("names")
- try:
- names.pop(names.index(u'Custom'))
- except ValueError:
- pass
- custom_names = self.get_option("custom_names", [])
-
- # Useful for retrieving the actual data
- for n in names + custom_names:
- self.scheme_choices_dict[self.get_option('{0}/name'.format(n))] = n
-
- if custom_names:
- choices = names + [None] + custom_names
- else:
- choices = names
-
- combobox = self.schemes_combobox
- combobox.clear()
-
- for name in choices:
- if name is None:
- continue
- combobox.addItem(self.get_option('{0}/name'.format(name)), name)
-
- if custom_names:
- combobox.insertSeparator(len(names))
-
- self.schemes_combobox.blockSignals(False)
- self.schemes_combobox.setCurrentIndex(index)
-
- def update_buttons(self):
- """Updates the enable status of delete and reset buttons."""
- current_scheme = self.current_scheme
- names = self.get_option("names")
- try:
- names.pop(names.index(u'Custom'))
- except ValueError:
- pass
- delete_enabled = current_scheme not in names
- self.delete_button.setEnabled(delete_enabled)
- self.reset_button.setEnabled(not delete_enabled)
-
- def update_preview(self, index=None, scheme_name=None):
- """
- Update the color scheme of the preview editor and adds text.
-
- Note
- ----
- 'index' is needed, because this is triggered by a signal that sends
- the selected index.
- """
- text = ('"""A string"""\n\n'
- '# A comment\n\n'
- '# %% A cell\n\n'
- 'class Foo(object):\n'
- ' def __init__(self):\n'
- ' bar = 42\n'
- ' print(bar)\n'
- )
- show_blanks = CONF.get('editor', 'blank_spaces')
- update_scrollbar = CONF.get('editor', 'scroll_past_end')
- if scheme_name is None:
- scheme_name = self.current_scheme
- self.preview_editor.setup_editor(linenumbers=True,
- markers=True,
- tab_mode=False,
- font=get_font(),
- show_blanks=show_blanks,
- color_scheme=scheme_name,
- scroll_past_end=update_scrollbar)
- self.preview_editor.set_text(text)
- self.preview_editor.set_language('Python')
-
- # Actions
- # -------------------------------------------------------------------------
- def create_new_scheme(self):
- """Creates a new color scheme with a custom name."""
- names = self.get_option('names')
- custom_names = self.get_option('custom_names', [])
-
- # Get the available number this new color scheme
- counter = len(custom_names) - 1
- custom_index = [int(n.split('-')[-1]) for n in custom_names]
- for i in range(len(custom_names)):
- if custom_index[i] != i:
- counter = i - 1
- break
- custom_name = "custom-{0}".format(counter+1)
-
- # Add the config settings, based on the current one.
- custom_names.append(custom_name)
- self.set_option('custom_names', custom_names)
- for key in syntaxhighlighters.COLOR_SCHEME_KEYS:
- name = "{0}/{1}".format(custom_name, key)
- default_name = "{0}/{1}".format(self.current_scheme, key)
- option = self.get_option(default_name)
- self.set_option(name, option)
- self.set_option('{0}/name'.format(custom_name), custom_name)
-
- # Now they need to be loaded! how to make a partial load_from_conf?
- dlg = self.scheme_editor_dialog
- dlg.add_color_scheme_stack(custom_name, custom=True)
- dlg.set_scheme(custom_name)
- self.load_from_conf()
-
- if dlg.exec_():
- # This is needed to have the custom name updated on the combobox
- name = dlg.get_scheme_name()
- self.set_option('{0}/name'.format(custom_name), name)
-
- # The +1 is needed because of the separator in the combobox
- index = (names + custom_names).index(custom_name) + 1
- self.update_combobox()
- self.schemes_combobox.setCurrentIndex(index)
- else:
- # Delete the config ....
- custom_names.remove(custom_name)
- self.set_option('custom_names', custom_names)
- dlg.delete_color_scheme_stack(custom_name)
-
- def edit_scheme(self):
- """Edit current scheme."""
- dlg = self.scheme_editor_dialog
- dlg.set_scheme(self.current_scheme)
-
- if dlg.exec_():
- # Update temp scheme to reflect instant edits on the preview
- temporal_color_scheme = dlg.get_edited_color_scheme()
- for key in temporal_color_scheme:
- option = "temp/{0}".format(key)
- value = temporal_color_scheme[key]
- self.set_option(option, value)
- self.update_preview(scheme_name='temp')
-
- def delete_scheme(self):
- """Deletes the currently selected custom color scheme."""
- scheme_name = self.current_scheme
-
- answer = QMessageBox.warning(self, _("Warning"),
- _("Are you sure you want to delete "
- "this scheme?"),
- QMessageBox.Yes | QMessageBox.No)
- if answer == QMessageBox.Yes:
- # Put the combobox in Spyder by default, when deleting a scheme
- names = self.get_option('names')
- self.set_scheme('spyder')
- self.schemes_combobox.setCurrentIndex(names.index('spyder'))
- self.set_option('selected', 'spyder')
-
- # Delete from custom_names
- custom_names = self.get_option('custom_names', [])
- if scheme_name in custom_names:
- custom_names.remove(scheme_name)
- self.set_option('custom_names', custom_names)
-
- # Delete config options
- for key in syntaxhighlighters.COLOR_SCHEME_KEYS:
- option = "{0}/{1}".format(scheme_name, key)
- CONF.remove_option(self.CONF_SECTION, option)
- CONF.remove_option(self.CONF_SECTION, "{0}/name".format(scheme_name))
-
- self.update_combobox()
- self.update_preview()
-
- def set_scheme(self, scheme_name):
- """
- Set the current stack in the dialog to the scheme with 'scheme_name'.
- """
- dlg = self.scheme_editor_dialog
- dlg.set_scheme(scheme_name)
-
- @Slot()
- def reset_to_default(self):
- """Restore initial values for default color schemes."""
- # Checks that this is indeed a default scheme
- scheme = self.current_scheme
- names = self.get_option('names')
- if scheme in names:
- for key in syntaxhighlighters.COLOR_SCHEME_KEYS:
- option = "{0}/{1}".format(scheme, key)
- value = CONF.get_default(self.CONF_SECTION, option)
- self.set_option(option, value)
-
- self.load_from_conf()
-
-
-class SchemeEditor(QDialog):
- """A color scheme editor dialog."""
- def __init__(self, parent=None, stack=None):
- super(SchemeEditor, self).__init__(parent)
- self.parent = parent
- self.stack = stack
- self.order = [] # Uses scheme names
-
- # Needed for self.get_edited_color_scheme()
- self.widgets = {}
- self.scheme_name_textbox = {}
- self.last_edited_color_scheme = None
- self.last_used_scheme = None
-
- # Widgets
- bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
-
- # Layout
- layout = QVBoxLayout()
- layout.addWidget(self.stack)
- layout.addWidget(bbox)
- self.setLayout(layout)
-
- # Signals
- bbox.accepted.connect(self.accept)
- bbox.accepted.connect(self.get_edited_color_scheme)
- bbox.rejected.connect(self.reject)
-
- # Helpers
- # -------------------------------------------------------------------------
- def set_scheme(self, scheme_name):
- """Set the current stack by 'scheme_name'."""
- self.stack.setCurrentIndex(self.order.index(scheme_name))
- self.last_used_scheme = scheme_name
-
- def get_scheme_name(self):
- """
- Returns the edited scheme name, needed to update the combobox on
- scheme creation.
- """
- return self.scheme_name_textbox[self.last_used_scheme].text()
-
- def get_edited_color_scheme(self):
- """
- Get the values of the last edited color scheme to be used in an instant
- preview in the preview editor, without using `apply`.
- """
- color_scheme = {}
- scheme_name = self.last_used_scheme
-
- for key in self.widgets[scheme_name]:
- items = self.widgets[scheme_name][key]
-
- if len(items) == 1:
- # ColorLayout
- value = items[0].text()
- else:
- # ColorLayout + checkboxes
- value = (items[0].text(), items[1].isChecked(),
- items[2].isChecked())
-
- color_scheme[key] = value
-
- return color_scheme
-
- # Actions
- # -------------------------------------------------------------------------
- def add_color_scheme_stack(self, scheme_name, custom=False):
- """Add a stack for a given scheme and connects the CONF values."""
- color_scheme_groups = [
- (_('Text'), ["normal", "comment", "string", "number", "keyword",
- "builtin", "definition", "instance", ]),
- (_('Highlight'), ["currentcell", "currentline", "occurrence",
- "matched_p", "unmatched_p", "ctrlclick"]),
- (_('Background'), ["background", "sideareas"])
- ]
-
- parent = self.parent
- line_edit = parent.create_lineedit(_("Scheme name:"),
- '{0}/name'.format(scheme_name))
-
- self.widgets[scheme_name] = {}
-
- # Widget setup
- line_edit.label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
- self.setWindowTitle(_('Color scheme editor'))
-
- # Layout
- name_layout = QHBoxLayout()
- name_layout.addWidget(line_edit.label)
- name_layout.addWidget(line_edit.textbox)
- self.scheme_name_textbox[scheme_name] = line_edit.textbox
-
- if not custom:
- line_edit.textbox.setDisabled(True)
-
- cs_layout = QVBoxLayout()
- cs_layout.addLayout(name_layout)
-
- h_layout = QHBoxLayout()
- v_layout = QVBoxLayout()
-
- for index, item in enumerate(color_scheme_groups):
- group_name, keys = item
- group_layout = QGridLayout()
-
- for row, key in enumerate(keys):
- option = "{0}/{1}".format(scheme_name, key)
- value = self.parent.get_option(option)
- name = syntaxhighlighters.COLOR_SCHEME_KEYS[key]
-
- if is_text_string(value):
- label, clayout = parent.create_coloredit(
- name,
- option,
- without_layout=True,
- )
- label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
- group_layout.addWidget(label, row+1, 0)
- group_layout.addLayout(clayout, row+1, 1)
-
- # Needed to update temp scheme to obtain instant preview
- self.widgets[scheme_name][key] = [clayout]
- else:
- label, clayout, cb_bold, cb_italic = parent.create_scedit(
- name,
- option,
- without_layout=True,
- )
- label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
- group_layout.addWidget(label, row+1, 0)
- group_layout.addLayout(clayout, row+1, 1)
- group_layout.addWidget(cb_bold, row+1, 2)
- group_layout.addWidget(cb_italic, row+1, 3)
-
- # Needed to update temp scheme to obtain instant preview
- self.widgets[scheme_name][key] = [clayout, cb_bold,
- cb_italic]
-
- group_box = QGroupBox(group_name)
- group_box.setLayout(group_layout)
-
- if index == 0:
- h_layout.addWidget(group_box)
- else:
- v_layout.addWidget(group_box)
-
- h_layout.addLayout(v_layout)
- cs_layout.addLayout(h_layout)
-
- stackitem = QWidget()
- stackitem.setLayout(cs_layout)
- self.stack.addWidget(stackitem)
- self.order.append(scheme_name)
-
- def delete_color_scheme_stack(self, scheme_name):
- """Remove stack widget by 'scheme_name'."""
- self.set_scheme(scheme_name)
- widget = self.stack.currentWidget()
- self.stack.removeWidget(widget)
- index = self.order.index(scheme_name)
- self.order.pop(index)
diff --git a/spyder/plugins/console.py b/spyder/plugins/console.py
deleted file mode 100644
index 56f1b34d661..00000000000
--- a/spyder/plugins/console.py
+++ /dev/null
@@ -1,370 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright © Spyder Project Contributors
-# Licensed under the terms of the MIT License
-# (see spyder/__init__.py for details)
-
-"""Internal Console Plugin"""
-
-# pylint: disable=C0103
-# pylint: disable=R0903
-# pylint: disable=R0911
-# pylint: disable=R0201
-
-# Standard library imports
-import os
-import os.path as osp
-import sys
-
-# Third party imports
-from qtpy.compat import getopenfilename
-from qtpy.QtCore import Qt, Signal, Slot
-from qtpy.QtWidgets import QInputDialog, QLineEdit, QMenu, QHBoxLayout
-
-# Local imports
-from spyder.config.base import _, DEV, DEBUG, debug_print
-from spyder.config.main import CONF
-from spyder.utils import icon_manager as ima
-from spyder.utils.environ import EnvDialog
-from spyder.utils.misc import (get_error_match, remove_backslashes,
- getcwd_or_home)
-from spyder.utils.qthelpers import (add_actions, create_action,
- create_plugin_layout, DialogManager,
- mimedata2url, MENU_SEPARATOR)
-from spyder.widgets.internalshell import InternalShell
-from spyder.widgets.findreplace import FindReplace
-from spyder.widgets.variableexplorer.collectionseditor import CollectionsEditor
-from spyder.widgets.reporterror import SpyderErrorDialog
-from spyder.api.plugins import SpyderPluginWidget
-from spyder.py3compat import to_text_string
-
-
-class Console(SpyderPluginWidget):
- """
- Console widget
- """
- CONF_SECTION = 'internal_console'
- focus_changed = Signal()
- redirect_stdio = Signal(bool)
- edit_goto = Signal(str, int, str)
-
- def __init__(self, parent=None, namespace=None, commands=[], message=None,
- exitfunc=None, profile=False, multithreaded=False):
- SpyderPluginWidget.__init__(self, parent)
-
- debug_print(" ..internal console: initializing")
- self.dialog_manager = DialogManager()
-
- # Shell
- light_background = self.get_option('light_background')
- self.shell = InternalShell(parent, namespace, commands, message,
- self.get_option('max_line_count'),
- self.get_plugin_font(), exitfunc, profile,
- multithreaded,
- light_background=light_background)
- self.shell.status.connect(lambda msg: self.show_message.emit(msg, 0))
- self.shell.go_to_error.connect(self.go_to_error)
- self.shell.focus_changed.connect(lambda: self.focus_changed.emit())
-
- # Redirecting some signals:
- self.shell.redirect_stdio.connect(lambda state:
- self.redirect_stdio.emit(state))
-
- # Initialize plugin
- self.initialize_plugin()
-
- # Find/replace widget
- self.find_widget = FindReplace(self)
- self.find_widget.set_editor(self.shell)
- self.find_widget.hide()
- self.register_widget_shortcuts(self.find_widget)
-
- # Main layout
- btn_layout = QHBoxLayout()
- btn_layout.setAlignment(Qt.AlignLeft)
- btn_layout.addStretch()
- btn_layout.addWidget(self.options_button, Qt.AlignRight)
- layout = create_plugin_layout(btn_layout)
- layout.addWidget(self.shell)
- layout.addWidget(self.find_widget)
- self.setLayout(layout)
-
- # Parameters
- self.shell.toggle_wrap_mode(self.get_option('wrap'))
-
- # Accepting drops
- self.setAcceptDrops(True)
-
- # Traceback MessageBox
- self.error_dlg = None
- self.error_traceback = ""
- self.dismiss_error = False
-
- #------ Private API --------------------------------------------------------
- def set_help(self, help_plugin):
- """Bind help instance to this console"""
- self.shell.help = help_plugin
-
- #------ SpyderPluginWidget API ---------------------------------------------
- def get_plugin_title(self):
- """Return widget title"""
- return _('Internal console')
-
- def get_focus_widget(self):
- """
- Return the widget to give focus to when
- this plugin's dockwidget is raised on top-level
- """
- return self.shell
-
- def update_font(self):
- """Update font from Preferences"""
- font = self.get_plugin_font()
- self.shell.set_font(font)
-
- def closing_plugin(self, cancelable=False):
- """Perform actions before parent main window is closed"""
- self.dialog_manager.close_all()
- self.shell.exit_interpreter()
- return True
-
- def refresh_plugin(self):
- pass
-
- def get_plugin_actions(self):
- """Return a list of actions related to plugin"""
- quit_action = create_action(self, _("&Quit"),
- icon=ima.icon('exit'),
- tip=_("Quit"),
- triggered=self.quit)
- self.register_shortcut(quit_action, "_", "Quit", "Ctrl+Q")
- run_action = create_action(self, _("&Run..."), None,
- ima.icon('run_small'),
- _("Run a Python script"),
- triggered=self.run_script)
- environ_action = create_action(self,
- _("Environment variables..."),
- icon=ima.icon('environ'),
- tip=_("Show and edit environment variables"
- " (for current session)"),
- triggered=self.show_env)
- syspath_action = create_action(self,
- _("Show sys.path contents..."),
- icon=ima.icon('syspath'),
- tip=_("Show (read-only) sys.path"),
- triggered=self.show_syspath)
- buffer_action = create_action(self,
- _("Buffer..."), None,
- tip=_("Set maximum line count"),
- triggered=self.change_max_line_count)
- exteditor_action = create_action(self,
- _("External editor path..."), None, None,
- _("Set external editor executable path"),
- triggered=self.change_exteditor)
- wrap_action = create_action(self,
- _("Wrap lines"),
- toggled=self.toggle_wrap_mode)
- wrap_action.setChecked(self.get_option('wrap'))
- calltips_action = create_action(self, _("Display balloon tips"),
- toggled=self.toggle_calltips)
- calltips_action.setChecked(self.get_option('calltips'))
- codecompletion_action = create_action(self,
- _("Automatic code completion"),
- toggled=self.toggle_codecompletion)
- codecompletion_action.setChecked(self.get_option('codecompletion/auto'))
- codecompenter_action = create_action(self,
- _("Enter key selects completion"),
- toggled=self.toggle_codecompletion_enter)
- codecompenter_action.setChecked(self.get_option(
- 'codecompletion/enter_key'))
-
- option_menu = QMenu(_('Internal console settings'), self)
- option_menu.setIcon(ima.icon('tooloptions'))
- add_actions(option_menu, (buffer_action, wrap_action,
- calltips_action, codecompletion_action,
- codecompenter_action, exteditor_action))
-
- plugin_actions = [None, run_action, environ_action, syspath_action,
- option_menu, MENU_SEPARATOR, quit_action,
- self.undock_action]
-
- return plugin_actions
-
- def register_plugin(self):
- """Register plugin in Spyder's main window"""
- self.focus_changed.connect(self.main.plugin_focus_changed)
- self.main.add_dockwidget(self)
- # Connecting the following signal once the dockwidget has been created:
- self.shell.exception_occurred.connect(self.exception_occurred)
-
- def exception_occurred(self, text, is_traceback):
- """
- Exception ocurred in the internal console.
-
- Show a QDialog or the internal console to warn the user.
- """
- # Skip errors without traceback or dismiss
- if (not is_traceback and self.error_dlg is None) or self.dismiss_error:
- return
-
- if CONF.get('main', 'show_internal_errors'):
- if self.error_dlg is None:
- self.error_dlg = SpyderErrorDialog(self)
- self.error_dlg.close_btn.clicked.connect(self.close_error_dlg)
- self.error_dlg.rejected.connect(self.remove_error_dlg)
- self.error_dlg.details.go_to_error.connect(self.go_to_error)
- self.error_dlg.show()
- self.error_dlg.append_traceback(text)
- elif DEV or DEBUG:
- self.dockwidget.show()
- self.dockwidget.raise_()
-
- def close_error_dlg(self):
- """Close error dialog."""
- if self.error_dlg.dismiss_box.isChecked():
- self.dismiss_error = True
- self.error_dlg.reject()
-
- def remove_error_dlg(self):
- """Remove error dialog."""
- self.error_dlg = None
-
- #------ Public API ---------------------------------------------------------
- @Slot()
- def quit(self):
- """Quit mainwindow"""
- self.main.close()
-
- @Slot()
- def show_env(self):
- """Show environment variables"""
- self.dialog_manager.show(EnvDialog())
-
- @Slot()
- def show_syspath(self):
- """Show sys.path"""
- editor = CollectionsEditor()
- editor.setup(sys.path, title="sys.path", readonly=True,
- width=600, icon=ima.icon('syspath'))
- self.dialog_manager.show(editor)
-
- @Slot()
- def run_script(self, filename=None, silent=False, set_focus=False,
- args=None):
- """Run a Python script"""
- if filename is None:
- self.shell.interpreter.restore_stds()
- filename, _selfilter = getopenfilename(
- self, _("Run Python script"), getcwd_or_home(),
- _("Python scripts")+" (*.py ; *.pyw ; *.ipy)")
- self.shell.interpreter.redirect_stds()
- if filename:
- os.chdir( osp.dirname(filename) )
- filename = osp.basename(filename)
- else:
- return
- debug_print(args)
- filename = osp.abspath(filename)
- rbs = remove_backslashes
- command = "runfile('%s', args='%s')" % (rbs(filename), rbs(args))
- if set_focus:
- self.shell.setFocus()
- if self.dockwidget and not self.ismaximized:
- self.dockwidget.setVisible(True)
- self.dockwidget.raise_()
- self.shell.write(command+'\n')
- self.shell.run_command(command)
-
-
- def go_to_error(self, text):
- """Go to error if relevant"""
- match = get_error_match(to_text_string(text))
- if match:
- fname, lnb = match.groups()
- self.edit_script(fname, int(lnb))
-
- def edit_script(self, filename=None, goto=-1):
- """Edit script"""
- # Called from InternalShell
- if not hasattr(self, 'main') \
- or not hasattr(self.main, 'editor'):
- self.shell.external_editor(filename, goto)
- return
- if filename is not None:
- self.edit_goto.emit(osp.abspath(filename), goto, '')
-
- def execute_lines(self, lines):
- """Execute lines and give focus to shell"""
- self.shell.execute_lines(to_text_string(lines))
- self.shell.setFocus()
-
- @Slot()
- def change_max_line_count(self):
- "Change maximum line count"""
- mlc, valid = QInputDialog.getInt(self, _('Buffer'),
- _('Maximum line count'),
- self.get_option('max_line_count'),
- 0, 1000000)
- if valid:
- self.shell.setMaximumBlockCount(mlc)
- self.set_option('max_line_count', mlc)
-
- @Slot()
- def change_exteditor(self):
- """Change external editor path"""
- path, valid = QInputDialog.getText(self, _('External editor'),
- _('External editor executable path:'),
- QLineEdit.Normal,
- self.get_option('external_editor/path'))
- if valid:
- self.set_option('external_editor/path', to_text_string(path))
-
- @Slot(bool)
- def toggle_wrap_mode(self, checked):
- """Toggle wrap mode"""
- self.shell.toggle_wrap_mode(checked)
- self.set_option('wrap', checked)
-
- @Slot(bool)
- def toggle_calltips(self, checked):
- """Toggle calltips"""
- self.shell.set_calltips(checked)
- self.set_option('calltips', checked)
-
- @Slot(bool)
- def toggle_codecompletion(self, checked):
- """Toggle automatic code completion"""
- self.shell.set_codecompletion_auto(checked)
- self.set_option('codecompletion/auto', checked)
-
- @Slot(bool)
- def toggle_codecompletion_enter(self, checked):
- """Toggle Enter key for code completion"""
- self.shell.set_codecompletion_enter(checked)
- self.set_option('codecompletion/enter_key', checked)
-
- #----Drag and drop
- def dragEnterEvent(self, event):
- """Reimplement Qt method
- Inform Qt about the types of data that the widget accepts"""
- source = event.mimeData()
- if source.hasUrls():
- if mimedata2url(source):
- event.acceptProposedAction()
- else:
- event.ignore()
- elif source.hasText():
- event.acceptProposedAction()
-
- def dropEvent(self, event):
- """Reimplement Qt method
- Unpack dropped data and handle it"""
- source = event.mimeData()
- if source.hasUrls():
- pathlist = mimedata2url(source)
- self.shell.drop_pathlist(pathlist)
- elif source.hasText():
- lines = to_text_string(source.text())
- self.shell.set_cursor_position('eof')
- self.shell.execute_lines(lines)
- event.acceptProposedAction()
diff --git a/spyder/plugins/console/__init__.py b/spyder/plugins/console/__init__.py
new file mode 100644
index 00000000000..6563fcb987a
--- /dev/null
+++ b/spyder/plugins/console/__init__.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+
+"""
+spyder.plugins.console
+======================
+
+Internal Console Plugin.
+"""
diff --git a/spyder/plugins/console/plugin.py b/spyder/plugins/console/plugin.py
new file mode 100644
index 00000000000..2fb57221fe4
--- /dev/null
+++ b/spyder/plugins/console/plugin.py
@@ -0,0 +1,355 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Internal Console Plugin"""
+
+# pylint: disable=C0103
+# pylint: disable=R0903
+# pylint: disable=R0911
+# pylint: disable=R0201
+
+# Standard library imports
+import os
+import os.path as osp
+import sys
+import logging
+
+# Third party imports
+from qtpy.compat import getopenfilename
+from qtpy.QtCore import Qt, Signal, Slot
+from qtpy.QtWidgets import QInputDialog, QLineEdit, QMenu, QHBoxLayout
+
+# Local imports
+from spyder.config.base import _, DEV, get_debug_level
+from spyder.config.main import CONF
+from spyder.utils import icon_manager as ima
+from spyder.utils.environ import EnvDialog
+from spyder.utils.misc import (get_error_match, remove_backslashes,
+ getcwd_or_home)
+from spyder.utils.qthelpers import (add_actions, create_action,
+ create_plugin_layout, DialogManager,
+ mimedata2url, MENU_SEPARATOR)
+from spyder.plugins.console.widgets.internalshell import InternalShell
+from spyder.widgets.findreplace import FindReplace
+from spyder.plugins.variableexplorer.widgets.collectionseditor import (
+ CollectionsEditor)
+from spyder.widgets.reporterror import SpyderErrorDialog
+from spyder.api.plugins import SpyderPluginWidget
+from spyder.py3compat import to_text_string
+
+logger = logging.getLogger(__name__)
+
+
+class Console(SpyderPluginWidget):
+ """
+ Console widget
+ """
+ CONF_SECTION = 'internal_console'
+ focus_changed = Signal()
+ redirect_stdio = Signal(bool)
+ edit_goto = Signal(str, int, str)
+
+ def __init__(self, parent=None, namespace=None, commands=[], message=None,
+ exitfunc=None, profile=False, multithreaded=False):
+ SpyderPluginWidget.__init__(self, parent)
+
+ logger.info("Initializing...")
+ self.dialog_manager = DialogManager()
+
+ # Shell
+ self.shell = InternalShell(parent, namespace, commands, message,
+ self.get_option('max_line_count'),
+ self.get_plugin_font(), exitfunc, profile,
+ multithreaded)
+ self.shell.status.connect(lambda msg: self.show_message.emit(msg, 0))
+ self.shell.go_to_error.connect(self.go_to_error)
+ self.shell.focus_changed.connect(lambda: self.focus_changed.emit())
+
+ # Redirecting some signals:
+ self.shell.redirect_stdio.connect(lambda state:
+ self.redirect_stdio.emit(state))
+
+ # Initialize plugin
+ self.initialize_plugin()
+
+ # Find/replace widget
+ self.find_widget = FindReplace(self)
+ self.find_widget.set_editor(self.shell)
+ self.find_widget.hide()
+ self.register_widget_shortcuts(self.find_widget)
+
+ # Main layout
+ btn_layout = QHBoxLayout()
+ btn_layout.setAlignment(Qt.AlignLeft)
+ btn_layout.addStretch()
+ btn_layout.addWidget(self.options_button, Qt.AlignRight)
+ layout = create_plugin_layout(btn_layout)
+ layout.addWidget(self.shell)
+ layout.addWidget(self.find_widget)
+ self.setLayout(layout)
+
+ # Parameters
+ self.shell.toggle_wrap_mode(self.get_option('wrap'))
+
+ # Accepting drops
+ self.setAcceptDrops(True)
+
+ # Traceback MessageBox
+ self.error_dlg = None
+ self.error_traceback = ""
+ self.dismiss_error = False
+
+ #------ Private API --------------------------------------------------------
+ def set_help(self, help_plugin):
+ """Bind help instance to this console"""
+ self.shell.help = help_plugin
+
+ #------ SpyderPluginWidget API ---------------------------------------------
+ def get_plugin_title(self):
+ """Return widget title"""
+ return _('Internal console')
+
+ def get_focus_widget(self):
+ """
+ Return the widget to give focus to when
+ this plugin's dockwidget is raised on top-level
+ """
+ return self.shell
+
+ def update_font(self):
+ """Update font from Preferences"""
+ font = self.get_plugin_font()
+ self.shell.set_font(font)
+
+ def closing_plugin(self, cancelable=False):
+ """Perform actions before parent main window is closed"""
+ self.dialog_manager.close_all()
+ self.shell.exit_interpreter()
+ return True
+
+ def refresh_plugin(self):
+ pass
+
+ def get_plugin_actions(self):
+ """Return a list of actions related to plugin"""
+ quit_action = create_action(self, _("&Quit"),
+ icon=ima.icon('exit'),
+ tip=_("Quit"),
+ triggered=self.quit)
+ self.register_shortcut(quit_action, "_", "Quit", "Ctrl+Q")
+ run_action = create_action(self, _("&Run..."), None,
+ ima.icon('run_small'),
+ _("Run a Python script"),
+ triggered=self.run_script)
+ environ_action = create_action(self,
+ _("Environment variables..."),
+ icon=ima.icon('environ'),
+ tip=_("Show and edit environment variables"
+ " (for current session)"),
+ triggered=self.show_env)
+ syspath_action = create_action(self,
+ _("Show sys.path contents..."),
+ icon=ima.icon('syspath'),
+ tip=_("Show (read-only) sys.path"),
+ triggered=self.show_syspath)
+ buffer_action = create_action(self,
+ _("Buffer..."), None,
+ tip=_("Set maximum line count"),
+ triggered=self.change_max_line_count)
+ exteditor_action = create_action(self,
+ _("External editor path..."), None, None,
+ _("Set external editor executable path"),
+ triggered=self.change_exteditor)
+ wrap_action = create_action(self,
+ _("Wrap lines"),
+ toggled=self.toggle_wrap_mode)
+ wrap_action.setChecked(self.get_option('wrap'))
+ codecompletion_action = create_action(self,
+ _("Automatic code completion"),
+ toggled=self.toggle_codecompletion)
+ codecompletion_action.setChecked(self.get_option('codecompletion/auto'))
+
+ option_menu = QMenu(_('Internal console settings'), self)
+ option_menu.setIcon(ima.icon('tooloptions'))
+ add_actions(option_menu, (buffer_action, wrap_action,
+ codecompletion_action,
+ exteditor_action))
+
+ plugin_actions = [None, run_action, environ_action, syspath_action,
+ option_menu, MENU_SEPARATOR, quit_action,
+ self.undock_action]
+
+ return plugin_actions
+
+ def register_plugin(self):
+ """Register plugin in Spyder's main window"""
+ self.focus_changed.connect(self.main.plugin_focus_changed)
+ self.main.add_dockwidget(self)
+ # Connecting the following signal once the dockwidget has been created:
+ self.shell.exception_occurred.connect(self.exception_occurred)
+
+ def exception_occurred(self, text, is_traceback, is_pyls_error=False):
+ """
+ Exception ocurred in the internal console.
+
+ Show a QDialog or the internal console to warn the user.
+ """
+ # Skip errors without traceback or dismiss
+ if (not is_traceback and self.error_dlg is None) or self.dismiss_error:
+ return
+
+ if CONF.get('main', 'show_internal_errors'):
+ if self.error_dlg is None:
+ self.error_dlg = SpyderErrorDialog(self)
+ self.error_dlg.close_btn.clicked.connect(self.close_error_dlg)
+ self.error_dlg.rejected.connect(self.remove_error_dlg)
+ self.error_dlg.details.go_to_error.connect(self.go_to_error)
+ if is_pyls_error:
+ title = "Internal Python Language Server error"
+ self.error_dlg.set_title(title)
+ self.error_dlg.title.setEnabled(False)
+ self.error_dlg.append_traceback(text)
+ self.error_dlg.show()
+ elif DEV or get_debug_level():
+ self.switch_to_plugin()
+
+ def close_error_dlg(self):
+ """Close error dialog."""
+ if self.error_dlg.dismiss_box.isChecked():
+ self.dismiss_error = True
+ self.error_dlg.reject()
+
+ def remove_error_dlg(self):
+ """Remove error dialog."""
+ self.error_dlg = None
+
+ #------ Public API ---------------------------------------------------------
+ @Slot()
+ def quit(self):
+ """Quit mainwindow"""
+ self.main.close()
+
+ @Slot()
+ def show_env(self):
+ """Show environment variables"""
+ self.dialog_manager.show(EnvDialog(parent=self))
+
+ @Slot()
+ def show_syspath(self):
+ """Show sys.path"""
+ editor = CollectionsEditor(parent=self)
+ editor.setup(sys.path, title="sys.path", readonly=True,
+ width=600, icon=ima.icon('syspath'))
+ self.dialog_manager.show(editor)
+
+ @Slot()
+ def run_script(self, filename=None, silent=False, set_focus=False,
+ args=None):
+ """Run a Python script"""
+ if filename is None:
+ self.shell.interpreter.restore_stds()
+ filename, _selfilter = getopenfilename(
+ self, _("Run Python script"), getcwd_or_home(),
+ _("Python scripts")+" (*.py ; *.pyw ; *.ipy)")
+ self.shell.interpreter.redirect_stds()
+ if filename:
+ os.chdir( osp.dirname(filename) )
+ filename = osp.basename(filename)
+ else:
+ return
+ logger.debug("Running script with %s", args)
+ filename = osp.abspath(filename)
+ rbs = remove_backslashes
+ command = "runfile('%s', args='%s')" % (rbs(filename), rbs(args))
+ if set_focus:
+ self.shell.setFocus()
+ if self.dockwidget and not self.ismaximized:
+ self.dockwidget.setVisible(True)
+ self.dockwidget.raise_()
+ self.shell.write(command+'\n')
+ self.shell.run_command(command)
+
+
+ def go_to_error(self, text):
+ """Go to error if relevant"""
+ match = get_error_match(to_text_string(text))
+ if match:
+ fname, lnb = match.groups()
+ self.edit_script(fname, int(lnb))
+
+ def edit_script(self, filename=None, goto=-1):
+ """Edit script"""
+ # Called from InternalShell
+ if not hasattr(self, 'main') \
+ or not hasattr(self.main, 'editor'):
+ self.shell.external_editor(filename, goto)
+ return
+ if filename is not None:
+ self.edit_goto.emit(osp.abspath(filename), goto, '')
+
+ def execute_lines(self, lines):
+ """Execute lines and give focus to shell"""
+ self.shell.execute_lines(to_text_string(lines))
+ self.shell.setFocus()
+
+ @Slot()
+ def change_max_line_count(self):
+ "Change maximum line count"""
+ mlc, valid = QInputDialog.getInt(self, _('Buffer'),
+ _('Maximum line count'),
+ self.get_option('max_line_count'),
+ 0, 1000000)
+ if valid:
+ self.shell.setMaximumBlockCount(mlc)
+ self.set_option('max_line_count', mlc)
+
+ @Slot()
+ def change_exteditor(self):
+ """Change external editor path"""
+ path, valid = QInputDialog.getText(self, _('External editor'),
+ _('External editor executable path:'),
+ QLineEdit.Normal,
+ self.get_option('external_editor/path'))
+ if valid:
+ self.set_option('external_editor/path', to_text_string(path))
+
+ @Slot(bool)
+ def toggle_wrap_mode(self, checked):
+ """Toggle wrap mode"""
+ self.shell.toggle_wrap_mode(checked)
+ self.set_option('wrap', checked)
+
+ @Slot(bool)
+ def toggle_codecompletion(self, checked):
+ """Toggle automatic code completion"""
+ self.shell.set_codecompletion_auto(checked)
+ self.set_option('codecompletion/auto', checked)
+
+ #----Drag and drop
+ def dragEnterEvent(self, event):
+ """Reimplement Qt method
+ Inform Qt about the types of data that the widget accepts"""
+ source = event.mimeData()
+ if source.hasUrls():
+ if mimedata2url(source):
+ event.acceptProposedAction()
+ else:
+ event.ignore()
+ elif source.hasText():
+ event.acceptProposedAction()
+
+ def dropEvent(self, event):
+ """Reimplement Qt method
+ Unpack dropped data and handle it"""
+ source = event.mimeData()
+ if source.hasUrls():
+ pathlist = mimedata2url(source)
+ self.shell.drop_pathlist(pathlist)
+ elif source.hasText():
+ lines = to_text_string(source.text())
+ self.shell.set_cursor_position('eof')
+ self.shell.execute_lines(lines)
+ event.acceptProposedAction()
diff --git a/spyder/plugins/console/utils/__init__.py b/spyder/plugins/console/utils/__init__.py
new file mode 100644
index 00000000000..65301b65eb5
--- /dev/null
+++ b/spyder/plugins/console/utils/__init__.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+spyder.plugins.console.utils
+============================
+
+Some utility classes and functions for the internal console.
+"""
diff --git a/spyder/plugins/console/utils/ansihandler.py b/spyder/plugins/console/utils/ansihandler.py
new file mode 100644
index 00000000000..f343669f4a8
--- /dev/null
+++ b/spyder/plugins/console/utils/ansihandler.py
@@ -0,0 +1,115 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Terminal emulation tools"""
+
+import os
+
+class ANSIEscapeCodeHandler(object):
+ """ANSI Escape sequences handler"""
+ if os.name == 'nt':
+ # Windows terminal colors:
+ ANSI_COLORS = ( # Normal, Bright/Light
+ ('#000000', '#808080'), # 0: black
+ ('#800000', '#ff0000'), # 1: red
+ ('#008000', '#00ff00'), # 2: green
+ ('#808000', '#ffff00'), # 3: yellow
+ ('#000080', '#0000ff'), # 4: blue
+ ('#800080', '#ff00ff'), # 5: magenta
+ ('#008080', '#00ffff'), # 6: cyan
+ ('#c0c0c0', '#ffffff'), # 7: white
+ )
+ elif os.name == 'mac':
+ # Terminal.app colors:
+ ANSI_COLORS = ( # Normal, Bright/Light
+ ('#000000', '#818383'), # 0: black
+ ('#C23621', '#FC391F'), # 1: red
+ ('#25BC24', '#25BC24'), # 2: green
+ ('#ADAD27', '#EAEC23'), # 3: yellow
+ ('#492EE1', '#5833FF'), # 4: blue
+ ('#D338D3', '#F935F8'), # 5: magenta
+ ('#33BBC8', '#14F0F0'), # 6: cyan
+ ('#CBCCCD', '#E9EBEB'), # 7: white
+ )
+ else:
+ # xterm colors:
+ ANSI_COLORS = ( # Normal, Bright/Light
+ ('#000000', '#7F7F7F'), # 0: black
+ ('#CD0000', '#ff0000'), # 1: red
+ ('#00CD00', '#00ff00'), # 2: green
+ ('#CDCD00', '#ffff00'), # 3: yellow
+ ('#0000EE', '#5C5CFF'), # 4: blue
+ ('#CD00CD', '#ff00ff'), # 5: magenta
+ ('#00CDCD', '#00ffff'), # 6: cyan
+ ('#E5E5E5', '#ffffff'), # 7: white
+ )
+ def __init__(self):
+ self.intensity = 0
+ self.italic = None
+ self.bold = None
+ self.underline = None
+ self.foreground_color = None
+ self.background_color = None
+ self.default_foreground_color = 30
+ self.default_background_color = 47
+
+ def set_code(self, code):
+ assert isinstance(code, int)
+ if code == 0:
+ # Reset all settings
+ self.reset()
+ elif code == 1:
+ # Text color intensity
+ self.intensity = 1
+ # The following line is commented because most terminals won't
+ # change the font weight, against ANSI standard recommendation:
+# self.bold = True
+ elif code == 3:
+ # Italic on
+ self.italic = True
+ elif code == 4:
+ # Underline simple
+ self.underline = True
+ elif code == 22:
+ # Normal text color intensity
+ self.intensity = 0
+ self.bold = False
+ elif code == 23:
+ # No italic
+ self.italic = False
+ elif code == 24:
+ # No underline
+ self.underline = False
+ elif code >= 30 and code <= 37:
+ # Text color
+ self.foreground_color = code
+ elif code == 39:
+ # Default text color
+ self.foreground_color = self.default_foreground_color
+ elif code >= 40 and code <= 47:
+ # Background color
+ self.background_color = code
+ elif code == 49:
+ # Default background color
+ self.background_color = self.default_background_color
+ self.set_style()
+
+ def set_style(self):
+ """
+ Set font style with the following attributes:
+ 'foreground_color', 'background_color', 'italic',
+ 'bold' and 'underline'
+ """
+ raise NotImplementedError
+
+ def reset(self):
+ self.current_format = None
+ self.intensity = 0
+ self.italic = False
+ self.bold = False
+ self.underline = False
+ self.foreground_color = None
+ self.background_color = None
diff --git a/spyder/interpreter.py b/spyder/plugins/console/utils/interpreter.py
similarity index 93%
rename from spyder/interpreter.py
rename to spyder/plugins/console/utils/interpreter.py
index 5b461a1c579..9e063ec93e6 100644
--- a/spyder/interpreter.py
+++ b/spyder/plugins/console/utils/interpreter.py
@@ -18,8 +18,9 @@
import pydoc
from code import InteractiveConsole
+from spyder_kernels.utils.dochelpers import isdefined
+
# Local imports:
-from spyder.utils.dochelpers import isdefined
from spyder.utils import encoding, programs
from spyder.py3compat import is_text_string
from spyder.utils.misc import remove_backslashes, getcwd_or_home
@@ -56,42 +57,42 @@ def __init__(self, namespace=None, exitfunc=None,
"""
InteractiveConsole.__init__(self, namespace)
threading.Thread.__init__(self)
-
+
self._id = None
-
+
self.exit_flag = False
self.debug = debug
-
+
# Execution Status
self.more = False
-
+
if exitfunc is not None:
atexit.register(exitfunc)
-
+
self.namespace = self.locals
self.namespace['__name__'] = '__main__'
self.namespace['execfile'] = self.execfile
self.namespace['runfile'] = self.runfile
self.namespace['raw_input'] = self.raw_input_replacement
self.namespace['help'] = self.help_replacement
-
- # Capture all interactive input/output
+
+ # Capture all interactive input/output
self.initial_stdout = sys.stdout
self.initial_stderr = sys.stderr
self.initial_stdin = sys.stdin
-
+
# Create communication pipes
pr, pw = os.pipe()
self.stdin_read = os.fdopen(pr, "r")
self.stdin_write = os.fdopen(pw, "wb", 0)
self.stdout_write = Output()
self.stderr_write = Output()
-
+
self.input_condition = threading.Condition()
self.widget_proxy = WidgetProxy(self.input_condition)
-
+
self.redirect_stds()
-
+
#------ Standard input/output
def redirect_stds(self):
@@ -100,7 +101,7 @@ def redirect_stds(self):
sys.stdout = self.stdout_write
sys.stderr = self.stderr_write
sys.stdin = self.stdin_read
-
+
def restore_stds(self):
"""Restore stds"""
if not self.debug:
@@ -117,7 +118,7 @@ def raw_input_replacement(self, prompt=''):
inp = self.widget_proxy.input_data
self.input_condition.release()
return inp
-
+
def help_replacement(self, text=None, interactive=False):
"""For help builtin function emulation"""
if text is not None and not interactive:
@@ -128,7 +129,7 @@ def help_replacement(self, text=None, interactive=False):
Welcome to Python %s! This is the online help utility.
If this is your first time using Python, you should definitely check out
-the tutorial on the Internet at http://www.python.org/doc/tut/.
+the tutorial on the Internet at https://www.python.org/about/gettingstarted/
Enter the name of any module, keyword, or topic to get help on writing
Python programs and using Python modules. To quit this help utility and
@@ -181,7 +182,7 @@ def run_command(self, cmd, new_prompt=True):
elif cd_match:
cmd = 'import os; os.chdir(r"%s")' % cd_match.groups()[0].strip()
# -- End of Special commands type I
-
+
# -- Special commands type II
# (don't need code execution in interpreter)
xedit_match = re.match(special_pattern % 'xedit', cmd)
@@ -225,24 +226,24 @@ def run_command(self, cmd, new_prompt=True):
# self.widget_proxy.set_readonly(True)
self.more = self.push(cmd)
# self.widget_proxy.set_readonly(False)
-
+
if new_prompt:
self.widget_proxy.new_prompt(self.p2 if self.more else self.p1)
if not self.more:
self.resetbuffer()
-
+
def run(self):
"""Wait for input and run it"""
while not self.exit_flag:
self.run_line()
-
+
def run_line(self):
line = self.stdin_read.readline()
if self.exit_flag:
return
# Remove last character which is always '\n':
self.run_command(line[:-1])
-
+
def get_thread_id(self):
"""Return thread id"""
if self._id is None:
@@ -250,7 +251,7 @@ def get_thread_id(self):
if obj is self:
self._id = thread_id
return self._id
-
+
def raise_keyboard_interrupt(self):
if self.isAlive():
ctypes.pythonapi.PyThreadState_SetAsyncExc(self.get_thread_id(),
@@ -258,12 +259,12 @@ def raise_keyboard_interrupt(self):
return True
else:
return False
-
-
+
+
def closing(self):
"""Actions to be done before restarting this interpreter"""
pass
-
+
def execfile(self, filename):
"""Exec filename"""
source = open(filename, 'r').read()
@@ -277,7 +278,7 @@ def execfile(self, filename):
InteractiveConsole.showsyntaxerror(self, filename)
else:
self.runcode(code)
-
+
def runfile(self, filename, args=None):
"""
Run filename
@@ -293,7 +294,7 @@ def runfile(self, filename, args=None):
self.execfile(filename)
sys.argv = ['']
self.namespace.pop('__file__')
-
+
def eval(self, text):
"""
Evaluate text and return (obj, valid)
@@ -305,31 +306,30 @@ def eval(self, text):
return eval(text, self.locals), True
except:
return None, False
-
+
def is_defined(self, objtxt, force_import=False):
"""Return True if object is defined"""
return isdefined(objtxt, force_import=force_import,
namespace=self.locals)
-
+
#===========================================================================
# InteractiveConsole API
#===========================================================================
def push(self, line):
"""
Push a line of source text to the interpreter
-
- The line should not have a trailing newline; it may have internal
- newlines. The line is appended to a buffer and the interpreter’s
- runsource() method is called with the concatenated contents of the
- buffer as source. If this indicates that the command was executed
- or invalid, the buffer is reset; otherwise, the command is incomplete,
- and the buffer is left as it was after the line was appended.
- The return value is True if more input is required, False if the line
+
+ The line should not have a trailing newline; it may have internal
+ newlines. The line is appended to a buffer and the interpreter’s
+ runsource() method is called with the concatenated contents of the
+ buffer as source. If this indicates that the command was executed
+ or invalid, the buffer is reset; otherwise, the command is incomplete,
+ and the buffer is left as it was after the line was appended.
+ The return value is True if more input is required, False if the line
was dealt with in some way (this is the same as runsource()).
"""
return InteractiveConsole.push(self, "#coding=utf-8\n" + line)
-
+
def resetbuffer(self):
"""Remove any unhandled source text from the input buffer"""
InteractiveConsole.resetbuffer(self)
-
diff --git a/spyder/plugins/console/widgets/__init__.py b/spyder/plugins/console/widgets/__init__.py
new file mode 100644
index 00000000000..97000e1ad2c
--- /dev/null
+++ b/spyder/plugins/console/widgets/__init__.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+spyder.plugins.console.widgets
+==============================
+"""
diff --git a/spyder/plugins/console/widgets/console.py b/spyder/plugins/console/widgets/console.py
new file mode 100644
index 00000000000..d141047c58c
--- /dev/null
+++ b/spyder/plugins/console/widgets/console.py
@@ -0,0 +1,298 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Console base class"""
+
+import re
+
+from qtconsole.styles import dark_color
+from qtpy.QtCore import Signal
+from qtpy.QtGui import QColor, QFont, QTextCharFormat, QTextCursor
+from qtpy.QtWidgets import QApplication
+
+from spyder.config.gui import is_dark_interface
+from spyder.plugins.editor.widgets.base import TextEditBaseWidget
+from spyder.plugins.console.utils.ansihandler import ANSIEscapeCodeHandler
+
+
+if is_dark_interface():
+ MAIN_BG_COLOR = '#19232D'
+ MAIN_DEFAULT_FG_COLOR = '#ffffff'
+ MAIN_ERROR_FG_COLOR = '#FF0000'
+ MAIN_TB_FG_COLOR = '#2980b9'
+ MAIN_PROMPT_FG_COLOR = '#00AA00'
+else:
+ MAIN_BG_COLOR = 'white'
+ MAIN_DEFAULT_FG_COLOR = '#000000'
+ MAIN_ERROR_FG_COLOR = '#FF0000'
+ MAIN_TB_FG_COLOR = '#0000FF'
+ MAIN_PROMPT_FG_COLOR = '#00AA00'
+
+
+def insert_text_to(cursor, text, fmt):
+ """Helper to print text, taking into account backspaces"""
+ while True:
+ index = text.find(chr(8)) # backspace
+ if index == -1:
+ break
+ cursor.insertText(text[:index], fmt)
+ if cursor.positionInBlock() > 0:
+ cursor.deletePreviousChar()
+ text = text[index+1:]
+ cursor.insertText(text, fmt)
+
+
+class QtANSIEscapeCodeHandler(ANSIEscapeCodeHandler):
+ def __init__(self):
+ ANSIEscapeCodeHandler.__init__(self)
+ self.base_format = None
+ self.current_format = None
+
+ def set_color_scheme(self, foreground_color, background_color):
+ """Set color scheme (foreground and background)."""
+ if dark_color(foreground_color):
+ self.default_foreground_color = 30
+ else:
+ self.default_foreground_color = 37
+
+ if dark_color(background_color):
+ self.default_background_color = 47
+ else:
+ self.default_background_color = 40
+
+ def set_base_format(self, base_format):
+ self.base_format = base_format
+
+ def get_format(self):
+ return self.current_format
+
+ def set_style(self):
+ """
+ Set font style with the following attributes:
+ 'foreground_color', 'background_color', 'italic',
+ 'bold' and 'underline'
+ """
+ if self.current_format is None:
+ assert self.base_format is not None
+ self.current_format = QTextCharFormat(self.base_format)
+ # Foreground color
+ if self.foreground_color is None:
+ qcolor = self.base_format.foreground()
+ else:
+ cstr = self.ANSI_COLORS[self.foreground_color-30][self.intensity]
+ qcolor = QColor(cstr)
+ self.current_format.setForeground(qcolor)
+ # Background color
+ if self.background_color is None:
+ qcolor = self.base_format.background()
+ else:
+ cstr = self.ANSI_COLORS[self.background_color-40][self.intensity]
+ qcolor = QColor(cstr)
+ self.current_format.setBackground(qcolor)
+
+ font = self.current_format.font()
+ # Italic
+ if self.italic is None:
+ italic = self.base_format.fontItalic()
+ else:
+ italic = self.italic
+ font.setItalic(italic)
+ # Bold
+ if self.bold is None:
+ bold = self.base_format.font().bold()
+ else:
+ bold = self.bold
+ font.setBold(bold)
+ # Underline
+ if self.underline is None:
+ underline = self.base_format.font().underline()
+ else:
+ underline = self.underline
+ font.setUnderline(underline)
+ self.current_format.setFont(font)
+
+
+def inverse_color(color):
+ color.setHsv(color.hue(), color.saturation(), 255-color.value())
+
+
+class ConsoleFontStyle(object):
+ def __init__(self, foregroundcolor, backgroundcolor,
+ bold, italic, underline):
+ self.foregroundcolor = foregroundcolor
+ self.backgroundcolor = backgroundcolor
+ self.bold = bold
+ self.italic = italic
+ self.underline = underline
+ self.format = None
+
+ def apply_style(self, font, is_default):
+ self.format = QTextCharFormat()
+ self.format.setFont(font)
+ foreground = QColor(self.foregroundcolor)
+ self.format.setForeground(foreground)
+ background = QColor(self.backgroundcolor)
+ self.format.setBackground(background)
+ font = self.format.font()
+ font.setBold(self.bold)
+ font.setItalic(self.italic)
+ font.setUnderline(self.underline)
+ self.format.setFont(font)
+
+
+class ConsoleBaseWidget(TextEditBaseWidget):
+ """Console base widget"""
+ BRACE_MATCHING_SCOPE = ('sol', 'eol')
+ COLOR_PATTERN = re.compile(r'\x01?\x1b\[(.*?)m\x02?')
+ exception_occurred = Signal(str, bool)
+ userListActivated = Signal(int, str)
+ completion_widget_activated = Signal(str)
+
+ def __init__(self, parent=None):
+ TextEditBaseWidget.__init__(self, parent)
+
+ # We use an object name to set the right background
+ # color when changing interface theme. This seems to
+ # be a Qt bug.
+ # Fixes issue 8072
+ self.setObjectName('console')
+
+ self.setMaximumBlockCount(300)
+
+ # ANSI escape code handler
+ self.ansi_handler = QtANSIEscapeCodeHandler()
+
+ # Disable undo/redo (nonsense for a console widget...):
+ self.setUndoRedoEnabled(False)
+
+ self.userListActivated.connect(
+ lambda user_id, text: self.completion_widget_activated.emit(text))
+
+ background_color = MAIN_BG_COLOR
+ default_foreground_color = MAIN_DEFAULT_FG_COLOR
+ error_foreground_color = MAIN_ERROR_FG_COLOR
+ traceback_foreground_color = MAIN_TB_FG_COLOR
+ prompt_foreground_color = MAIN_PROMPT_FG_COLOR
+
+ self.default_style = ConsoleFontStyle(
+ foregroundcolor=default_foreground_color,
+ backgroundcolor=background_color,
+ bold=False, italic=False, underline=False)
+ self.error_style = ConsoleFontStyle(
+ foregroundcolor=error_foreground_color,
+ backgroundcolor=background_color,
+ bold=False, italic=False, underline=False)
+ self.traceback_link_style = ConsoleFontStyle(
+ foregroundcolor=traceback_foreground_color,
+ backgroundcolor=background_color,
+ bold=True, italic=False, underline=True)
+ self.prompt_style = ConsoleFontStyle(
+ foregroundcolor=prompt_foreground_color,
+ backgroundcolor=background_color,
+ bold=True, italic=False, underline=False)
+ self.font_styles = (self.default_style, self.error_style,
+ self.traceback_link_style, self.prompt_style)
+
+ self.set_color_scheme(default_foreground_color, background_color)
+ self.setMouseTracking(True)
+
+ def set_color_scheme(self, foreground_color, background_color):
+ """Set color scheme of the console (foreground and background)."""
+ self.ansi_handler.set_color_scheme(foreground_color, background_color)
+
+ background_color = QColor(background_color)
+ foreground_color = QColor(foreground_color)
+
+ self.set_palette(background=background_color,
+ foreground=foreground_color)
+
+ self.set_pythonshell_font()
+
+ # ----- Python shell
+ def insert_text(self, text):
+ """Reimplement TextEditBaseWidget method"""
+ # Eventually this maybe should wrap to insert_text_to if
+ # backspace-handling is required
+ self.textCursor().insertText(text, self.default_style.format)
+
+ def paste(self):
+ """Reimplement Qt method"""
+ if self.has_selected_text():
+ self.remove_selected_text()
+ self.insert_text(QApplication.clipboard().text())
+
+ def append_text_to_shell(self, text, error, prompt):
+ """
+ Append text to Python shell
+ In a way, this method overrides the method 'insert_text' when text is
+ inserted at the end of the text widget for a Python shell
+
+ Handles error messages and show blue underlined links
+ Handles ANSI color sequences
+ Handles ANSI FF sequence
+ """
+ cursor = self.textCursor()
+ cursor.movePosition(QTextCursor.End)
+ if '\r' in text: # replace \r\n with \n
+ text = text.replace('\r\n', '\n')
+ text = text.replace('\r', '\n')
+ while True:
+ index = text.find(chr(12))
+ if index == -1:
+ break
+ text = text[index+1:]
+ self.clear()
+ if error:
+ is_traceback = False
+ for text in text.splitlines(True):
+ if (text.startswith(' File')
+ and not text.startswith(' File "<')):
+ is_traceback = True
+ # Show error links in blue underlined text
+ cursor.insertText(' ', self.default_style.format)
+ cursor.insertText(text[2:],
+ self.traceback_link_style.format)
+ else:
+ # Show error/warning messages in red
+ cursor.insertText(text, self.error_style.format)
+ self.exception_occurred.emit(text, is_traceback)
+ elif prompt:
+ # Show prompt in green
+ insert_text_to(cursor, text, self.prompt_style.format)
+ else:
+ # Show other outputs in black
+ last_end = 0
+ for match in self.COLOR_PATTERN.finditer(text):
+ insert_text_to(cursor, text[last_end:match.start()],
+ self.default_style.format)
+ last_end = match.end()
+ try:
+ for code in [int(_c) for _c in match.group(1).split(';')]:
+ self.ansi_handler.set_code(code)
+ except ValueError:
+ pass
+ self.default_style.format = self.ansi_handler.get_format()
+ insert_text_to(cursor, text[last_end:], self.default_style.format)
+# # Slower alternative:
+# segments = self.COLOR_PATTERN.split(text)
+# cursor.insertText(segments.pop(0), self.default_style.format)
+# if segments:
+# for ansi_tags, text in zip(segments[::2], segments[1::2]):
+# for ansi_tag in ansi_tags.split(';'):
+# self.ansi_handler.set_code(int(ansi_tag))
+# self.default_style.format = self.ansi_handler.get_format()
+# cursor.insertText(text, self.default_style.format)
+ self.set_cursor_position('eof')
+ self.setCurrentCharFormat(self.default_style.format)
+
+ def set_pythonshell_font(self, font=None):
+ """Python Shell only"""
+ if font is None:
+ font = QFont()
+ for style in self.font_styles:
+ style.apply_style(font=font,
+ is_default=style is self.default_style)
+ self.ansi_handler.set_base_format(self.default_style.format)
diff --git a/spyder/widgets/internalshell.py b/spyder/plugins/console/widgets/internalshell.py
similarity index 89%
rename from spyder/widgets/internalshell.py
rename to spyder/plugins/console/widgets/internalshell.py
index f2047fd4cc9..19da3ad3150 100644
--- a/spyder/widgets/internalshell.py
+++ b/spyder/plugins/console/widgets/internalshell.py
@@ -21,23 +21,24 @@
# Third party imports
from qtpy.QtCore import QEventLoop, QObject, Signal, Slot
from qtpy.QtWidgets import QMessageBox
+from spyder_kernels.utils.dochelpers import (getargtxt, getdoc, getobjdir,
+ getsource)
# Local imports
from spyder import get_versions
-from spyder.interpreter import Interpreter
+from spyder.plugins.console.utils.interpreter import Interpreter
from spyder.py3compat import (builtins, to_binary_string,
to_text_string)
from spyder.utils import icon_manager as ima
from spyder.utils import programs
-from spyder.utils.dochelpers import getargtxt, getdoc, getobjdir, getsource
from spyder.utils.misc import get_error_match, getcwd_or_home
from spyder.utils.qthelpers import create_action
-from spyder.widgets.shell import PythonShellWidget
-from spyder.widgets.variableexplorer.objecteditor import oedit
+from spyder.plugins.console.widgets.shell import PythonShellWidget
+from spyder.plugins.variableexplorer.widgets.objecteditor import oedit
# TODO: remove the CONF object and make it work anyway
# In fact, this 'CONF' object has nothing to do in package spyder/widgets
# which should not contain anything directly related to Spyder's main app
-from spyder.config.base import _, DEBUG, get_conf_path
+from spyder.config.base import _, get_conf_path, get_debug_level
from spyder.config.main import CONF
@@ -57,12 +58,12 @@ def create_banner(message):
class SysOutput(QObject):
"""Handle standard I/O queue"""
data_avail = Signal()
-
+
def __init__(self):
QObject.__init__(self)
self.queue = []
self.lock = threading.Lock()
-
+
def write(self, val):
self.lock.acquire()
self.queue.append(val)
@@ -75,7 +76,7 @@ def empty_queue(self):
self.queue = []
self.lock.release()
return s
-
+
# We need to add this method to fix Issue 1789
def flush(self):
pass
@@ -90,34 +91,34 @@ class WidgetProxyData(object):
class WidgetProxy(QObject):
"""Handle Shell widget refresh signal"""
-
+
sig_new_prompt = Signal(str)
sig_set_readonly = Signal(bool)
sig_edit = Signal(str, bool)
sig_wait_input = Signal(str)
-
+
def __init__(self, input_condition):
QObject.__init__(self)
self.input_data = None
self.input_condition = input_condition
-
+
def new_prompt(self, prompt):
self.sig_new_prompt.emit(prompt)
-
+
def set_readonly(self, state):
self.sig_set_readonly.emit(state)
-
+
def edit(self, filename, external_editor=False):
self.sig_edit.emit(filename, external_editor)
-
+
def data_available(self):
"""Return True if input data is available"""
return self.input_data is not WidgetProxyData
-
+
def wait_input(self, prompt=''):
self.input_data = WidgetProxyData
self.sig_wait_input.emit(prompt)
-
+
def end_input(self, cmd):
self.input_condition.acquire()
self.input_data = cmd
@@ -127,20 +128,19 @@ def end_input(self, cmd):
class InternalShell(PythonShellWidget):
"""Shell base widget: link between PythonShellWidget and Interpreter"""
-
+
status = Signal(str)
refresh = Signal()
go_to_error = Signal(str)
focus_changed = Signal()
-
+
def __init__(self, parent=None, namespace=None, commands=[], message=None,
max_line_count=300, font=None, exitfunc=None, profile=False,
- multithreaded=True, light_background=True):
+ multithreaded=True):
PythonShellWidget.__init__(self, parent,
get_conf_path('history_internal.py'),
- profile)
-
- self.set_light_background(light_background)
+ profile=profile)
+
self.multithreaded = multithreaded
self.setMaximumBlockCount(max_line_count)
@@ -150,16 +150,14 @@ def __init__(self, parent=None, namespace=None, commands=[], message=None,
# Allow raw_input support:
self.input_loop = None
self.input_mode = False
-
+
# KeyboardInterrupt support
self.interrupted = False # used only for not-multithreaded mode
self.sig_keyboard_interrupt.connect(self.keyboard_interrupt)
-
+
# Code completion / calltips
getcfg = lambda option: CONF.get('internal_console', option)
- case_sensitive = getcfg('codecompletion/case_sensitive')
- self.set_codecompletion_case(case_sensitive)
-
+
# keyboard events management
self.eventqueue = []
@@ -169,10 +167,10 @@ def __init__(self, parent=None, namespace=None, commands=[], message=None,
self.message = message
self.interpreter = None
self.start_interpreter(namespace)
-
+
# Clear status bar
self.status.emit('')
-
+
# Embedded shell -- requires the monitor (which installs the
# 'open_in_spyder' function in builtins)
if hasattr(builtins, 'open_in_spyder'):
@@ -182,11 +180,12 @@ def __init__(self, parent=None, namespace=None, commands=[], message=None,
def start_interpreter(self, namespace):
"""Start Python interpreter"""
self.clear()
-
+
if self.interpreter is not None:
self.interpreter.closing()
self.interpreter = Interpreter(namespace, self.exitfunc,
- SysOutput, WidgetProxy, DEBUG)
+ SysOutput, WidgetProxy,
+ get_debug_level())
self.interpreter.stdout_write.data_avail.connect(self.stdout_avail)
self.interpreter.stderr_write.data_avail.connect(self.stderr_avail)
self.interpreter.widget_proxy.sig_set_readonly.connect(self.setReadOnly)
@@ -195,7 +194,7 @@ def start_interpreter(self, namespace):
self.interpreter.widget_proxy.sig_wait_input.connect(self.wait_input)
if self.multithreaded:
self.interpreter.start()
-
+
# Interpreter banner
banner = create_banner(self.message)
self.write(banner, prompt=True)
@@ -203,7 +202,7 @@ def start_interpreter(self, namespace):
# Initial commands
for cmd in self.commands:
self.run_command(cmd, history=False, new_prompt=False)
-
+
# First prompt
self.new_prompt(self.interpreter.p1)
self.refresh.emit()
@@ -216,28 +215,28 @@ def exit_interpreter(self):
if self.multithreaded:
self.interpreter.stdin_write.write(to_binary_string('\n'))
self.interpreter.restore_stds()
-
+
def edit_script(self, filename, external_editor):
filename = to_text_string(filename)
if external_editor:
self.external_editor(filename)
else:
- self.parent().edit_script(filename)
-
+ self.parent().edit_script(filename)
+
def stdout_avail(self):
"""Data is available in stdout, let's empty the queue and write it!"""
data = self.interpreter.stdout_write.empty_queue()
if data:
self.write(data)
-
+
def stderr_avail(self):
"""Data is available in stderr, let's empty the queue and write it!"""
data = self.interpreter.stderr_write.empty_queue()
if data:
self.write(data, error=True)
self.flush(error=True)
-
-
+
+
#------Raw input support
def wait_input(self, prompt=''):
"""Wait for input (raw_input support)"""
@@ -247,7 +246,7 @@ def wait_input(self, prompt=''):
self.input_loop = QEventLoop()
self.input_loop.exec_()
self.input_loop = None
-
+
def end_input(self, cmd):
"""End of wait_input mode"""
self.input_mode = False
@@ -350,13 +349,13 @@ def keyPressEvent(self, event):
# Event was accepted in self.preprocess_keyevent
return
self.postprocess_keyevent(event)
-
+
def __flush_eventqueue(self):
"""Flush keyboard event queue"""
while self.eventqueue:
past_event = self.eventqueue.pop(0)
self.postprocess_keyevent(past_event)
-
+
#------ Command execution
def keyboard_interrupt(self):
"""Simulate keyboard interrupt"""
@@ -383,7 +382,7 @@ def execute_lines(self, lines):
self.write(line+os.linesep, flush=True)
self.execute_command(line+"\n")
self.flush()
-
+
def execute_command(self, cmd):
"""
Execute a command
@@ -399,7 +398,7 @@ def execute_command(self, cmd):
self.clear_terminal()
return
self.run_command(cmd)
-
+
def run_command(self, cmd, history=True, new_prompt=True):
"""Run command in interpreter"""
if not cmd:
@@ -407,55 +406,64 @@ def run_command(self, cmd, history=True, new_prompt=True):
else:
if history:
self.add_to_history(cmd)
- self.interpreter.stdin_write.write(to_binary_string(cmd + '\n'))
if not self.multithreaded:
- self.interpreter.run_line()
- self.refresh.emit()
-
-
+ if 'input' not in cmd:
+ self.interpreter.stdin_write.write(
+ to_binary_string(cmd + '\n'))
+ self.interpreter.run_line()
+ self.refresh.emit()
+ else:
+ self.write(_('In order to use commands like "raw_input" '
+ 'or "input" run Spyder with the multithread '
+ 'option (--multithread) from a system terminal'),
+ error=True)
+ else:
+ self.interpreter.stdin_write.write(to_binary_string(cmd + '\n'))
+
+
#------ Code completion / Calltips
def _eval(self, text):
"""Is text a valid object?"""
return self.interpreter.eval(text)
-
+
def get_dir(self, objtxt):
"""Return dir(object)"""
obj, valid = self._eval(objtxt)
if valid:
return getobjdir(obj)
-
+
def get_globals_keys(self):
"""Return shell globals() keys"""
return list(self.interpreter.namespace.keys())
-
+
def get_cdlistdir(self):
"""Return shell current directory list dir"""
return os.listdir(getcwd_or_home())
-
+
def iscallable(self, objtxt):
"""Is object callable?"""
obj, valid = self._eval(objtxt)
if valid:
return callable(obj)
-
+
def get_arglist(self, objtxt):
"""Get func/method argument list"""
obj, valid = self._eval(objtxt)
if valid:
return getargtxt(obj)
-
+
def get__doc__(self, objtxt):
"""Get object __doc__"""
obj, valid = self._eval(objtxt)
if valid:
return obj.__doc__
-
+
def get_doc(self, objtxt):
"""Get object documentation dictionary"""
obj, valid = self._eval(objtxt)
if valid:
return getdoc(obj)
-
+
def get_source(self, objtxt):
"""Get object source"""
obj, valid = self._eval(objtxt)
diff --git a/spyder/plugins/console/widgets/shell.py b/spyder/plugins/console/widgets/shell.py
new file mode 100644
index 00000000000..8ed6aaeceb7
--- /dev/null
+++ b/spyder/plugins/console/widgets/shell.py
@@ -0,0 +1,1013 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Shell widgets: base, python and terminal"""
+
+# pylint: disable=C0103
+# pylint: disable=R0903
+# pylint: disable=R0911
+# pylint: disable=R0201
+
+# Standard library imports
+import keyword
+import locale
+import os
+import os.path as osp
+import re
+import sys
+import time
+
+# Third party imports
+from qtpy.compat import getsavefilename
+from qtpy.QtCore import Property, QCoreApplication, Qt, QTimer, Signal, Slot
+from qtpy.QtGui import QKeySequence, QTextCharFormat, QTextCursor
+from qtpy.QtWidgets import QApplication, QMenu, QToolTip
+
+# Local import
+from spyder.config.base import _, get_conf_path, get_debug_level, STDERR
+from spyder.config.gui import config_shortcut, get_shortcut
+from spyder.config.main import CONF
+from spyder.py3compat import (builtins, is_string, is_text_string,
+ PY3, str_lower, to_text_string)
+from spyder.utils import encoding
+from spyder.utils import icon_manager as ima
+from spyder.utils.qthelpers import (add_actions, create_action, keybinding,
+ restore_keyevent)
+from spyder.widgets.mixins import (GetHelpMixin, SaveHistoryMixin,
+ TracebackLinksMixin, BrowseHistoryMixin)
+from spyder.plugins.console.widgets.console import ConsoleBaseWidget
+
+
+class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
+ BrowseHistoryMixin):
+ """
+ Shell base widget
+ """
+
+ redirect_stdio = Signal(bool)
+ sig_keyboard_interrupt = Signal()
+ execute = Signal(str)
+ append_to_history = Signal(str, str)
+
+ def __init__(self, parent, history_filename, profile=False,
+ initial_message=None, default_foreground_color=None,
+ error_foreground_color=None, traceback_foreground_color=None,
+ prompt_foreground_color=None, background_color=None):
+ """
+ parent : specifies the parent widget
+ """
+ ConsoleBaseWidget.__init__(self, parent)
+ SaveHistoryMixin.__init__(self, history_filename)
+ BrowseHistoryMixin.__init__(self)
+
+ # Prompt position: tuple (line, index)
+ self.current_prompt_pos = None
+ self.new_input_line = True
+
+ # History
+ assert is_text_string(history_filename)
+ self.history = self.load_history()
+
+ # Session
+ self.historylog_filename = CONF.get('main', 'historylog_filename',
+ get_conf_path('history.log'))
+
+ # Context menu
+ self.menu = None
+ self.setup_context_menu()
+
+ # Simple profiling test
+ self.profile = profile
+
+ # Buffer to increase performance of write/flush operations
+ self.__buffer = []
+ if initial_message:
+ self.__buffer.append(initial_message)
+
+ self.__timestamp = 0.0
+ self.__flushtimer = QTimer(self)
+ self.__flushtimer.setSingleShot(True)
+ self.__flushtimer.timeout.connect(self.flush)
+
+ # Give focus to widget
+ self.setFocus()
+
+ # Cursor width
+ self.setCursorWidth(CONF.get('main', 'cursor/width'))
+
+ # Adjustments to completion_widget to use it here
+ self.completion_widget.currentRowChanged.disconnect()
+
+ def toggle_wrap_mode(self, enable):
+ """Enable/disable wrap mode"""
+ self.set_wrap_mode('character' if enable else None)
+
+ def set_font(self, font):
+ """Set shell styles font"""
+ self.setFont(font)
+ self.set_pythonshell_font(font)
+ cursor = self.textCursor()
+ cursor.select(QTextCursor.Document)
+ charformat = QTextCharFormat()
+ charformat.setFontFamily(font.family())
+ charformat.setFontPointSize(font.pointSize())
+ cursor.mergeCharFormat(charformat)
+
+
+ #------ Context menu
+ def setup_context_menu(self):
+ """Setup shell context menu"""
+ self.menu = QMenu(self)
+ self.cut_action = create_action(self, _("Cut"),
+ shortcut=keybinding('Cut'),
+ icon=ima.icon('editcut'),
+ triggered=self.cut)
+ self.copy_action = create_action(self, _("Copy"),
+ shortcut=keybinding('Copy'),
+ icon=ima.icon('editcopy'),
+ triggered=self.copy)
+ paste_action = create_action(self, _("Paste"),
+ shortcut=keybinding('Paste'),
+ icon=ima.icon('editpaste'),
+ triggered=self.paste)
+ save_action = create_action(self, _("Save history log..."),
+ icon=ima.icon('filesave'),
+ tip=_("Save current history log (i.e. all "
+ "inputs and outputs) in a text file"),
+ triggered=self.save_historylog)
+ self.delete_action = create_action(self, _("Delete"),
+ shortcut=keybinding('Delete'),
+ icon=ima.icon('editdelete'),
+ triggered=self.delete)
+ selectall_action = create_action(self, _("Select All"),
+ shortcut=keybinding('SelectAll'),
+ icon=ima.icon('selectall'),
+ triggered=self.selectAll)
+ add_actions(self.menu, (self.cut_action, self.copy_action,
+ paste_action, self.delete_action, None,
+ selectall_action, None, save_action) )
+
+ def contextMenuEvent(self, event):
+ """Reimplement Qt method"""
+ state = self.has_selected_text()
+ self.copy_action.setEnabled(state)
+ self.cut_action.setEnabled(state)
+ self.delete_action.setEnabled(state)
+ self.menu.popup(event.globalPos())
+ event.accept()
+
+
+ #------ Input buffer
+ def get_current_line_from_cursor(self):
+ return self.get_text('cursor', 'eof')
+
+ def _select_input(self):
+ """Select current line (without selecting console prompt)"""
+ line, index = self.get_position('eof')
+ if self.current_prompt_pos is None:
+ pline, pindex = line, index
+ else:
+ pline, pindex = self.current_prompt_pos
+ self.setSelection(pline, pindex, line, index)
+
+ @Slot()
+ def clear_terminal(self):
+ """
+ Clear terminal window
+ Child classes reimplement this method to write prompt
+ """
+ self.clear()
+
+ # The buffer being edited
+ def _set_input_buffer(self, text):
+ """Set input buffer"""
+ if self.current_prompt_pos is not None:
+ self.replace_text(self.current_prompt_pos, 'eol', text)
+ else:
+ self.insert(text)
+ self.set_cursor_position('eof')
+
+ def _get_input_buffer(self):
+ """Return input buffer"""
+ input_buffer = ''
+ if self.current_prompt_pos is not None:
+ input_buffer = self.get_text(self.current_prompt_pos, 'eol')
+ input_buffer = input_buffer.replace(os.linesep, '\n')
+ return input_buffer
+
+ input_buffer = Property("QString", _get_input_buffer, _set_input_buffer)
+
+
+ #------ Prompt
+ def new_prompt(self, prompt):
+ """
+ Print a new prompt and save its (line, index) position
+ """
+ if self.get_cursor_line_column()[1] != 0:
+ self.write('\n')
+ self.write(prompt, prompt=True)
+ # now we update our cursor giving end of prompt
+ self.current_prompt_pos = self.get_position('cursor')
+ self.ensureCursorVisible()
+ self.new_input_line = False
+
+ def check_selection(self):
+ """
+ Check if selected text is r/w,
+ otherwise remove read-only parts of selection
+ """
+ if self.current_prompt_pos is None:
+ self.set_cursor_position('eof')
+ else:
+ self.truncate_selection(self.current_prompt_pos)
+
+
+ #------ Copy / Keyboard interrupt
+ @Slot()
+ def copy(self):
+ """Copy text to clipboard... or keyboard interrupt"""
+ if self.has_selected_text():
+ ConsoleBaseWidget.copy(self)
+ elif not sys.platform == 'darwin':
+ self.interrupt()
+
+ def interrupt(self):
+ """Keyboard interrupt"""
+ self.sig_keyboard_interrupt.emit()
+
+ @Slot()
+ def cut(self):
+ """Cut text"""
+ self.check_selection()
+ if self.has_selected_text():
+ ConsoleBaseWidget.cut(self)
+
+ @Slot()
+ def delete(self):
+ """Remove selected text"""
+ self.check_selection()
+ if self.has_selected_text():
+ ConsoleBaseWidget.remove_selected_text(self)
+
+ @Slot()
+ def save_historylog(self):
+ """Save current history log (all text in console)"""
+ title = _("Save history log")
+ self.redirect_stdio.emit(False)
+ filename, _selfilter = getsavefilename(self, title,
+ self.historylog_filename, "%s (*.log)" % _("History logs"))
+ self.redirect_stdio.emit(True)
+ if filename:
+ filename = osp.normpath(filename)
+ try:
+ encoding.write(to_text_string(self.get_text_with_eol()),
+ filename)
+ self.historylog_filename = filename
+ CONF.set('main', 'historylog_filename', filename)
+ except EnvironmentError:
+ pass
+
+ #------ Basic keypress event handler
+ def on_enter(self, command):
+ """on_enter"""
+ self.execute_command(command)
+
+ def execute_command(self, command):
+ self.execute.emit(command)
+ self.add_to_history(command)
+ self.new_input_line = True
+
+ def on_new_line(self):
+ """On new input line"""
+ self.set_cursor_position('eof')
+ self.current_prompt_pos = self.get_position('cursor')
+ self.new_input_line = False
+
+ @Slot()
+ def paste(self):
+ """Reimplemented slot to handle multiline paste action"""
+ if self.new_input_line:
+ self.on_new_line()
+ ConsoleBaseWidget.paste(self)
+
+ def keyPressEvent(self, event):
+ """
+ Reimplement Qt Method
+ Basic keypress event handler
+ (reimplemented in InternalShell to add more sophisticated features)
+ """
+ if self.preprocess_keyevent(event):
+ # Event was accepted in self.preprocess_keyevent
+ return
+ self.postprocess_keyevent(event)
+
+ def preprocess_keyevent(self, event):
+ """Pre-process keypress event:
+ return True if event is accepted, false otherwise"""
+ # Copy must be done first to be able to copy read-only text parts
+ # (otherwise, right below, we would remove selection
+ # if not on current line)
+ ctrl = event.modifiers() & Qt.ControlModifier
+ meta = event.modifiers() & Qt.MetaModifier # meta=ctrl in OSX
+ if event.key() == Qt.Key_C and \
+ ((Qt.MetaModifier | Qt.ControlModifier) & event.modifiers()):
+ if meta and sys.platform == 'darwin':
+ self.interrupt()
+ elif ctrl:
+ self.copy()
+ event.accept()
+ return True
+
+ if self.new_input_line and ( len(event.text()) or event.key() in \
+ (Qt.Key_Up, Qt.Key_Down, Qt.Key_Left, Qt.Key_Right) ):
+ self.on_new_line()
+
+ return False
+
+ def postprocess_keyevent(self, event):
+ """Post-process keypress event:
+ in InternalShell, this is method is called when shell is ready"""
+ event, text, key, ctrl, shift = restore_keyevent(event)
+
+ # Is cursor on the last line? and after prompt?
+ if len(text):
+ #XXX: Shouldn't it be: `if len(unicode(text).strip(os.linesep))` ?
+ if self.has_selected_text():
+ self.check_selection()
+ self.restrict_cursor_position(self.current_prompt_pos, 'eof')
+
+ cursor_position = self.get_position('cursor')
+
+ if key in (Qt.Key_Return, Qt.Key_Enter):
+ if self.is_cursor_on_last_line():
+ self._key_enter()
+ # add and run selection
+ else:
+ self.insert_text(self.get_selected_text(), at_end=True)
+
+ elif key == Qt.Key_Insert and not shift and not ctrl:
+ self.setOverwriteMode(not self.overwriteMode())
+
+ elif key == Qt.Key_Delete:
+ if self.has_selected_text():
+ self.check_selection()
+ self.remove_selected_text()
+ elif self.is_cursor_on_last_line():
+ self.stdkey_clear()
+
+ elif key == Qt.Key_Backspace:
+ self._key_backspace(cursor_position)
+
+ elif key == Qt.Key_Tab:
+ self._key_tab()
+
+ elif key == Qt.Key_Space and ctrl:
+ self._key_ctrl_space()
+
+ elif key == Qt.Key_Left:
+ if self.current_prompt_pos == cursor_position:
+ # Avoid moving cursor on prompt
+ return
+ method = self.extend_selection_to_next if shift \
+ else self.move_cursor_to_next
+ method('word' if ctrl else 'character', direction='left')
+
+ elif key == Qt.Key_Right:
+ if self.is_cursor_at_end():
+ return
+ method = self.extend_selection_to_next if shift \
+ else self.move_cursor_to_next
+ method('word' if ctrl else 'character', direction='right')
+
+ elif (key == Qt.Key_Home) or ((key == Qt.Key_Up) and ctrl):
+ self._key_home(shift, ctrl)
+
+ elif (key == Qt.Key_End) or ((key == Qt.Key_Down) and ctrl):
+ self._key_end(shift, ctrl)
+
+ elif key == Qt.Key_Up:
+ if not self.is_cursor_on_last_line():
+ self.set_cursor_position('eof')
+ y_cursor = self.get_coordinates(cursor_position)[1]
+ y_prompt = self.get_coordinates(self.current_prompt_pos)[1]
+ if y_cursor > y_prompt:
+ self.stdkey_up(shift)
+ else:
+ self.browse_history(backward=True)
+
+ elif key == Qt.Key_Down:
+ if not self.is_cursor_on_last_line():
+ self.set_cursor_position('eof')
+ y_cursor = self.get_coordinates(cursor_position)[1]
+ y_end = self.get_coordinates('eol')[1]
+ if y_cursor < y_end:
+ self.stdkey_down(shift)
+ else:
+ self.browse_history(backward=False)
+
+ elif key in (Qt.Key_PageUp, Qt.Key_PageDown):
+ #XXX: Find a way to do this programmatically instead of calling
+ # widget keyhandler (this won't work if the *event* is coming from
+ # the event queue - i.e. if the busy buffer is ever implemented)
+ ConsoleBaseWidget.keyPressEvent(self, event)
+
+ elif key == Qt.Key_Escape and shift:
+ self.clear_line()
+
+ elif key == Qt.Key_Escape:
+ self._key_escape()
+
+ elif key == Qt.Key_L and ctrl:
+ self.clear_terminal()
+
+ elif key == Qt.Key_V and ctrl:
+ self.paste()
+
+ elif key == Qt.Key_X and ctrl:
+ self.cut()
+
+ elif key == Qt.Key_Z and ctrl:
+ self.undo()
+
+ elif key == Qt.Key_Y and ctrl:
+ self.redo()
+
+ elif key == Qt.Key_A and ctrl:
+ self.selectAll()
+
+ elif key == Qt.Key_Question and not self.has_selected_text():
+ self._key_question(text)
+
+ elif key == Qt.Key_ParenLeft and not self.has_selected_text():
+ self._key_parenleft(text)
+
+ elif key == Qt.Key_Period and not self.has_selected_text():
+ self._key_period(text)
+
+ elif len(text) and not self.isReadOnly():
+ self.hist_wholeline = False
+ self.insert_text(text)
+ self._key_other(text)
+
+ else:
+ # Let the parent widget handle the key press event
+ ConsoleBaseWidget.keyPressEvent(self, event)
+
+
+ #------ Key handlers
+ def _key_enter(self):
+ command = self.input_buffer
+ self.insert_text('\n', at_end=True)
+ self.on_enter(command)
+ self.flush()
+ def _key_other(self, text):
+ raise NotImplementedError
+ def _key_backspace(self, cursor_position):
+ raise NotImplementedError
+ def _key_tab(self):
+ raise NotImplementedError
+ def _key_ctrl_space(self):
+ raise NotImplementedError
+ def _key_home(self, shift, ctrl):
+ if self.is_cursor_on_last_line():
+ self.stdkey_home(shift, ctrl, self.current_prompt_pos)
+ def _key_end(self, shift, ctrl):
+ if self.is_cursor_on_last_line():
+ self.stdkey_end(shift, ctrl)
+ def _key_pageup(self):
+ raise NotImplementedError
+ def _key_pagedown(self):
+ raise NotImplementedError
+ def _key_escape(self):
+ raise NotImplementedError
+ def _key_question(self, text):
+ raise NotImplementedError
+ def _key_parenleft(self, text):
+ raise NotImplementedError
+ def _key_period(self, text):
+ raise NotImplementedError
+
+
+ #------ History Management
+ def load_history(self):
+ """Load history from a .py file in user home directory"""
+ if osp.isfile(self.history_filename):
+ rawhistory, _ = encoding.readlines(self.history_filename)
+ rawhistory = [line.replace('\n', '') for line in rawhistory]
+ if rawhistory[1] != self.INITHISTORY[1]:
+ rawhistory[1] = self.INITHISTORY[1]
+ else:
+ rawhistory = self.INITHISTORY
+ history = [line for line in rawhistory \
+ if line and not line.startswith('#')]
+
+ # Truncating history to X entries:
+ while len(history) >= CONF.get('historylog', 'max_entries'):
+ del history[0]
+ while rawhistory[0].startswith('#'):
+ del rawhistory[0]
+ del rawhistory[0]
+
+ # Saving truncated history:
+ try:
+ encoding.writelines(rawhistory, self.history_filename)
+ except EnvironmentError:
+ pass
+
+ return history
+
+ #------ Simulation standards input/output
+ def write_error(self, text):
+ """Simulate stderr"""
+ self.flush()
+ self.write(text, flush=True, error=True)
+ if get_debug_level():
+ STDERR.write(text)
+
+ def write(self, text, flush=False, error=False, prompt=False):
+ """Simulate stdout and stderr"""
+ if prompt:
+ self.flush()
+ if not is_string(text):
+ # This test is useful to discriminate QStrings from decoded str
+ text = to_text_string(text)
+ self.__buffer.append(text)
+ ts = time.time()
+ if flush or prompt:
+ self.flush(error=error, prompt=prompt)
+ elif ts - self.__timestamp > 0.05:
+ self.flush(error=error)
+ self.__timestamp = ts
+ # Timer to flush strings cached by last write() operation in series
+ self.__flushtimer.start(50)
+
+ def flush(self, error=False, prompt=False):
+ """Flush buffer, write text to console"""
+ # Fix for Issue 2452
+ if PY3:
+ try:
+ text = "".join(self.__buffer)
+ except TypeError:
+ text = b"".join(self.__buffer)
+ try:
+ text = text.decode( locale.getdefaultlocale()[1] )
+ except:
+ pass
+ else:
+ text = "".join(self.__buffer)
+
+ self.__buffer = []
+ self.insert_text(text, at_end=True, error=error, prompt=prompt)
+ QCoreApplication.processEvents()
+ self.repaint()
+ # Clear input buffer:
+ self.new_input_line = True
+
+
+ #------ Text Insertion
+ def insert_text(self, text, at_end=False, error=False, prompt=False):
+ """
+ Insert text at the current cursor position
+ or at the end of the command line
+ """
+ if at_end:
+ # Insert text at the end of the command line
+ self.append_text_to_shell(text, error, prompt)
+ else:
+ # Insert text at current cursor position
+ ConsoleBaseWidget.insert_text(self, text)
+
+
+ #------ Re-implemented Qt Methods
+ def focusNextPrevChild(self, next):
+ """
+ Reimplemented to stop Tab moving to the next window
+ """
+ if next:
+ return False
+ return ConsoleBaseWidget.focusNextPrevChild(self, next)
+
+
+ #------ Drag and drop
+ def dragEnterEvent(self, event):
+ """Drag and Drop - Enter event"""
+ event.setAccepted(event.mimeData().hasFormat("text/plain"))
+
+ def dragMoveEvent(self, event):
+ """Drag and Drop - Move event"""
+ if (event.mimeData().hasFormat("text/plain")):
+ event.setDropAction(Qt.MoveAction)
+ event.accept()
+ else:
+ event.ignore()
+
+ def dropEvent(self, event):
+ """Drag and Drop - Drop event"""
+ if (event.mimeData().hasFormat("text/plain")):
+ text = to_text_string(event.mimeData().text())
+ if self.new_input_line:
+ self.on_new_line()
+ self.insert_text(text, at_end=True)
+ self.setFocus()
+ event.setDropAction(Qt.MoveAction)
+ event.accept()
+ else:
+ event.ignore()
+
+ def drop_pathlist(self, pathlist):
+ """Drop path list"""
+ raise NotImplementedError
+
+
+# Example how to debug complex interclass call chains:
+#
+# from spyder.utils.debug import log_methods_calls
+# log_methods_calls('log.log', ShellBaseWidget)
+
+class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
+ GetHelpMixin):
+ """Python shell widget"""
+ QT_CLASS = ShellBaseWidget
+ INITHISTORY = ['# -*- coding: utf-8 -*-',
+ '# *** Spyder Python Console History Log ***',]
+ SEPARATOR = '%s##---(%s)---' % (os.linesep*2, time.ctime())
+ go_to_error = Signal(str)
+
+ def __init__(self, parent, history_filename, profile=False, initial_message=None):
+ ShellBaseWidget.__init__(self, parent, history_filename,
+ profile=profile,
+ initial_message=initial_message)
+ TracebackLinksMixin.__init__(self)
+ GetHelpMixin.__init__(self)
+
+ # Local shortcuts
+ self.shortcuts = self.create_shortcuts()
+
+ def create_shortcuts(self):
+ array_inline = config_shortcut(lambda: self.enter_array_inline(),
+ context='array_builder',
+ name='enter array inline', parent=self)
+ array_table = config_shortcut(lambda: self.enter_array_table(),
+ context='array_builder',
+ name='enter array table', parent=self)
+ inspectsc = config_shortcut(self.inspect_current_object,
+ context='Console',
+ name='Inspect current object',
+ parent=self)
+ return [inspectsc, array_inline, array_table]
+
+ def get_shortcut_data(self):
+ """
+ Returns shortcut data, a list of tuples (shortcut, text, default)
+ shortcut (QShortcut or QAction instance)
+ text (string): action/shortcut description
+ default (string): default key sequence
+ """
+ return [sc.data for sc in self.shortcuts]
+
+ #------ Context menu
+ def setup_context_menu(self):
+ """Reimplements ShellBaseWidget method"""
+ ShellBaseWidget.setup_context_menu(self)
+ self.copy_without_prompts_action = create_action(self,
+ _("Copy without prompts"),
+ icon=ima.icon('copywop'),
+ triggered=self.copy_without_prompts)
+ clear_line_action = create_action(self, _("Clear line"),
+ QKeySequence(get_shortcut('console',
+ 'Clear line')),
+ icon=ima.icon('editdelete'),
+ tip=_("Clear line"),
+ triggered=self.clear_line)
+ clear_action = create_action(self, _("Clear shell"),
+ QKeySequence(get_shortcut('console',
+ 'Clear shell')),
+ icon=ima.icon('editclear'),
+ tip=_("Clear shell contents "
+ "('cls' command)"),
+ triggered=self.clear_terminal)
+ add_actions(self.menu, (self.copy_without_prompts_action,
+ clear_line_action, clear_action))
+
+ def contextMenuEvent(self, event):
+ """Reimplements ShellBaseWidget method"""
+ state = self.has_selected_text()
+ self.copy_without_prompts_action.setEnabled(state)
+ ShellBaseWidget.contextMenuEvent(self, event)
+
+ @Slot()
+ def copy_without_prompts(self):
+ """Copy text to clipboard without prompts"""
+ text = self.get_selected_text()
+ lines = text.split(os.linesep)
+ for index, line in enumerate(lines):
+ if line.startswith('>>> ') or line.startswith('... '):
+ lines[index] = line[4:]
+ text = os.linesep.join(lines)
+ QApplication.clipboard().setText(text)
+
+
+ #------ Key handlers
+ def postprocess_keyevent(self, event):
+ """Process keypress event"""
+ ShellBaseWidget.postprocess_keyevent(self, event)
+ if QToolTip.isVisible():
+ _event, _text, key, _ctrl, _shift = restore_keyevent(event)
+ self.hide_tooltip_if_necessary(key)
+
+ def _key_other(self, text):
+ """1 character key"""
+ if self.is_completion_widget_visible():
+ self.completion_text += text
+
+ def _key_backspace(self, cursor_position):
+ """Action for Backspace key"""
+ if self.has_selected_text():
+ self.check_selection()
+ self.remove_selected_text()
+ elif self.current_prompt_pos == cursor_position:
+ # Avoid deleting prompt
+ return
+ elif self.is_cursor_on_last_line():
+ self.stdkey_backspace()
+ if self.is_completion_widget_visible():
+ # Removing only last character because if there was a selection
+ # the completion widget would have been canceled
+ self.completion_text = self.completion_text[:-1]
+
+ def _key_tab(self):
+ """Action for TAB key"""
+ if self.is_cursor_on_last_line():
+ empty_line = not self.get_current_line_to_cursor().strip()
+ if empty_line:
+ self.stdkey_tab()
+ else:
+ self.show_code_completion()
+
+ def _key_ctrl_space(self):
+ """Action for Ctrl+Space"""
+ if not self.is_completion_widget_visible():
+ self.show_code_completion()
+
+ def _key_pageup(self):
+ """Action for PageUp key"""
+ pass
+
+ def _key_pagedown(self):
+ """Action for PageDown key"""
+ pass
+
+ def _key_escape(self):
+ """Action for ESCAPE key"""
+ if self.is_completion_widget_visible():
+ self.hide_completion_widget()
+
+ def _key_question(self, text):
+ """Action for '?'"""
+ if self.get_current_line_to_cursor():
+ last_obj = self.get_last_obj()
+ if last_obj and not last_obj.isdigit():
+ self.show_object_info(last_obj)
+ self.insert_text(text)
+ # In case calltip and completion are shown at the same time:
+ if self.is_completion_widget_visible():
+ self.completion_text += '?'
+
+ def _key_parenleft(self, text):
+ """Action for '('"""
+ self.hide_completion_widget()
+ if self.get_current_line_to_cursor():
+ last_obj = self.get_last_obj()
+ if last_obj and not last_obj.isdigit():
+ self.insert_text(text)
+ self.show_object_info(last_obj, call=True)
+ return
+ self.insert_text(text)
+
+ def _key_period(self, text):
+ """Action for '.'"""
+ self.insert_text(text)
+ if self.codecompletion_auto:
+ # Enable auto-completion only if last token isn't a float
+ last_obj = self.get_last_obj()
+ if last_obj and not last_obj.isdigit():
+ self.show_code_completion()
+
+
+ #------ Paste
+ def paste(self):
+ """Reimplemented slot to handle multiline paste action"""
+ text = to_text_string(QApplication.clipboard().text())
+ if len(text.splitlines()) > 1:
+ # Multiline paste
+ if self.new_input_line:
+ self.on_new_line()
+ self.remove_selected_text() # Remove selection, eventually
+ end = self.get_current_line_from_cursor()
+ lines = self.get_current_line_to_cursor() + text + end
+ self.clear_line()
+ self.execute_lines(lines)
+ self.move_cursor(-len(end))
+ else:
+ # Standard paste
+ ShellBaseWidget.paste(self)
+
+ # ------ Code Completion / Calltips
+ # Methods implemented in child class:
+ # (e.g. InternalShell)
+ def get_dir(self, objtxt):
+ """Return dir(object)"""
+ raise NotImplementedError
+ def get_globals_keys(self):
+ """Return shell globals() keys"""
+ raise NotImplementedError
+ def get_cdlistdir(self):
+ """Return shell current directory list dir"""
+ raise NotImplementedError
+ def iscallable(self, objtxt):
+ """Is object callable?"""
+ raise NotImplementedError
+ def get_arglist(self, objtxt):
+ """Get func/method argument list"""
+ raise NotImplementedError
+ def get__doc__(self, objtxt):
+ """Get object __doc__"""
+ raise NotImplementedError
+ def get_doc(self, objtxt):
+ """Get object documentation dictionary"""
+ raise NotImplementedError
+ def get_source(self, objtxt):
+ """Get object source"""
+ raise NotImplementedError
+ def is_defined(self, objtxt, force_import=False):
+ """Return True if object is defined"""
+ raise NotImplementedError
+
+ def show_completion_widget(self, textlist):
+ """Show completion widget"""
+ self.completion_widget.show_list(textlist, position=None)
+
+ def hide_completion_widget(self):
+ """Hide completion widget"""
+ self.completion_widget.hide()
+
+ def show_completion_list(self, completions, completion_text=""):
+ """Display the possible completions"""
+ if not completions:
+ return
+ if not isinstance(completions[0], tuple):
+ completions = [(c, '') for c in completions]
+ if len(completions) == 1 and completions[0][0] == completion_text:
+ return
+ self.completion_text = completion_text
+ # Sorting completion list (entries starting with underscore are
+ # put at the end of the list):
+ underscore = set([(comp, t) for (comp, t) in completions
+ if comp.startswith('_')])
+
+ completions = sorted(set(completions) - underscore,
+ key=lambda x: str_lower(x[0]))
+ completions += sorted(underscore, key=lambda x: str_lower(x[0]))
+ self.show_completion_widget(completions)
+
+ def show_code_completion(self):
+ """Display a completion list based on the current line"""
+ # Note: unicode conversion is needed only for ExternalShellBase
+ text = to_text_string(self.get_current_line_to_cursor())
+ last_obj = self.get_last_obj()
+ if not text:
+ return
+
+ obj_dir = self.get_dir(last_obj)
+ if last_obj and obj_dir and text.endswith('.'):
+ self.show_completion_list(obj_dir)
+ return
+
+ # Builtins and globals
+ if not text.endswith('.') and last_obj \
+ and re.match(r'[a-zA-Z_0-9]*$', last_obj):
+ b_k_g = dir(builtins)+self.get_globals_keys()+keyword.kwlist
+ for objname in b_k_g:
+ if objname.startswith(last_obj) and objname != last_obj:
+ self.show_completion_list(b_k_g, completion_text=last_obj)
+ return
+ else:
+ return
+
+ # Looking for an incomplete completion
+ if last_obj is None:
+ last_obj = text
+ dot_pos = last_obj.rfind('.')
+ if dot_pos != -1:
+ if dot_pos == len(last_obj)-1:
+ completion_text = ""
+ else:
+ completion_text = last_obj[dot_pos+1:]
+ last_obj = last_obj[:dot_pos]
+ completions = self.get_dir(last_obj)
+ if completions is not None:
+ self.show_completion_list(completions,
+ completion_text=completion_text)
+ return
+
+ # Looking for ' or ": filename completion
+ q_pos = max([text.rfind("'"), text.rfind('"')])
+ if q_pos != -1:
+ completions = self.get_cdlistdir()
+ if completions:
+ self.show_completion_list(completions,
+ completion_text=text[q_pos+1:])
+ return
+
+ def document_did_change(self, text=None):
+ """
+ This is here to be compatible with CodeEditor and be able to use
+ code completion.
+ """
+ pass
+
+ #------ Drag'n Drop
+ def drop_pathlist(self, pathlist):
+ """Drop path list"""
+ if pathlist:
+ files = ["r'%s'" % path for path in pathlist]
+ if len(files) == 1:
+ text = files[0]
+ else:
+ text = "[" + ", ".join(files) + "]"
+ if self.new_input_line:
+ self.on_new_line()
+ self.insert_text(text)
+ self.setFocus()
+
+
+class TerminalWidget(ShellBaseWidget):
+ """
+ Terminal widget
+ """
+ COM = 'rem' if os.name == 'nt' else '#'
+ INITHISTORY = ['%s *** Spyder Terminal History Log ***' % COM, COM,]
+ SEPARATOR = '%s%s ---(%s)---' % (os.linesep*2, COM, time.ctime())
+ go_to_error = Signal(str)
+
+ def __init__(self, parent, history_filename, profile=False):
+ ShellBaseWidget.__init__(self, parent, history_filename, profile)
+
+ #------ Key handlers
+ def _key_other(self, text):
+ """1 character key"""
+ pass
+
+ def _key_backspace(self, cursor_position):
+ """Action for Backspace key"""
+ if self.has_selected_text():
+ self.check_selection()
+ self.remove_selected_text()
+ elif self.current_prompt_pos == cursor_position:
+ # Avoid deleting prompt
+ return
+ elif self.is_cursor_on_last_line():
+ self.stdkey_backspace()
+
+ def _key_tab(self):
+ """Action for TAB key"""
+ if self.is_cursor_on_last_line():
+ self.stdkey_tab()
+
+ def _key_ctrl_space(self):
+ """Action for Ctrl+Space"""
+ pass
+
+ def _key_escape(self):
+ """Action for ESCAPE key"""
+ self.clear_line()
+
+ def _key_question(self, text):
+ """Action for '?'"""
+ self.insert_text(text)
+
+ def _key_parenleft(self, text):
+ """Action for '('"""
+ self.insert_text(text)
+
+ def _key_period(self, text):
+ """Action for '.'"""
+ self.insert_text(text)
+
+
+ #------ Drag'n Drop
+ def drop_pathlist(self, pathlist):
+ """Drop path list"""
+ if pathlist:
+ files = ['"%s"' % path for path in pathlist]
+ if len(files) == 1:
+ text = files[0]
+ else:
+ text = " ".join(files)
+ if self.new_input_line:
+ self.on_new_line()
+ self.insert_text(text)
+ self.setFocus()
diff --git a/spyder/plugins/editor.py b/spyder/plugins/editor.py
deleted file mode 100644
index 0d82371afdb..00000000000
--- a/spyder/plugins/editor.py
+++ /dev/null
@@ -1,2920 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright © Spyder Project Contributors
-# Licensed under the terms of the MIT License
-# (see spyder/__init__.py for details)
-
-"""Editor Plugin"""
-
-# pylint: disable=C0103
-# pylint: disable=R0903
-# pylint: disable=R0911
-# pylint: disable=R0201
-
-# Standard library imports
-import os
-import os.path as osp
-import re
-import time
-
-# Third party imports
-from qtpy import API
-from qtpy.compat import from_qvariant, getopenfilenames, to_qvariant
-from qtpy.QtCore import QByteArray, Qt, Signal, Slot
-from qtpy.QtGui import QKeySequence
-from qtpy.QtPrintSupport import QAbstractPrintDialog, QPrintDialog, QPrinter
-from qtpy.QtWidgets import (QAction, QActionGroup, QApplication, QDialog,
- QFileDialog, QGridLayout, QGroupBox, QHBoxLayout,
- QInputDialog, QLabel, QMenu, QSplitter, QTabWidget,
- QToolBar, QVBoxLayout, QWidget)
-
-# Local imports
-from spyder import dependencies
-from spyder.config.base import (_, debug_print, get_conf_path,
- running_under_pytest)
-from spyder.config.main import (CONF, RUN_CELL_SHORTCUT,
- RUN_CELL_AND_ADVANCE_SHORTCUT)
-from spyder.config.utils import (get_edit_filetypes, get_edit_filters,
- get_filter)
-from spyder.py3compat import PY2, qbytearray_to_str, to_text_string
-from spyder.utils import codeanalysis, encoding, programs, sourcecode
-from spyder.utils import icon_manager as ima
-from spyder.utils.introspection.manager import IntrospectionManager
-from spyder.utils.qthelpers import create_action, add_actions, MENU_SEPARATOR
-from spyder.utils.misc import getcwd_or_home
-from spyder.widgets.findreplace import FindReplace
-from spyder.widgets.editor import (EditorMainWindow, EditorSplitter,
- EditorStack, Printer)
-from spyder.widgets.sourcecode.codeeditor import CodeEditor
-from spyder.widgets.status import (CursorPositionStatus, EncodingStatus,
- EOLStatus, ReadWriteStatus)
-from spyder.api.plugins import SpyderPluginWidget
-from spyder.api.preferences import PluginConfigPage
-from spyder.plugins.runconfig import (ALWAYS_OPEN_FIRST_RUN_OPTION,
- get_run_configuration,
- RunConfigDialog, RunConfigOneDialog)
-
-
-# Dependencies
-NBCONVERT_REQVER = ">=4.0"
-dependencies.add("nbconvert", _("Manipulate Jupyter notebooks on the Editor"),
- required_version=NBCONVERT_REQVER)
-
-
-def _load_all_breakpoints():
- bp_dict = CONF.get('run', 'breakpoints', {})
- for filename in list(bp_dict.keys()):
- if not osp.isfile(filename):
- bp_dict.pop(filename)
- return bp_dict
-
-
-def load_breakpoints(filename):
- breakpoints = _load_all_breakpoints().get(filename, [])
- if breakpoints and isinstance(breakpoints[0], int):
- # Old breakpoints format
- breakpoints = [(lineno, None) for lineno in breakpoints]
- return breakpoints
-
-
-def save_breakpoints(filename, breakpoints):
- if not osp.isfile(filename):
- return
- bp_dict = _load_all_breakpoints()
- bp_dict[filename] = breakpoints
- CONF.set('run', 'breakpoints', bp_dict)
-
-
-def clear_all_breakpoints():
- CONF.set('run', 'breakpoints', {})
-
-
-def clear_breakpoint(filename, lineno):
- breakpoints = load_breakpoints(filename)
- if breakpoints:
- for breakpoint in breakpoints[:]:
- if breakpoint[0] == lineno:
- breakpoints.remove(breakpoint)
- save_breakpoints(filename, breakpoints)
-
-
-WINPDB_PATH = programs.find_program('winpdb')
-
-
-class EditorConfigPage(PluginConfigPage):
- def get_name(self):
- return _("Editor")
-
- def get_icon(self):
- return ima.icon('edit')
-
- def setup_page(self):
- template_btn = self.create_button(_("Edit template for new modules"),
- self.plugin.edit_template)
-
- interface_group = QGroupBox(_("Interface"))
- newcb = self.create_checkbox
- showtabbar_box = newcb(_("Show tab bar"), 'show_tab_bar')
- showclassfuncdropdown_box = newcb(
- _("Show selector for classes and functions"),
- 'show_class_func_dropdown')
- showindentguides_box = newcb(_("Show Indent Guides"),
- 'indent_guides')
-
- interface_layout = QVBoxLayout()
- interface_layout.addWidget(showtabbar_box)
- interface_layout.addWidget(showclassfuncdropdown_box)
- interface_layout.addWidget(showindentguides_box)
- interface_group.setLayout(interface_layout)
-
- display_group = QGroupBox(_("Source code"))
- linenumbers_box = newcb(_("Show line numbers"), 'line_numbers')
- blanks_box = newcb(_("Show blank spaces"), 'blank_spaces')
- edgeline_box = newcb(_("Show vertical lines after"), 'edge_line')
- edgeline_edit = self.create_lineedit("", 'edge_line_columns',
- tip="Enter values separated by commas ','",
- alignment=Qt.Horizontal,
- regex="[0-9]+(,[0-9]+)*")
- edgeline_edit_label = QLabel(_("characters"))
- edgeline_box.toggled.connect(edgeline_edit.setEnabled)
- edgeline_box.toggled.connect(edgeline_edit_label.setEnabled)
- edgeline_edit.setEnabled(self.get_option('edge_line'))
- edgeline_edit_label.setEnabled(self.get_option('edge_line'))
-
- currentline_box = newcb(_("Highlight current line"),
- 'highlight_current_line')
- currentcell_box = newcb(_("Highlight current cell"),
- 'highlight_current_cell')
- occurrence_box = newcb(_("Highlight occurrences after"),
- 'occurrence_highlighting')
- occurrence_spin = self.create_spinbox("", _(" ms"),
- 'occurrence_highlighting/timeout',
- min_=100, max_=1000000, step=100)
- occurrence_box.toggled.connect(occurrence_spin.spinbox.setEnabled)
- occurrence_box.toggled.connect(occurrence_spin.slabel.setEnabled)
- occurrence_spin.spinbox.setEnabled(
- self.get_option('occurrence_highlighting'))
- occurrence_spin.slabel.setEnabled(
- self.get_option('occurrence_highlighting'))
-
- wrap_mode_box = newcb(_("Wrap lines"), 'wrap')
- scroll_past_end_box = newcb(_("Scroll past the end"),
- 'scroll_past_end')
-
- display_layout = QGridLayout()
- display_layout.addWidget(linenumbers_box, 0, 0)
- display_layout.addWidget(blanks_box, 1, 0)
- display_layout.addWidget(edgeline_box, 2, 0)
- display_layout.addWidget(edgeline_edit, 2, 1)
- display_layout.addWidget(edgeline_edit_label, 2, 2)
- display_layout.addWidget(currentline_box, 3, 0)
- display_layout.addWidget(currentcell_box, 4, 0)
- display_layout.addWidget(occurrence_box, 5, 0)
- display_layout.addWidget(occurrence_spin.spinbox, 5, 1)
- display_layout.addWidget(occurrence_spin.slabel, 5, 2)
- display_layout.addWidget(wrap_mode_box, 6, 0)
- display_layout.addWidget(scroll_past_end_box, 7, 0)
- display_h_layout = QHBoxLayout()
- display_h_layout.addLayout(display_layout)
- display_h_layout.addStretch(1)
- display_group.setLayout(display_h_layout)
-
- run_group = QGroupBox(_("Run"))
- saveall_box = newcb(_("Save all files before running script"),
- 'save_all_before_run')
-
- run_selection_group = QGroupBox(_("Run selection"))
- focus_box = newcb(_("Maintain focus in the Editor after running cells "
- "or selections"), 'focus_to_editor')
-
- introspection_group = QGroupBox(_("Introspection"))
- rope_is_installed = programs.is_module_installed('rope')
- if rope_is_installed:
- completion_box = newcb(_("Automatic code completion"),
- 'codecompletion/auto')
- case_comp_box = newcb(_("Case sensitive code completion"),
- 'codecompletion/case_sensitive')
- comp_enter_box = newcb(_("Enter key selects completion"),
- 'codecompletion/enter_key')
- calltips_box = newcb(_("Display balloon tips"), 'calltips')
- gotodef_box = newcb(_("Link to object definition"),
- 'go_to_definition',
- tip=_("If this option is enabled, clicking on an object\n"
- "name (left-click + Ctrl key) will go this object\n"
- "definition (if resolved)."))
- else:
- rope_label = QLabel(_("Warning:
"
- "The Python module rope is not "
- "installed on this computer: calltips, "
- "code completion and go-to-definition "
- "features won't be available."))
- rope_label.setWordWrap(True)
-
- sourcecode_group = QGroupBox(_("Source code"))
- closepar_box = newcb(_("Automatic insertion of parentheses, braces "
- "and brackets"),
- 'close_parentheses')
- close_quotes_box = newcb(_("Automatic insertion of closing quotes"),
- 'close_quotes')
- add_colons_box = newcb(_("Automatic insertion of colons after 'for', "
- "'if', 'def', etc"),
- 'add_colons')
- autounindent_box = newcb(_("Automatic indentation after 'else', "
- "'elif', etc."), 'auto_unindent')
- indent_chars_box = self.create_combobox(_("Indentation characters: "),
- ((_("2 spaces"), '* *'),
- (_("3 spaces"), '* *'),
- (_("4 spaces"), '* *'),
- (_("5 spaces"), '* *'),
- (_("6 spaces"), '* *'),
- (_("7 spaces"), '* *'),
- (_("8 spaces"), '* *'),
- (_("Tabulations"), '*\t*')), 'indent_chars')
- tabwidth_spin = self.create_spinbox(_("Tab stop width:"), _("spaces"),
- 'tab_stop_width_spaces', 4, 1, 8, 1)
- def enable_tabwidth_spin(index):
- if index == 7: # Tabulations
- tabwidth_spin.plabel.setEnabled(True)
- tabwidth_spin.spinbox.setEnabled(True)
- else:
- tabwidth_spin.plabel.setEnabled(False)
- tabwidth_spin.spinbox.setEnabled(False)
-
- indent_chars_box.combobox.currentIndexChanged.connect(enable_tabwidth_spin)
-
- tab_mode_box = newcb(_("Tab always indent"),
- 'tab_always_indent', default=False,
- tip=_("If enabled, pressing Tab will always indent,\n"
- "even when the cursor is not at the beginning\n"
- "of a line (when this option is enabled, code\n"
- "completion may be triggered using the alternate\n"
- "shortcut: Ctrl+Space)"))
- ibackspace_box = newcb(_("Intelligent backspace"),
- 'intelligent_backspace', default=True)
- removetrail_box = newcb(_("Automatically remove trailing spaces "
- "when saving files"),
- 'always_remove_trailing_spaces', default=False)
-
- analysis_group = QGroupBox(_("Analysis"))
- pep_url = 'PEP8'
- pep8_label = QLabel(_("(Refer to the {} page)").format(pep_url))
- pep8_label.setOpenExternalLinks(True)
- is_pyflakes = codeanalysis.is_pyflakes_installed()
- is_pep8 = codeanalysis.get_checker_executable(
- 'pycodestyle') is not None
- pyflakes_box = newcb(_("Real-time code analysis"),
- 'code_analysis/pyflakes', default=True,
- tip=_("If enabled, Python source code will be analyzed "
- "using pyflakes, lines containing errors or "
- "warnings will be highlighted.
"
- "Note: add analysis:ignore in "
- "a comment to ignore code analysis "
- "warnings.
"))
- pyflakes_box.setEnabled(is_pyflakes)
- if not is_pyflakes:
- pyflakes_box.setToolTip(_("Code analysis requires pyflakes %s+") %
- codeanalysis.PYFLAKES_REQVER)
- pep8_box = newcb(_("Real-time code style analysis"),
- 'code_analysis/pep8', default=False,
- tip=_("If enabled, Python source code will be analyzed "
- "using pycodestyle, lines that are not following PEP8 "
- "style guide will be highlighted.
"
- "Note: add analysis:ignore in "
- "a comment to ignore style analysis "
- "warnings.
"))
- pep8_box.setEnabled(is_pep8)
- todolist_box = newcb(_("Code annotations (TODO, FIXME, XXX, HINT, TIP,"
- " @todo, HACK, BUG, OPTIMIZE, !!!, ???)"),
- 'todo_list', default=True)
- realtime_radio = self.create_radiobutton(
- _("Perform analysis when "
- "saving file and every"),
- 'realtime_analysis', True)
- saveonly_radio = self.create_radiobutton(
- _("Perform analysis only "
- "when saving file"),
- 'onsave_analysis')
- af_spin = self.create_spinbox("", _(" ms"), 'realtime_analysis/timeout',
- min_=100, max_=1000000, step=100)
- af_layout = QHBoxLayout()
- af_layout.addWidget(realtime_radio)
- af_layout.addWidget(af_spin)
-
- run_layout = QVBoxLayout()
- run_layout.addWidget(saveall_box)
- run_group.setLayout(run_layout)
-
- run_selection_layout = QVBoxLayout()
- run_selection_layout.addWidget(focus_box)
- run_selection_group.setLayout(run_selection_layout)
-
- introspection_layout = QVBoxLayout()
- if rope_is_installed:
- introspection_layout.addWidget(calltips_box)
- introspection_layout.addWidget(completion_box)
- introspection_layout.addWidget(case_comp_box)
- introspection_layout.addWidget(comp_enter_box)
- introspection_layout.addWidget(gotodef_box)
- else:
- introspection_layout.addWidget(rope_label)
- introspection_group.setLayout(introspection_layout)
-
- analysis_layout = QVBoxLayout()
- analysis_layout.addWidget(pyflakes_box)
- analysis_pep_layout = QHBoxLayout()
- analysis_pep_layout.addWidget(pep8_box)
- analysis_pep_layout.addWidget(pep8_label)
- analysis_layout.addLayout(analysis_pep_layout)
- analysis_layout.addWidget(todolist_box)
- analysis_layout.addLayout(af_layout)
- analysis_layout.addWidget(saveonly_radio)
- analysis_group.setLayout(analysis_layout)
-
- sourcecode_layout = QVBoxLayout()
- sourcecode_layout.addWidget(closepar_box)
- sourcecode_layout.addWidget(autounindent_box)
- sourcecode_layout.addWidget(add_colons_box)
- sourcecode_layout.addWidget(close_quotes_box)
- indent_tab_layout = QHBoxLayout()
- indent_tab_grid_layout = QGridLayout()
- indent_tab_grid_layout.addWidget(indent_chars_box.label, 0, 0)
- indent_tab_grid_layout.addWidget(indent_chars_box.combobox, 0, 1)
- indent_tab_grid_layout.addWidget(tabwidth_spin.plabel, 1, 0)
- indent_tab_grid_layout.addWidget(tabwidth_spin.spinbox, 1, 1)
- indent_tab_grid_layout.addWidget(tabwidth_spin.slabel, 1, 2)
- indent_tab_layout.addLayout(indent_tab_grid_layout)
- indent_tab_layout.addStretch(1)
- sourcecode_layout.addLayout(indent_tab_layout)
- sourcecode_layout.addWidget(tab_mode_box)
- sourcecode_layout.addWidget(ibackspace_box)
- sourcecode_layout.addWidget(removetrail_box)
- sourcecode_group.setLayout(sourcecode_layout)
-
- eol_group = QGroupBox(_("End-of-line characters"))
- eol_label = QLabel(_("When opening a text file containing "
- "mixed end-of-line characters (this may "
- "raise syntax errors in the consoles "
- "on Windows platforms), Spyder may fix the "
- "file automatically."))
- eol_label.setWordWrap(True)
- check_eol_box = newcb(_("Fix automatically and show warning "
- "message box"),
- 'check_eol_chars', default=True)
- convert_eol_on_save_box = newcb(_("On Save: convert EOL characters"
- " to"),
- 'convert_eol_on_save', default=False)
- eol_combo_choices = ((_("LF (UNIX)"), 'LF'),
- (_("CRLF (Windows)"), 'CRLF'),
- (_("CR (Mac)"), 'CR'),
- )
- convert_eol_on_save_combo = self.create_combobox("",
- eol_combo_choices,
- 'convert_eol_on_save_to',
- )
- convert_eol_on_save_box.toggled.connect(convert_eol_on_save_combo.setEnabled)
- convert_eol_on_save_combo.setEnabled(
- self.get_option('convert_eol_on_save'))
-
- eol_on_save_layout = QHBoxLayout()
- eol_on_save_layout.addWidget(convert_eol_on_save_box)
- eol_on_save_layout.addWidget(convert_eol_on_save_combo)
-
- eol_layout = QVBoxLayout()
- eol_layout.addWidget(eol_label)
- eol_layout.addWidget(check_eol_box)
- eol_layout.addLayout(eol_on_save_layout)
- eol_group.setLayout(eol_layout)
-
- tabs = QTabWidget()
- tabs.addTab(self.create_tab(interface_group, display_group),
- _("Display"))
- tabs.addTab(self.create_tab(introspection_group, analysis_group),
- _("Code Introspection/Analysis"))
- tabs.addTab(self.create_tab(template_btn, run_group, run_selection_group,
- sourcecode_group, eol_group),
- _("Advanced settings"))
-
- vlayout = QVBoxLayout()
- vlayout.addWidget(tabs)
- self.setLayout(vlayout)
-
-
-class Editor(SpyderPluginWidget):
- """
- Multi-file Editor widget
- """
- CONF_SECTION = 'editor'
- CONFIGWIDGET_CLASS = EditorConfigPage
- TEMPFILE_PATH = get_conf_path('temp.py')
- TEMPLATE_PATH = get_conf_path('template.py')
- DISABLE_ACTIONS_WHEN_HIDDEN = False # SpyderPluginWidget class attribute
-
- # Signals
- run_in_current_ipyclient = Signal(str, str, str, bool, bool, bool, bool)
- exec_in_extconsole = Signal(str, bool)
- redirect_stdio = Signal(bool)
- open_dir = Signal(str)
- breakpoints_saved = Signal()
- run_in_current_extconsole = Signal(str, str, str, bool, bool)
- open_file_update = Signal(str)
-
- def __init__(self, parent, ignore_last_opened_files=False):
- SpyderPluginWidget.__init__(self, parent)
-
- self.__set_eol_chars = True
-
- # Creating template if it doesn't already exist
- if not osp.isfile(self.TEMPLATE_PATH):
- if os.name == "nt":
- shebang = []
- else:
- shebang = ['#!/usr/bin/env python' + ('2' if PY2 else '3')]
- header = shebang + [
- '# -*- coding: utf-8 -*-',
- '"""', 'Created on %(date)s', '',
- '@author: %(username)s', '"""', '', '']
- encoding.write(os.linesep.join(header), self.TEMPLATE_PATH, 'utf-8')
-
- self.projects = None
- self.outlineexplorer = None
- self.help = None
-
- self.editorstacks = None
- self.editorwindows = None
- self.editorwindows_to_be_created = None
-
- self.file_dependent_actions = []
- self.pythonfile_dependent_actions = []
- self.dock_toolbar_actions = None
- self.edit_menu_actions = None #XXX: find another way to notify Spyder
- # (see spyder.py: 'update_edit_menu' method)
- self.search_menu_actions = None #XXX: same thing ('update_search_menu')
- self.stack_menu_actions = None
- self.checkable_actions = {}
-
- # Initialize plugin
- self.initialize_plugin()
- self.options_button.hide()
-
- # Configuration dialog size
- self.dialog_size = None
-
- statusbar = self.main.statusBar()
- self.readwrite_status = ReadWriteStatus(self, statusbar)
- self.eol_status = EOLStatus(self, statusbar)
- self.encoding_status = EncodingStatus(self, statusbar)
- self.cursorpos_status = CursorPositionStatus(self, statusbar)
-
- layout = QVBoxLayout()
- self.dock_toolbar = QToolBar(self)
- add_actions(self.dock_toolbar, self.dock_toolbar_actions)
- layout.addWidget(self.dock_toolbar)
-
- self.last_edit_cursor_pos = None
- self.cursor_pos_history = []
- self.cursor_pos_index = None
- self.__ignore_cursor_position = True
-
- self.editorstacks = []
- self.last_focus_editorstack = {}
- self.editorwindows = []
- self.editorwindows_to_be_created = []
- self.toolbar_list = None
- self.menu_list = None
-
- # Don't start IntrospectionManager when running tests because
- # it consumes a lot of memory
- if (running_under_pytest()
- and not os.environ.get('SPY_TEST_USE_INTROSPECTION')):
- try:
- from unittest.mock import Mock
- except ImportError:
- from mock import Mock # Python 2
- self.introspector = Mock()
- else:
- self.introspector = IntrospectionManager(
- extra_path=self.main.get_spyder_pythonpath())
-
- # Setup new windows:
- self.main.all_actions_defined.connect(self.setup_other_windows)
-
- # Change module completions when PYTHONPATH changes
- self.main.sig_pythonpath_changed.connect(self.set_path)
-
- # Find widget
- self.find_widget = FindReplace(self, enable_replace=True)
- self.find_widget.hide()
- self.find_widget.visibility_changed.connect(
- lambda vs: self.rehighlight_cells())
- self.register_widget_shortcuts(self.find_widget)
-
- # Tabbed editor widget + Find/Replace widget
- editor_widgets = QWidget(self)
- editor_layout = QVBoxLayout()
- editor_layout.setContentsMargins(0, 0, 0, 0)
- editor_widgets.setLayout(editor_layout)
- self.editorsplitter = EditorSplitter(self, self,
- self.stack_menu_actions, first=True)
- editor_layout.addWidget(self.editorsplitter)
- editor_layout.addWidget(self.find_widget)
-
- # Splitter: editor widgets (see above) + outline explorer
- self.splitter = QSplitter(self)
- self.splitter.setContentsMargins(0, 0, 0, 0)
- self.splitter.addWidget(editor_widgets)
- self.splitter.setStretchFactor(0, 5)
- self.splitter.setStretchFactor(1, 1)
- layout.addWidget(self.splitter)
- self.setLayout(layout)
- self.setFocusPolicy(Qt.ClickFocus)
-
- # Editor's splitter state
- state = self.get_option('splitter_state', None)
- if state is not None:
- self.splitter.restoreState( QByteArray().fromHex(
- str(state).encode('utf-8')) )
-
- self.recent_files = self.get_option('recent_files', [])
- self.untitled_num = 0
-
- # Parameters of last file execution:
- self.__last_ic_exec = None # internal console
- self.__last_ec_exec = None # external console
-
- # File types and filters used by the Open dialog
- self.edit_filetypes = None
- self.edit_filters = None
-
- self.__ignore_cursor_position = False
- current_editor = self.get_current_editor()
- if current_editor is not None:
- filename = self.get_current_filename()
- position = current_editor.get_position('cursor')
- self.add_cursor_position_to_history(filename, position)
- self.update_cursorpos_actions()
- self.set_path()
-
- def set_projects(self, projects):
- self.projects = projects
-
- @Slot()
- def show_hide_projects(self):
- if self.projects is not None:
- dw = self.projects.dockwidget
- if dw.isVisible():
- dw.hide()
- else:
- dw.show()
- dw.raise_()
- self.switch_to_plugin()
-
- def set_outlineexplorer(self, outlineexplorer):
- self.outlineexplorer = outlineexplorer
- for editorstack in self.editorstacks:
- # Pass the OutlineExplorer widget to the stacks because they
- # don't need the plugin
- editorstack.set_outlineexplorer(self.outlineexplorer.explorer)
- self.editorstacks[0].initialize_outlineexplorer()
- self.outlineexplorer.explorer.edit_goto.connect(
- lambda filenames, goto, word:
- self.load(filenames=filenames, goto=goto, word=word,
- editorwindow=self))
- self.outlineexplorer.explorer.edit.connect(
- lambda filenames:
- self.load(filenames=filenames, editorwindow=self))
-
- def set_help(self, help_plugin):
- self.help = help_plugin
- for editorstack in self.editorstacks:
- editorstack.set_help(self.help)
-
- #------ Private API --------------------------------------------------------
- def restore_scrollbar_position(self):
- """Restoring scrollbar position after main window is visible"""
- # Widget is now visible, we may center cursor on top level editor:
- try:
- self.get_current_editor().centerCursor()
- except AttributeError:
- pass
-
- #------ SpyderPluginWidget API ---------------------------------------------
- def get_plugin_title(self):
- """Return widget title"""
- title = _('Editor')
- if self.dockwidget:
- filename = self.get_current_filename()
- if self.dockwidget.dock_tabbar:
- if filename and self.dockwidget.dock_tabbar.count() < 2:
- title += ' - ' + to_text_string(filename)
- else:
- title += ' - ' + to_text_string(filename)
- return title
-
- def get_plugin_icon(self):
- """Return widget icon."""
- return ima.icon('edit')
-
- def get_focus_widget(self):
- """
- Return the widget to give focus to.
-
- This happens when plugin's dockwidget is raised on top-level.
- """
- return self.get_current_editor()
-
- def visibility_changed(self, enable):
- """DockWidget visibility has changed"""
- SpyderPluginWidget.visibility_changed(self, enable)
- if self.dockwidget.isWindow():
- self.dock_toolbar.show()
- else:
- self.dock_toolbar.hide()
- if enable:
- self.refresh_plugin()
- self.sig_update_plugin_title.emit()
-
- def refresh_plugin(self):
- """Refresh editor plugin"""
- editorstack = self.get_current_editorstack()
- editorstack.refresh()
- self.refresh_save_all_action()
-
- def closing_plugin(self, cancelable=False):
- """Perform actions before parent main window is closed"""
- state = self.splitter.saveState()
- self.set_option('splitter_state', qbytearray_to_str(state))
- filenames = []
- editorstack = self.editorstacks[0]
-
- active_project_path = None
- if self.projects is not None:
- active_project_path = self.projects.get_active_project_path()
- if not active_project_path:
- self.set_open_filenames()
- else:
- self.projects.set_project_filenames(
- [finfo.filename for finfo in editorstack.data])
-
- self.set_option('layout_settings',
- self.editorsplitter.get_layout_settings())
- self.set_option('windows_layout_settings',
- [win.get_layout_settings() for win in self.editorwindows])
-# self.set_option('filenames', filenames)
- self.set_option('recent_files', self.recent_files)
- try:
- if not editorstack.save_if_changed(cancelable) and cancelable:
- return False
- else:
- for win in self.editorwindows[:]:
- win.close()
- return True
- except IndexError:
- return True
-
- def get_plugin_actions(self):
- """Return a list of actions related to plugin"""
- # ---- File menu and toolbar ----
- self.new_action = create_action(
- self,
- _("&New file..."),
- icon=ima.icon('filenew'), tip=_("New file"),
- triggered=self.new,
- context=Qt.WidgetShortcut
- )
- self.register_shortcut(self.new_action, context="Editor",
- name="New file", add_sc_to_tip=True)
-
- self.open_last_closed_action = create_action(
- self,
- _("O&pen last closed"),
- tip=_("Open last closed"),
- triggered=self.open_last_closed
- )
- self.register_shortcut(self.open_last_closed_action, context="Editor",
- name="Open last closed")
-
- self.open_action = create_action(self, _("&Open..."),
- icon=ima.icon('fileopen'), tip=_("Open file"),
- triggered=self.load,
- context=Qt.WidgetShortcut)
- self.register_shortcut(self.open_action, context="Editor",
- name="Open file", add_sc_to_tip=True)
-
- self.revert_action = create_action(self, _("&Revert"),
- icon=ima.icon('revert'), tip=_("Revert file from disk"),
- triggered=self.revert)
-
- self.save_action = create_action(self, _("&Save"),
- icon=ima.icon('filesave'), tip=_("Save file"),
- triggered=self.save,
- context=Qt.WidgetShortcut)
- self.register_shortcut(self.save_action, context="Editor",
- name="Save file", add_sc_to_tip=True)
-
- self.save_all_action = create_action(self, _("Sav&e all"),
- icon=ima.icon('save_all'), tip=_("Save all files"),
- triggered=self.save_all,
- context=Qt.WidgetShortcut)
- self.register_shortcut(self.save_all_action, context="Editor",
- name="Save all", add_sc_to_tip=True)
-
- save_as_action = create_action(self, _("Save &as..."), None,
- ima.icon('filesaveas'), tip=_("Save current file as..."),
- triggered=self.save_as,
- context=Qt.WidgetShortcut)
- self.register_shortcut(save_as_action, "Editor", "Save As")
-
- save_copy_as_action = create_action(self, _("Save copy as..."), None,
- ima.icon('filesaveas'), _("Save copy of current file as..."),
- triggered=self.save_copy_as)
-
- print_preview_action = create_action(self, _("Print preview..."),
- tip=_("Print preview..."), triggered=self.print_preview)
- self.print_action = create_action(self, _("&Print..."),
- icon=ima.icon('print'), tip=_("Print current file..."),
- triggered=self.print_file)
- # Shortcut for close_action is defined in widgets/editor.py
- self.close_action = create_action(self, _("&Close"),
- icon=ima.icon('fileclose'), tip=_("Close current file"),
- triggered=self.close_file)
-
- self.close_all_action = create_action(self, _("C&lose all"),
- icon=ima.icon('filecloseall'), tip=_("Close all opened files"),
- triggered=self.close_all_files,
- context=Qt.WidgetShortcut)
- self.register_shortcut(self.close_all_action, context="Editor",
- name="Close all")
-
- # ---- Find menu and toolbar ----
- _text = _("&Find text")
- find_action = create_action(self, _text, icon=ima.icon('find'),
- tip=_text, triggered=self.find,
- context=Qt.WidgetShortcut)
- self.register_shortcut(find_action, context="_",
- name="Find text", add_sc_to_tip=True)
- find_next_action = create_action(self, _("Find &next"),
- icon=ima.icon('findnext'),
- triggered=self.find_next,
- context=Qt.WidgetShortcut)
- self.register_shortcut(find_next_action, context="_",
- name="Find next")
- find_previous_action = create_action(self, _("Find &previous"),
- icon=ima.icon('findprevious'),
- triggered=self.find_previous,
- context=Qt.WidgetShortcut)
- self.register_shortcut(find_previous_action, context="_",
- name="Find previous")
- _text = _("&Replace text")
- replace_action = create_action(self, _text, icon=ima.icon('replace'),
- tip=_text, triggered=self.replace,
- context=Qt.WidgetShortcut)
- self.register_shortcut(replace_action, context="_",
- name="Replace text")
-
- # ---- Debug menu and toolbar ----
- set_clear_breakpoint_action = create_action(self,
- _("Set/Clear breakpoint"),
- icon=ima.icon('breakpoint_big'),
- triggered=self.set_or_clear_breakpoint,
- context=Qt.WidgetShortcut)
- self.register_shortcut(set_clear_breakpoint_action, context="Editor",
- name="Breakpoint")
- set_cond_breakpoint_action = create_action(self,
- _("Set/Edit conditional breakpoint"),
- icon=ima.icon('breakpoint_cond_big'),
- triggered=self.set_or_edit_conditional_breakpoint,
- context=Qt.WidgetShortcut)
- self.register_shortcut(set_cond_breakpoint_action, context="Editor",
- name="Conditional breakpoint")
- clear_all_breakpoints_action = create_action(self,
- _('Clear breakpoints in all files'),
- triggered=self.clear_all_breakpoints)
- self.winpdb_action = create_action(self, _("Debug with winpdb"),
- triggered=self.run_winpdb)
- self.winpdb_action.setEnabled(WINPDB_PATH is not None and PY2)
-
- # --- Debug toolbar ---
- debug_action = create_action(self, _("&Debug"),
- icon=ima.icon('debug'),
- tip=_("Debug file"),
- triggered=self.debug_file)
- self.register_shortcut(debug_action, context="_", name="Debug",
- add_sc_to_tip=True)
-
- debug_next_action = create_action(self, _("Step"),
- icon=ima.icon('arrow-step-over'), tip=_("Run current line"),
- triggered=lambda: self.debug_command("next"))
- self.register_shortcut(debug_next_action, "_", "Debug Step Over",
- add_sc_to_tip=True)
-
- debug_continue_action = create_action(self, _("Continue"),
- icon=ima.icon('arrow-continue'),
- tip=_("Continue execution until next breakpoint"),
- triggered=lambda: self.debug_command("continue"))
- self.register_shortcut(debug_continue_action, "_", "Debug Continue",
- add_sc_to_tip=True)
-
- debug_step_action = create_action(self, _("Step Into"),
- icon=ima.icon('arrow-step-in'),
- tip=_("Step into function or method of current line"),
- triggered=lambda: self.debug_command("step"))
- self.register_shortcut(debug_step_action, "_", "Debug Step Into",
- add_sc_to_tip=True)
-
- debug_return_action = create_action(self, _("Step Return"),
- icon=ima.icon('arrow-step-out'),
- tip=_("Run until current function or method returns"),
- triggered=lambda: self.debug_command("return"))
- self.register_shortcut(debug_return_action, "_", "Debug Step Return",
- add_sc_to_tip=True)
-
- debug_exit_action = create_action(self, _("Stop"),
- icon=ima.icon('stop_debug'), tip=_("Stop debugging"),
- triggered=lambda: self.debug_command("exit"))
- self.register_shortcut(debug_exit_action, "_", "Debug Exit",
- add_sc_to_tip=True)
-
- # --- Run toolbar ---
- run_action = create_action(self, _("&Run"), icon=ima.icon('run'),
- tip=_("Run file"),
- triggered=self.run_file)
- self.register_shortcut(run_action, context="_", name="Run",
- add_sc_to_tip=True)
-
- configure_action = create_action(self, _("&Configuration per file..."),
- icon=ima.icon('run_settings'),
- tip=_("Run settings"),
- menurole=QAction.NoRole,
- triggered=self.edit_run_configurations)
- self.register_shortcut(configure_action, context="_",
- name="Configure", add_sc_to_tip=True)
-
- re_run_action = create_action(self, _("Re-run &last script"),
- icon=ima.icon('run_again'),
- tip=_("Run again last file"),
- triggered=self.re_run_file)
- self.register_shortcut(re_run_action, context="_",
- name="Re-run last script",
- add_sc_to_tip=True)
-
- run_selected_action = create_action(self, _("Run &selection or "
- "current line"),
- icon=ima.icon('run_selection'),
- tip=_("Run selection or "
- "current line"),
- triggered=self.run_selection,
- context=Qt.WidgetShortcut)
- self.register_shortcut(run_selected_action, context="Editor",
- name="Run selection", add_sc_to_tip=True)
-
- run_cell_action = create_action(self,
- _("Run cell"),
- icon=ima.icon('run_cell'),
- shortcut=QKeySequence(RUN_CELL_SHORTCUT),
- tip=_("Run current cell (Ctrl+Enter)\n"
- "[Use #%% to create cells]"),
- triggered=self.run_cell,
- context=Qt.WidgetShortcut)
-
- run_cell_advance_action = create_action(self,
- _("Run cell and advance"),
- icon=ima.icon('run_cell_advance'),
- shortcut=QKeySequence(RUN_CELL_AND_ADVANCE_SHORTCUT),
- tip=_("Run current cell and go to the next one "
- "(Shift+Enter)"),
- triggered=self.run_cell_and_advance,
- context=Qt.WidgetShortcut)
-
- re_run_last_cell_action = create_action(self,
- _("Re-run last cell"),
- tip=_("Re run last cell "),
- triggered=self.re_run_last_cell,
- context=Qt.WidgetShortcut)
- self.register_shortcut(re_run_last_cell_action,
- context="Editor",
- name='re-run last cell',
- add_sc_to_tip=True)
-
- # --- Source code Toolbar ---
- self.todo_list_action = create_action(self,
- _("Show todo list"), icon=ima.icon('todo_list'),
- tip=_("Show comments list (TODO/FIXME/XXX/HINT/TIP/@todo/"
- "HACK/BUG/OPTIMIZE/!!!/???)"),
- triggered=self.go_to_next_todo)
- self.todo_menu = QMenu(self)
- self.todo_list_action.setMenu(self.todo_menu)
- self.todo_menu.aboutToShow.connect(self.update_todo_menu)
-
- self.warning_list_action = create_action(self,
- _("Show warning/error list"), icon=ima.icon('wng_list'),
- tip=_("Show code analysis warnings/errors"),
- triggered=self.go_to_next_warning)
- self.warning_menu = QMenu(self)
- self.warning_list_action.setMenu(self.warning_menu)
- self.warning_menu.aboutToShow.connect(self.update_warning_menu)
- self.previous_warning_action = create_action(self,
- _("Previous warning/error"), icon=ima.icon('prev_wng'),
- tip=_("Go to previous code analysis warning/error"),
- triggered=self.go_to_previous_warning,
- context=Qt.WidgetShortcut)
- self.register_shortcut(self.previous_warning_action,
- context="Editor",
- name="Previous warning",
- add_sc_to_tip=True)
- self.next_warning_action = create_action(self,
- _("Next warning/error"), icon=ima.icon('next_wng'),
- tip=_("Go to next code analysis warning/error"),
- triggered=self.go_to_next_warning,
- context=Qt.WidgetShortcut)
- self.register_shortcut(self.next_warning_action,
- context="Editor",
- name="Next warning",
- add_sc_to_tip=True)
-
- self.previous_edit_cursor_action = create_action(self,
- _("Last edit location"), icon=ima.icon('last_edit_location'),
- tip=_("Go to last edit location"),
- triggered=self.go_to_last_edit_location,
- context=Qt.WidgetShortcut)
- self.register_shortcut(self.previous_edit_cursor_action,
- context="Editor",
- name="Last edit location",
- add_sc_to_tip=True)
- self.previous_cursor_action = create_action(self,
- _("Previous cursor position"), icon=ima.icon('prev_cursor'),
- tip=_("Go to previous cursor position"),
- triggered=self.go_to_previous_cursor_position,
- context=Qt.WidgetShortcut)
- self.register_shortcut(self.previous_cursor_action,
- context="Editor",
- name="Previous cursor position",
- add_sc_to_tip=True)
- self.next_cursor_action = create_action(self,
- _("Next cursor position"), icon=ima.icon('next_cursor'),
- tip=_("Go to next cursor position"),
- triggered=self.go_to_next_cursor_position,
- context=Qt.WidgetShortcut)
- self.register_shortcut(self.next_cursor_action,
- context="Editor",
- name="Next cursor position",
- add_sc_to_tip=True)
-
- # --- Edit Toolbar ---
- self.toggle_comment_action = create_action(self,
- _("Comment")+"/"+_("Uncomment"), icon=ima.icon('comment'),
- tip=_("Comment current line or selection"),
- triggered=self.toggle_comment, context=Qt.WidgetShortcut)
- self.register_shortcut(self.toggle_comment_action, context="Editor",
- name="Toggle comment")
- blockcomment_action = create_action(self, _("Add &block comment"),
- tip=_("Add block comment around "
- "current line or selection"),
- triggered=self.blockcomment, context=Qt.WidgetShortcut)
- self.register_shortcut(blockcomment_action, context="Editor",
- name="Blockcomment")
- unblockcomment_action = create_action(self,
- _("R&emove block comment"),
- tip = _("Remove comment block around "
- "current line or selection"),
- triggered=self.unblockcomment, context=Qt.WidgetShortcut)
- self.register_shortcut(unblockcomment_action, context="Editor",
- name="Unblockcomment")
-
- # ----------------------------------------------------------------------
- # The following action shortcuts are hard-coded in CodeEditor
- # keyPressEvent handler (the shortcut is here only to inform user):
- # (context=Qt.WidgetShortcut -> disable shortcut for other widgets)
- self.indent_action = create_action(self,
- _("Indent"), "Tab", icon=ima.icon('indent'),
- tip=_("Indent current line or selection"),
- triggered=self.indent, context=Qt.WidgetShortcut)
- self.unindent_action = create_action(self,
- _("Unindent"), "Shift+Tab", icon=ima.icon('unindent'),
- tip=_("Unindent current line or selection"),
- triggered=self.unindent, context=Qt.WidgetShortcut)
-
- self.text_uppercase_action = create_action(self,
- _("Toggle Uppercase"),
- tip=_("Change to uppercase current line or selection"),
- triggered=self.text_uppercase, context=Qt.WidgetShortcut)
- self.register_shortcut(self.text_uppercase_action, context="Editor",
- name="transform to uppercase")
-
- self.text_lowercase_action = create_action(self,
- _("Toggle Lowercase"),
- tip=_("Change to lowercase current line or selection"),
- triggered=self.text_lowercase, context=Qt.WidgetShortcut)
- self.register_shortcut(self.text_lowercase_action, context="Editor",
- name="transform to lowercase")
- # ----------------------------------------------------------------------
-
- self.win_eol_action = create_action(self,
- _("Carriage return and line feed (Windows)"),
- toggled=lambda checked: self.toggle_eol_chars('nt', checked))
- self.linux_eol_action = create_action(self,
- _("Line feed (UNIX)"),
- toggled=lambda checked: self.toggle_eol_chars('posix', checked))
- self.mac_eol_action = create_action(self,
- _("Carriage return (Mac)"),
- toggled=lambda checked: self.toggle_eol_chars('mac', checked))
- eol_action_group = QActionGroup(self)
- eol_actions = (self.win_eol_action, self.linux_eol_action,
- self.mac_eol_action)
- add_actions(eol_action_group, eol_actions)
- eol_menu = QMenu(_("Convert end-of-line characters"), self)
- add_actions(eol_menu, eol_actions)
-
- trailingspaces_action = create_action(self,
- _("Remove trailing spaces"),
- triggered=self.remove_trailing_spaces)
-
- # Checkable actions
- showblanks_action = self._create_checkable_action(
- _("Show blank spaces"), 'blank_spaces', 'set_blanks_enabled')
-
- scrollpastend_action = self._create_checkable_action(
- _("Scroll past the end"), 'scroll_past_end',
- 'set_scrollpastend_enabled')
-
- showindentguides_action = self._create_checkable_action(
- _("Show indent guides."), 'indent_guides', 'set_indent_guides')
-
- show_classfunc_dropdown_action = self._create_checkable_action(
- _("Show selector for classes and functions."),
- 'show_class_func_dropdown', 'set_classfunc_dropdown_visible')
-
- showcode_analysis_pep8_action = self._create_checkable_action(
- _("Show code style warnings (pep8)"),
- 'code_analysis/pep8', 'set_pep8_enabled')
-
- self.checkable_actions = {
- 'blank_spaces': showblanks_action,
- 'scroll_past_end': scrollpastend_action,
- 'indent_guides': showindentguides_action,
- 'show_class_func_dropdown': show_classfunc_dropdown_action,
- 'code_analysis/pep8': showcode_analysis_pep8_action}
-
- fixindentation_action = create_action(self, _("Fix indentation"),
- tip=_("Replace tab characters by space characters"),
- triggered=self.fix_indentation)
-
- gotoline_action = create_action(self, _("Go to line..."),
- icon=ima.icon('gotoline'),
- triggered=self.go_to_line,
- context=Qt.WidgetShortcut)
- self.register_shortcut(gotoline_action, context="Editor",
- name="Go to line")
-
- workdir_action = create_action(self,
- _("Set console working directory"),
- icon=ima.icon('DirOpenIcon'),
- tip=_("Set current console (and file explorer) working "
- "directory to current script directory"),
- triggered=self.__set_workdir)
-
- self.max_recent_action = create_action(self,
- _("Maximum number of recent files..."),
- triggered=self.change_max_recent_files)
- self.clear_recent_action = create_action(self,
- _("Clear this list"), tip=_("Clear recent files list"),
- triggered=self.clear_recent_files)
-
- # ---- File menu/toolbar construction ----
- self.recent_file_menu = QMenu(_("Open &recent"), self)
- self.recent_file_menu.aboutToShow.connect(self.update_recent_file_menu)
-
- file_menu_actions = [self.new_action,
- MENU_SEPARATOR,
- self.open_action,
- self.open_last_closed_action,
- self.recent_file_menu,
- MENU_SEPARATOR,
- MENU_SEPARATOR,
- self.save_action,
- self.save_all_action,
- save_as_action,
- save_copy_as_action,
- self.revert_action,
- MENU_SEPARATOR,
- print_preview_action,
- self.print_action,
- MENU_SEPARATOR,
- self.close_action,
- self.close_all_action,
- MENU_SEPARATOR]
-
- self.main.file_menu_actions += file_menu_actions
- file_toolbar_actions = ([self.new_action, self.open_action,
- self.save_action, self.save_all_action] +
- self.main.file_toolbar_actions)
-
- self.main.file_toolbar_actions = file_toolbar_actions
-
- # ---- Find menu/toolbar construction ----
- self.main.search_menu_actions = [find_action,
- find_next_action,
- find_previous_action,
- replace_action]
- self.main.search_toolbar_actions = [find_action,
- find_next_action,
- replace_action]
-
- # ---- Edit menu/toolbar construction ----
- self.edit_menu_actions = [self.toggle_comment_action,
- blockcomment_action, unblockcomment_action,
- self.indent_action, self.unindent_action,
- self.text_uppercase_action,
- self.text_lowercase_action]
- self.main.edit_menu_actions += [MENU_SEPARATOR] + self.edit_menu_actions
- edit_toolbar_actions = [self.toggle_comment_action,
- self.unindent_action, self.indent_action]
- self.main.edit_toolbar_actions += edit_toolbar_actions
-
- # ---- Search menu/toolbar construction ----
- self.search_menu_actions = [gotoline_action]
- self.main.search_menu_actions += self.search_menu_actions
- self.main.search_toolbar_actions += [gotoline_action]
-
- # ---- Run menu/toolbar construction ----
- run_menu_actions = [run_action, run_cell_action,
- run_cell_advance_action,
- re_run_last_cell_action, MENU_SEPARATOR,
- run_selected_action, re_run_action,
- configure_action, MENU_SEPARATOR]
- self.main.run_menu_actions += run_menu_actions
- run_toolbar_actions = [run_action, run_cell_action,
- run_cell_advance_action, run_selected_action,
- re_run_action]
- self.main.run_toolbar_actions += run_toolbar_actions
-
- # ---- Debug menu/toolbar construction ----
- # NOTE: 'list_breakpoints' is used by the breakpoints
- # plugin to add its "List breakpoints" action to this
- # menu
- debug_menu_actions = [debug_action,
- debug_next_action,
- debug_step_action,
- debug_return_action,
- debug_continue_action,
- debug_exit_action,
- MENU_SEPARATOR,
- set_clear_breakpoint_action,
- set_cond_breakpoint_action,
- clear_all_breakpoints_action,
- 'list_breakpoints',
- MENU_SEPARATOR,
- self.winpdb_action]
- self.main.debug_menu_actions += debug_menu_actions
- debug_toolbar_actions = [debug_action, debug_next_action,
- debug_step_action, debug_return_action,
- debug_continue_action, debug_exit_action]
- self.main.debug_toolbar_actions += debug_toolbar_actions
-
- # ---- Source menu/toolbar construction ----
- source_menu_actions = [eol_menu,
- showblanks_action,
- scrollpastend_action,
- showindentguides_action,
- show_classfunc_dropdown_action,
- showcode_analysis_pep8_action,
- trailingspaces_action,
- fixindentation_action,
- MENU_SEPARATOR,
- self.todo_list_action,
- self.warning_list_action,
- self.previous_warning_action,
- self.next_warning_action,
- MENU_SEPARATOR,
- self.previous_edit_cursor_action,
- self.previous_cursor_action,
- self.next_cursor_action]
- self.main.source_menu_actions += source_menu_actions
-
- source_toolbar_actions = [self.todo_list_action,
- self.warning_list_action,
- self.previous_warning_action,
- self.next_warning_action,
- MENU_SEPARATOR,
- self.previous_edit_cursor_action,
- self.previous_cursor_action,
- self.next_cursor_action]
- self.main.source_toolbar_actions += source_toolbar_actions
-
- # ---- Dock widget and file dependent actions ----
- self.dock_toolbar_actions = (file_toolbar_actions +
- [MENU_SEPARATOR] +
- source_toolbar_actions +
- [MENU_SEPARATOR] +
- run_toolbar_actions +
- [MENU_SEPARATOR] +
- debug_toolbar_actions +
- [MENU_SEPARATOR] +
- edit_toolbar_actions)
- self.pythonfile_dependent_actions = [run_action, configure_action,
- set_clear_breakpoint_action,
- set_cond_breakpoint_action,
- debug_action, run_selected_action,
- run_cell_action,
- run_cell_advance_action,
- re_run_last_cell_action,
- blockcomment_action,
- unblockcomment_action,
- self.winpdb_action]
- self.cythonfile_compatible_actions = [run_action, configure_action]
- self.file_dependent_actions = self.pythonfile_dependent_actions + \
- [self.save_action, save_as_action, save_copy_as_action,
- print_preview_action, self.print_action,
- self.save_all_action, gotoline_action, workdir_action,
- self.close_action, self.close_all_action,
- self.toggle_comment_action, self.revert_action,
- self.indent_action, self.unindent_action]
- self.stack_menu_actions = [gotoline_action, workdir_action]
-
- return self.file_dependent_actions
-
- def register_plugin(self):
- """Register plugin in Spyder's main window"""
- self.main.restore_scrollbar_position.connect(
- self.restore_scrollbar_position)
- self.main.console.edit_goto.connect(self.load)
- self.exec_in_extconsole.connect(self.main.execute_in_external_console)
- self.redirect_stdio.connect(self.main.redirect_internalshell_stdio)
- self.open_dir.connect(self.main.workingdirectory.chdir)
- self.set_help(self.main.help)
- if self.main.outlineexplorer is not None:
- self.set_outlineexplorer(self.main.outlineexplorer)
- editorstack = self.get_current_editorstack()
- if not editorstack.data:
- self.__load_temp_file()
- self.main.add_dockwidget(self)
- self.main.add_to_fileswitcher(self, editorstack.tabs, editorstack.data,
- ima.icon('TextFileIcon'))
-
- def update_font(self):
- """Update font from Preferences"""
- font = self.get_plugin_font()
- color_scheme = self.get_color_scheme()
- for editorstack in self.editorstacks:
- editorstack.set_default_font(font, color_scheme)
- completion_size = CONF.get('main', 'completion/size')
- for finfo in editorstack.data:
- comp_widget = finfo.editor.completion_widget
- comp_widget.setup_appearance(completion_size, font)
-
- def _create_checkable_action(self, text, conf_name, editorstack_method):
- """Helper function to create a checkable action.
-
- Args:
- text (str): Text to be displayed in the action.
- conf_name (str): configuration setting associated with the action
- editorstack_method (str): name of EditorStack class that will be
- used to update the changes in each editorstack.
- """
- def toogle(checked):
- self._toggle_checkable_action(checked, editorstack_method,
- conf_name)
- action = create_action(self, text, toggled=toogle)
- action.setChecked(CONF.get('editor', conf_name))
- return action
-
- @Slot(bool, str, str)
- def _toggle_checkable_action(self, checked, editorstack_method, conf_name):
- """Handle the toogle of a checkable action.
-
- Update editorstacks and the configuration.
-
- Args:
- checked (bool): State of the action.
- editorstack_method (str): name of EditorStack class that will be
- used to update the changes in each editorstack.
- conf_name (str): configuration setting associated with the action.
- """
- if self.editorstacks:
- for editorstack in self.editorstacks:
- try:
- editorstack.__getattribute__(editorstack_method)(checked)
- except AttributeError as e:
- debug_print("Error {}".format(str))
- # Run code analysis when `set_pep8_enabled` is toggled
- if editorstack_method == 'set_pep8_enabled':
- for finfo in editorstack.data:
- finfo.run_code_analysis(
- self.get_option('code_analysis/pyflakes'),
- checked)
- CONF.set('editor', conf_name, checked)
-
- #------ Focus tabwidget
- def __get_focus_editorstack(self):
- fwidget = QApplication.focusWidget()
- if isinstance(fwidget, EditorStack):
- return fwidget
- else:
- for editorstack in self.editorstacks:
- if editorstack.isAncestorOf(fwidget):
- return editorstack
-
- def set_last_focus_editorstack(self, editorwindow, editorstack):
- self.last_focus_editorstack[editorwindow] = editorstack
- self.last_focus_editorstack[None] = editorstack # very last editorstack
-
- def get_last_focus_editorstack(self, editorwindow=None):
- return self.last_focus_editorstack[editorwindow]
-
- def remove_last_focus_editorstack(self, editorstack):
- for editorwindow, widget in list(self.last_focus_editorstack.items()):
- if widget is editorstack:
- self.last_focus_editorstack[editorwindow] = None
-
- def save_focus_editorstack(self):
- editorstack = self.__get_focus_editorstack()
- if editorstack is not None:
- for win in [self]+self.editorwindows:
- if win.isAncestorOf(editorstack):
- self.set_last_focus_editorstack(win, editorstack)
-
- # ------ Handling editorstacks
- def register_editorstack(self, editorstack):
- self.editorstacks.append(editorstack)
- self.register_widget_shortcuts(editorstack)
- if len(self.editorstacks) > 1 and self.main is not None:
- # The first editostack is registered automatically with Spyder's
- # main window through the `register_plugin` method. Only additional
- # editors added by splitting need to be registered.
- # See Issue #5057.
- self.main.fileswitcher.sig_goto_file.connect(
- editorstack.set_stack_index)
-
- if self.isAncestorOf(editorstack):
- # editorstack is a child of the Editor plugin
- self.set_last_focus_editorstack(self, editorstack)
- editorstack.set_closable( len(self.editorstacks) > 1 )
- if self.outlineexplorer is not None:
- editorstack.set_outlineexplorer(self.outlineexplorer.explorer)
- editorstack.set_find_widget(self.find_widget)
- editorstack.reset_statusbar.connect(self.readwrite_status.hide)
- editorstack.reset_statusbar.connect(self.encoding_status.hide)
- editorstack.reset_statusbar.connect(self.cursorpos_status.hide)
- editorstack.readonly_changed.connect(
- self.readwrite_status.readonly_changed)
- editorstack.encoding_changed.connect(
- self.encoding_status.encoding_changed)
- editorstack.sig_editor_cursor_position_changed.connect(
- self.cursorpos_status.cursor_position_changed)
- editorstack.sig_refresh_eol_chars.connect(self.eol_status.eol_changed)
-
- editorstack.set_help(self.help)
- editorstack.set_io_actions(self.new_action, self.open_action,
- self.save_action, self.revert_action)
- editorstack.set_tempfile_path(self.TEMPFILE_PATH)
- editorstack.set_introspector(self.introspector)
-
- settings = (
- ('set_pyflakes_enabled', 'code_analysis/pyflakes'),
- ('set_pep8_enabled', 'code_analysis/pep8'),
- ('set_todolist_enabled', 'todo_list'),
- ('set_realtime_analysis_enabled', 'realtime_analysis'),
- ('set_realtime_analysis_timeout', 'realtime_analysis/timeout'),
- ('set_blanks_enabled', 'blank_spaces'),
- ('set_scrollpastend_enabled', 'scroll_past_end'),
- ('set_linenumbers_enabled', 'line_numbers'),
- ('set_edgeline_enabled', 'edge_line'),
- ('set_edgeline_columns', 'edge_line_columns'),
- ('set_indent_guides', 'indent_guides'),
- ('set_codecompletion_auto_enabled', 'codecompletion/auto'),
- ('set_codecompletion_case_enabled', 'codecompletion/case_sensitive'),
- ('set_codecompletion_enter_enabled', 'codecompletion/enter_key'),
- ('set_calltips_enabled', 'calltips'),
- ('set_go_to_definition_enabled', 'go_to_definition'),
- ('set_focus_to_editor', 'focus_to_editor'),
- ('set_close_parentheses_enabled', 'close_parentheses'),
- ('set_close_quotes_enabled', 'close_quotes'),
- ('set_add_colons_enabled', 'add_colons'),
- ('set_auto_unindent_enabled', 'auto_unindent'),
- ('set_indent_chars', 'indent_chars'),
- ('set_tab_stop_width_spaces', 'tab_stop_width_spaces'),
- ('set_wrap_enabled', 'wrap'),
- ('set_tabmode_enabled', 'tab_always_indent'),
- ('set_intelligent_backspace_enabled', 'intelligent_backspace'),
- ('set_highlight_current_line_enabled', 'highlight_current_line'),
- ('set_highlight_current_cell_enabled', 'highlight_current_cell'),
- ('set_occurrence_highlighting_enabled', 'occurrence_highlighting'),
- ('set_occurrence_highlighting_timeout', 'occurrence_highlighting/timeout'),
- ('set_checkeolchars_enabled', 'check_eol_chars'),
- ('set_tabbar_visible', 'show_tab_bar'),
- ('set_classfunc_dropdown_visible', 'show_class_func_dropdown'),
- ('set_always_remove_trailing_spaces', 'always_remove_trailing_spaces'),
- ('set_convert_eol_on_save', 'convert_eol_on_save'),
- ('set_convert_eol_on_save_to', 'convert_eol_on_save_to'),
- )
- for method, setting in settings:
- getattr(editorstack, method)(self.get_option(setting))
- editorstack.set_help_enabled(CONF.get('help', 'connect/editor'))
- color_scheme = self.get_color_scheme()
- editorstack.set_default_font(self.get_plugin_font(), color_scheme)
-
- editorstack.starting_long_process.connect(self.starting_long_process)
- editorstack.ending_long_process.connect(self.ending_long_process)
-
- # Redirect signals
- editorstack.redirect_stdio.connect(
- lambda state: self.redirect_stdio.emit(state))
- editorstack.exec_in_extconsole.connect(
- lambda text, option:
- self.exec_in_extconsole.emit(text, option))
- editorstack.update_plugin_title.connect(
- lambda: self.sig_update_plugin_title.emit())
- editorstack.editor_focus_changed.connect(self.save_focus_editorstack)
- editorstack.editor_focus_changed.connect(self.set_editorstack_for_introspection)
- editorstack.editor_focus_changed.connect(self.main.plugin_focus_changed)
- editorstack.zoom_in.connect(lambda: self.zoom(1))
- editorstack.zoom_out.connect(lambda: self.zoom(-1))
- editorstack.zoom_reset.connect(lambda: self.zoom(0))
- editorstack.sig_new_file.connect(lambda s: self.new(text=s))
- editorstack.sig_new_file[()].connect(self.new)
- editorstack.sig_close_file.connect(self.close_file_in_all_editorstacks)
- editorstack.file_saved.connect(self.file_saved_in_editorstack)
- editorstack.file_renamed_in_data.connect(
- self.file_renamed_in_data_in_editorstack)
- editorstack.sig_undock_window.connect(self.undock_plugin)
- editorstack.opened_files_list_changed.connect(
- self.opened_files_list_changed)
- editorstack.analysis_results_changed.connect(
- self.analysis_results_changed)
- editorstack.todo_results_changed.connect(self.todo_results_changed)
- editorstack.update_code_analysis_actions.connect(
- self.update_code_analysis_actions)
- editorstack.update_code_analysis_actions.connect(
- self.update_todo_actions)
- editorstack.refresh_file_dependent_actions.connect(
- self.refresh_file_dependent_actions)
- editorstack.refresh_save_all_action.connect(self.refresh_save_all_action)
- editorstack.sig_refresh_eol_chars.connect(self.refresh_eol_chars)
- editorstack.save_breakpoints.connect(self.save_breakpoints)
- editorstack.text_changed_at.connect(self.text_changed_at)
- editorstack.current_file_changed.connect(self.current_file_changed)
- editorstack.plugin_load.connect(self.load)
- editorstack.plugin_load[()].connect(self.load)
- editorstack.edit_goto.connect(self.load)
- editorstack.sig_save_as.connect(self.save_as)
- editorstack.sig_prev_edit_pos.connect(self.go_to_last_edit_location)
- editorstack.sig_prev_cursor.connect(self.go_to_previous_cursor_position)
- editorstack.sig_next_cursor.connect(self.go_to_next_cursor_position)
- editorstack.sig_prev_warning.connect(self.go_to_previous_warning)
- editorstack.sig_next_warning.connect(self.go_to_next_warning)
-
- def unregister_editorstack(self, editorstack):
- """Removing editorstack only if it's not the last remaining"""
- self.remove_last_focus_editorstack(editorstack)
- if len(self.editorstacks) > 1:
- index = self.editorstacks.index(editorstack)
- self.editorstacks.pop(index)
- return True
- else:
- # editorstack was not removed!
- return False
-
- def clone_editorstack(self, editorstack):
- editorstack.clone_from(self.editorstacks[0])
- for finfo in editorstack.data:
- self.register_widget_shortcuts(finfo.editor)
-
- @Slot(str, str)
- def close_file_in_all_editorstacks(self, editorstack_id_str, filename):
- for editorstack in self.editorstacks:
- if str(id(editorstack)) != editorstack_id_str:
- editorstack.blockSignals(True)
- index = editorstack.get_index_from_filename(filename)
- editorstack.close_file(index, force=True)
- editorstack.blockSignals(False)
-
- @Slot(str, str, str)
- def file_saved_in_editorstack(self, editorstack_id_str,
- original_filename, filename):
- """A file was saved in editorstack, this notifies others"""
- for editorstack in self.editorstacks:
- if str(id(editorstack)) != editorstack_id_str:
- editorstack.file_saved_in_other_editorstack(original_filename,
- filename)
-
- @Slot(str, str, str)
- def file_renamed_in_data_in_editorstack(self, editorstack_id_str,
- original_filename, filename):
- """A file was renamed in data in editorstack, this notifies others"""
- for editorstack in self.editorstacks:
- if str(id(editorstack)) != editorstack_id_str:
- editorstack.rename_in_data(original_filename, filename)
-
- def set_editorstack_for_introspection(self):
- """
- Set the current editorstack to be used by the IntrospectionManager
- instance
- """
- editorstack = self.__get_focus_editorstack()
- if editorstack is not None:
- self.introspector.set_editor_widget(editorstack)
-
- # Disconnect active signals
- try:
- self.introspector.sig_send_to_help.disconnect()
- self.introspector.sig_edit_goto.disconnect()
- except TypeError:
- pass
-
- # Reconnect signals again
- self.introspector.sig_send_to_help.connect(editorstack.send_to_help)
- self.introspector.sig_edit_goto.connect(
- lambda fname, lineno, name:
- editorstack.edit_goto.emit(fname, lineno, name))
-
- #------ Handling editor windows
- def setup_other_windows(self):
- """Setup toolbars and menus for 'New window' instances"""
-
- self.toolbar_list = ((_("File toolbar"), "file_toolbar",
- self.main.file_toolbar_actions),
- (_("Search toolbar"), "search_toolbar",
- self.main.search_menu_actions),
- (_("Source toolbar"), "source_toolbar",
- self.main.source_toolbar_actions),
- (_("Run toolbar"), "run_toolbar",
- self.main.run_toolbar_actions),
- (_("Debug toolbar"), "debug_toolbar",
- self.main.debug_toolbar_actions),
- (_("Edit toolbar"), "edit_toolbar",
- self.main.edit_toolbar_actions))
- self.menu_list = ((_("&File"), self.main.file_menu_actions),
- (_("&Edit"), self.main.edit_menu_actions),
- (_("&Search"), self.main.search_menu_actions),
- (_("Sour&ce"), self.main.source_menu_actions),
- (_("&Run"), self.main.run_menu_actions),
- (_("&Tools"), self.main.tools_menu_actions),
- (_("&View"), []),
- (_("&Help"), self.main.help_menu_actions))
- # Create pending new windows:
- for layout_settings in self.editorwindows_to_be_created:
- win = self.create_new_window()
- win.set_layout_settings(layout_settings)
-
- @Slot()
- def create_window(self):
- """Open a new window instance of the Editor instead of undocking it."""
- if (self.dockwidget.isFloating() and not self.undocked and
- self.dockwidget.main.dockwidgets_locked):
- self.dockwidget.setVisible(False)
- self.create_new_window()
- self.toggle_view_action.setChecked(False)
- self.dockwidget.setFloating(False)
- self.undocked = False
- if self.get_current_editorstack():
- self.get_current_editorstack().new_window = False
-
- def undock_plugin(self):
- """Undocks the Editor window."""
- super(Editor, self).undock_plugin()
- self.get_current_editorstack().new_window = True
-
- def switch_to_plugin(self):
- """
- Reimplemented method to desactivate shortcut when
- opening a new window.
- """
- if not self.editorwindows or self.dockwidget.isVisible():
- super(Editor, self).switch_to_plugin()
-
- def create_new_window(self):
- oe_options = self.outlineexplorer.explorer.get_options()
- window = EditorMainWindow(self, self.stack_menu_actions,
- self.toolbar_list, self.menu_list,
- show_fullpath=oe_options['show_fullpath'],
- show_all_files=oe_options['show_all_files'],
- show_comments=oe_options['show_comments'])
- window.add_toolbars_to_menu("&View", window.get_toolbars())
- window.load_toolbars()
- window.resize(self.size())
- window.show()
- window.editorwidget.editorsplitter.editorstack.new_window = True
- self.register_editorwindow(window)
- window.destroyed.connect(lambda: self.unregister_editorwindow(window))
- return window
-
- def register_editorwindow(self, window):
- self.editorwindows.append(window)
-
- def unregister_editorwindow(self, window):
- if len(self.editorwindows) == 1:
- self.toggle_view_action.setChecked(True)
- self.editorwindows.pop(self.editorwindows.index(window))
-
-
- #------ Accessors
- def get_filenames(self):
- return [finfo.filename for finfo in self.editorstacks[0].data]
-
- def get_filename_index(self, filename):
- return self.editorstacks[0].has_filename(filename)
-
- def get_current_editorstack(self, editorwindow=None):
- if self.editorstacks is not None:
- if len(self.editorstacks) == 1:
- editorstack = self.editorstacks[0]
- else:
- editorstack = self.__get_focus_editorstack()
- if editorstack is None or editorwindow is not None:
- editorstack = self.get_last_focus_editorstack(editorwindow)
- if editorstack is None:
- editorstack = self.editorstacks[0]
- return editorstack
-
- def get_current_editor(self):
- editorstack = self.get_current_editorstack()
- if editorstack is not None:
- return editorstack.get_current_editor()
-
- def get_current_finfo(self):
- editorstack = self.get_current_editorstack()
- if editorstack is not None:
- return editorstack.get_current_finfo()
-
- def get_current_filename(self):
- editorstack = self.get_current_editorstack()
- if editorstack is not None:
- return editorstack.get_current_filename()
-
- def is_file_opened(self, filename=None):
- return self.editorstacks[0].is_file_opened(filename)
-
- def set_current_filename(self, filename, editorwindow=None, focus=True):
- """Set focus to *filename* if this file has been opened.
-
- Return the editor instance associated to *filename*.
- """
- editorstack = self.get_current_editorstack(editorwindow)
- return editorstack.set_current_filename(filename, focus)
-
- def set_path(self):
- for finfo in self.editorstacks[0].data:
- finfo.path = self.main.get_spyder_pythonpath()
- if self.introspector:
- self.introspector.change_extra_path(
- self.main.get_spyder_pythonpath())
-
- #------ FileSwitcher API
- def get_current_tab_manager(self):
- """Get the widget with the TabWidget attribute."""
- return self.get_current_editorstack()
-
- #------ Refresh methods
- def refresh_file_dependent_actions(self):
- """Enable/disable file dependent actions
- (only if dockwidget is visible)"""
- if self.dockwidget and self.dockwidget.isVisible():
- enable = self.get_current_editor() is not None
- for action in self.file_dependent_actions:
- action.setEnabled(enable)
-
- def refresh_save_all_action(self):
- """Enable 'Save All' if there are files to be saved"""
- editorstack = self.get_current_editorstack()
- if editorstack:
- state = any(finfo.editor.document().isModified() or finfo.newly_created
- for finfo in editorstack.data)
- self.save_all_action.setEnabled(state)
-
- def update_warning_menu(self):
- """Update warning list menu"""
- editorstack = self.get_current_editorstack()
- check_results = editorstack.get_analysis_results()
- self.warning_menu.clear()
- filename = self.get_current_filename()
- for message, line_number in check_results:
- error = 'syntax' in message
- text = message[:1].upper()+message[1:]
- icon = ima.icon('error') if error else ima.icon('warning')
- # QAction.triggered works differently for PySide and PyQt
- if not API == 'pyside':
- slot = lambda _checked, _l=line_number: self.load(filename, goto=_l)
- else:
- slot = lambda _l=line_number: self.load(filename, goto=_l)
- action = create_action(self, text=text, icon=icon, triggered=slot)
- self.warning_menu.addAction(action)
-
- def analysis_results_changed(self):
- """
- Synchronize analysis results between editorstacks
- Refresh analysis navigation buttons
- """
- editorstack = self.get_current_editorstack()
- results = editorstack.get_analysis_results()
- index = editorstack.get_stack_index()
- if index != -1:
- filename = editorstack.data[index].filename
- for other_editorstack in self.editorstacks:
- if other_editorstack is not editorstack:
- other_editorstack.set_analysis_results(filename, results)
- self.update_code_analysis_actions()
-
- def update_todo_menu(self):
- """Update todo list menu"""
- editorstack = self.get_current_editorstack()
- results = editorstack.get_todo_results()
- self.todo_menu.clear()
- filename = self.get_current_filename()
- for text, line0 in results:
- icon = ima.icon('todo')
- # QAction.triggered works differently for PySide and PyQt
- if not API == 'pyside':
- slot = lambda _checked, _l=line0: self.load(filename, goto=_l)
- else:
- slot = lambda _l=line0: self.load(filename, goto=_l)
- action = create_action(self, text=text, icon=icon, triggered=slot)
- self.todo_menu.addAction(action)
- self.update_todo_actions()
-
- def todo_results_changed(self):
- """
- Synchronize todo results between editorstacks
- Refresh todo list navigation buttons
- """
- editorstack = self.get_current_editorstack()
- results = editorstack.get_todo_results()
- index = editorstack.get_stack_index()
- if index != -1:
- filename = editorstack.data[index].filename
- for other_editorstack in self.editorstacks:
- if other_editorstack is not editorstack:
- other_editorstack.set_todo_results(filename, results)
- self.update_todo_actions()
-
- def refresh_eol_chars(self, os_name):
- os_name = to_text_string(os_name)
- self.__set_eol_chars = False
- if os_name == 'nt':
- self.win_eol_action.setChecked(True)
- elif os_name == 'posix':
- self.linux_eol_action.setChecked(True)
- else:
- self.mac_eol_action.setChecked(True)
- self.__set_eol_chars = True
-
-
- #------ Slots
- def opened_files_list_changed(self):
- """
- Opened files list has changed:
- --> open/close file action
- --> modification ('*' added to title)
- --> current edited file has changed
- """
- # Refresh Python file dependent actions:
- editor = self.get_current_editor()
- if editor:
- python_enable = editor.is_python()
- cython_enable = python_enable or (
- programs.is_module_installed('Cython') and editor.is_cython())
- for action in self.pythonfile_dependent_actions:
- if action in self.cythonfile_compatible_actions:
- enable = cython_enable
- else:
- enable = python_enable
- if action is self.winpdb_action:
- action.setEnabled(enable and WINPDB_PATH is not None)
- else:
- action.setEnabled(enable)
- self.open_file_update.emit(self.get_current_filename())
-
- def update_code_analysis_actions(self):
- editorstack = self.get_current_editorstack()
- results = editorstack.get_analysis_results()
-
- # Update code analysis buttons
- state = (self.get_option('code_analysis/pyflakes') \
- or self.get_option('code_analysis/pep8')) \
- and results is not None and len(results)
- for action in (self.warning_list_action, self.previous_warning_action,
- self.next_warning_action):
- action.setEnabled(state)
-
- def update_todo_actions(self):
- editorstack = self.get_current_editorstack()
- results = editorstack.get_todo_results()
- state = self.get_option('todo_list') \
- and results is not None and len(results)
- self.todo_list_action.setEnabled(state)
-
- def rehighlight_cells(self):
- """Rehighlight cells of current editor"""
- editor = self.get_current_editor()
- editor.rehighlight_cells()
- QApplication.processEvents()
-
-
- #------ Breakpoints
- def save_breakpoints(self, filename, breakpoints):
- filename = to_text_string(filename)
- breakpoints = to_text_string(breakpoints)
- filename = osp.normpath(osp.abspath(filename))
- if breakpoints:
- breakpoints = eval(breakpoints)
- else:
- breakpoints = []
- save_breakpoints(filename, breakpoints)
- self.breakpoints_saved.emit()
-
- #------ File I/O
- def __load_temp_file(self):
- """Load temporary file from a text file in user home directory"""
- if not osp.isfile(self.TEMPFILE_PATH):
- # Creating temporary file
- default = ['# -*- coding: utf-8 -*-',
- '"""', _("Spyder Editor"), '',
- _("This is a temporary script file."),
- '"""', '', '']
- text = os.linesep.join([encoding.to_unicode(qstr)
- for qstr in default])
- encoding.write(to_text_string(text), self.TEMPFILE_PATH, 'utf-8')
- self.load(self.TEMPFILE_PATH)
-
- @Slot()
- def __set_workdir(self):
- """Set current script directory as working directory"""
- fname = self.get_current_filename()
- if fname is not None:
- directory = osp.dirname(osp.abspath(fname))
- self.open_dir.emit(directory)
-
- def __add_recent_file(self, fname):
- """Add to recent file list"""
- if fname is None:
- return
- if fname in self.recent_files:
- self.recent_files.remove(fname)
- self.recent_files.insert(0, fname)
- if len(self.recent_files) > self.get_option('max_recent_files'):
- self.recent_files.pop(-1)
-
- def _clone_file_everywhere(self, finfo):
- """Clone file (*src_editor* widget) in all editorstacks
- Cloning from the first editorstack in which every single new editor
- is created (when loading or creating a new file)"""
- for editorstack in self.editorstacks[1:]:
- editor = editorstack.clone_editor_from(finfo, set_current=False)
- self.register_widget_shortcuts(editor)
-
- @Slot()
- @Slot(str)
- def new(self, fname=None, editorstack=None, text=None):
- """
- Create a new file - Untitled
-
- fname=None --> fname will be 'untitledXX.py' but do not create file
- fname= --> create file
- """
- # If no text is provided, create default content
- empty = False
- try:
- if text is None:
- default_content = True
- text, enc = encoding.read(self.TEMPLATE_PATH)
- enc_match = re.search(r'-*- coding: ?([a-z0-9A-Z\-]*) -*-',
- text)
- if enc_match:
- enc = enc_match.group(1)
- # Initialize template variables
- # Windows
- username = encoding.to_unicode_from_fs(
- os.environ.get('USERNAME', ''))
- # Linux, Mac OS X
- if not username:
- username = encoding.to_unicode_from_fs(
- os.environ.get('USER', '-'))
- VARS = {
- 'date': time.ctime(),
- 'username': username,
- }
- try:
- text = text % VARS
- except Exception:
- pass
- else:
- default_content = False
- enc = encoding.read(self.TEMPLATE_PATH)[1]
- except (IOError, OSError):
- text = ''
- enc = 'utf-8'
- default_content = True
- empty = True
-
- create_fname = lambda n: to_text_string(_("untitled")) + ("%d.py" % n)
- # Creating editor widget
- if editorstack is None:
- current_es = self.get_current_editorstack()
- else:
- current_es = editorstack
- created_from_here = fname is None
- if created_from_here:
- while True:
- fname = create_fname(self.untitled_num)
- self.untitled_num += 1
- if not osp.isfile(fname):
- break
- basedir = getcwd_or_home()
-
- if self.main.projects.get_active_project() is not None:
- basedir = self.main.projects.get_active_project_path()
- else:
- c_fname = self.get_current_filename()
- if c_fname is not None and c_fname != self.TEMPFILE_PATH:
- basedir = osp.dirname(c_fname)
- fname = osp.abspath(osp.join(basedir, fname))
- else:
- # QString when triggered by a Qt signal
- fname = osp.abspath(to_text_string(fname))
- index = current_es.has_filename(fname)
- if index is not None and not current_es.close_file(index):
- return
-
- # Creating the editor widget in the first editorstack (the one that
- # can't be destroyed), then cloning this editor widget in all other
- # editorstacks:
- finfo = self.editorstacks[0].new(fname, enc, text, default_content,
- empty)
- finfo.path = self.main.get_spyder_pythonpath()
- self._clone_file_everywhere(finfo)
- current_editor = current_es.set_current_filename(finfo.filename)
- self.register_widget_shortcuts(current_editor)
- if not created_from_here:
- self.save(force=True)
-
- def edit_template(self):
- """Edit new file template"""
- self.load(self.TEMPLATE_PATH)
-
- def update_recent_file_menu(self):
- """Update recent file menu"""
- recent_files = []
- for fname in self.recent_files:
- if self.is_file_opened(fname) is None and osp.isfile(fname):
- recent_files.append(fname)
- self.recent_file_menu.clear()
- if recent_files:
- for fname in recent_files:
- action = create_action(self, fname,
- icon=ima.icon('FileIcon'),
- triggered=self.load)
- action.setData(to_qvariant(fname))
- self.recent_file_menu.addAction(action)
- self.clear_recent_action.setEnabled(len(recent_files) > 0)
- add_actions(self.recent_file_menu, (None, self.max_recent_action,
- self.clear_recent_action))
-
- @Slot()
- def clear_recent_files(self):
- """Clear recent files list"""
- self.recent_files = []
-
- @Slot()
- def change_max_recent_files(self):
- "Change max recent files entries"""
- editorstack = self.get_current_editorstack()
- mrf, valid = QInputDialog.getInt(editorstack, _('Editor'),
- _('Maximum number of recent files'),
- self.get_option('max_recent_files'), 1, 35)
- if valid:
- self.set_option('max_recent_files', mrf)
-
- @Slot()
- @Slot(str)
- @Slot(str, int, str)
- @Slot(str, int, str, object)
- def load(self, filenames=None, goto=None, word='', editorwindow=None,
- processevents=True):
- """
- Load a text file
- editorwindow: load in this editorwindow (useful when clicking on
- outline explorer with multiple editor windows)
- processevents: determines if processEvents() should be called at the
- end of this method (set to False to prevent keyboard events from
- creeping through to the editor during debugging)
- """
- editor0 = self.get_current_editor()
- if editor0 is not None:
- position0 = editor0.get_position('cursor')
- filename0 = self.get_current_filename()
- else:
- position0, filename0 = None, None
- if not filenames:
- # Recent files action
- action = self.sender()
- if isinstance(action, QAction):
- filenames = from_qvariant(action.data(), to_text_string)
- if not filenames:
- basedir = getcwd_or_home()
- if self.edit_filetypes is None:
- self.edit_filetypes = get_edit_filetypes()
- if self.edit_filters is None:
- self.edit_filters = get_edit_filters()
-
- c_fname = self.get_current_filename()
- if c_fname is not None and c_fname != self.TEMPFILE_PATH:
- basedir = osp.dirname(c_fname)
- self.redirect_stdio.emit(False)
- parent_widget = self.get_current_editorstack()
- if filename0 is not None:
- selectedfilter = get_filter(self.edit_filetypes,
- osp.splitext(filename0)[1])
- else:
- selectedfilter = ''
- if not running_under_pytest():
- filenames, _sf = getopenfilenames(
- parent_widget,
- _("Open file"), basedir,
- self.edit_filters,
- selectedfilter=selectedfilter,
- options=QFileDialog.HideNameFilterDetails)
- else:
- # Use a Qt (i.e. scriptable) dialog for pytest
- dialog = QFileDialog(parent_widget, _("Open file"),
- options=QFileDialog.DontUseNativeDialog)
- if dialog.exec_():
- filenames = dialog.selectedFiles()
- self.redirect_stdio.emit(True)
- if filenames:
- filenames = [osp.normpath(fname) for fname in filenames]
- else:
- return
-
- focus_widget = QApplication.focusWidget()
- if self.editorwindows and not self.dockwidget.isVisible():
- # We override the editorwindow variable to force a focus on
- # the editor window instead of the hidden editor dockwidget.
- # See PR #5742.
- if editorwindow not in self.editorwindows:
- editorwindow = self.editorwindows[0]
- editorwindow.setFocus()
- editorwindow.raise_()
- elif (self.dockwidget and not self.ismaximized
- and not self.dockwidget.isAncestorOf(focus_widget)
- and not isinstance(focus_widget, CodeEditor)):
- self.dockwidget.setVisible(True)
- self.dockwidget.setFocus()
- self.dockwidget.raise_()
-
- def _convert(fname):
- fname = osp.abspath(encoding.to_unicode_from_fs(fname))
- if os.name == 'nt' and len(fname) >= 2 and fname[1] == ':':
- fname = fname[0].upper()+fname[1:]
- return fname
-
- if hasattr(filenames, 'replaceInStrings'):
- # This is a QStringList instance (PyQt API #1), converting to list:
- filenames = list(filenames)
- if not isinstance(filenames, list):
- filenames = [_convert(filenames)]
- else:
- filenames = [_convert(fname) for fname in list(filenames)]
- if isinstance(goto, int):
- goto = [goto]
- elif goto is not None and len(goto) != len(filenames):
- goto = None
-
- for index, filename in enumerate(filenames):
- # -- Do not open an already opened file
- if index == 0: # this is the last file focused in previous session
- focus = True
- else:
- focus = False
- current_editor = self.set_current_filename(filename,
- editorwindow,
- focus=focus)
- if current_editor is None:
- # -- Not a valid filename:
- if not osp.isfile(filename):
- continue
- # --
- current_es = self.get_current_editorstack(editorwindow)
- # Creating the editor widget in the first editorstack
- # (the one that can't be destroyed), then cloning this
- # editor widget in all other editorstacks:
- finfo = self.editorstacks[0].load(filename, set_current=False)
- finfo.path = self.main.get_spyder_pythonpath()
- self._clone_file_everywhere(finfo)
- current_editor = current_es.set_current_filename(filename,
- focus=focus)
- current_editor.set_breakpoints(load_breakpoints(filename))
- self.register_widget_shortcuts(current_editor)
- current_es.analyze_script()
- self.__add_recent_file(filename)
- if goto is not None: # 'word' is assumed to be None as well
- current_editor.go_to_line(goto[index], word=word)
- position = current_editor.get_position('cursor')
- self.cursor_moved(filename0, position0, filename, position)
- current_editor.clearFocus()
- current_editor.setFocus()
- current_editor.window().raise_()
- if processevents:
- QApplication.processEvents()
-
- @Slot()
- def print_file(self):
- """Print current file"""
- editor = self.get_current_editor()
- filename = self.get_current_filename()
- printer = Printer(mode=QPrinter.HighResolution,
- header_font=self.get_plugin_font('printer_header'))
- printDialog = QPrintDialog(printer, editor)
- if editor.has_selected_text():
- printDialog.setOption(QAbstractPrintDialog.PrintSelection, True)
- self.redirect_stdio.emit(False)
- answer = printDialog.exec_()
- self.redirect_stdio.emit(True)
- if answer == QDialog.Accepted:
- self.starting_long_process(_("Printing..."))
- printer.setDocName(filename)
- editor.print_(printer)
- self.ending_long_process()
-
- @Slot()
- def print_preview(self):
- """Print preview for current file"""
- from qtpy.QtPrintSupport import QPrintPreviewDialog
-
- editor = self.get_current_editor()
- printer = Printer(mode=QPrinter.HighResolution,
- header_font=self.get_plugin_font('printer_header'))
- preview = QPrintPreviewDialog(printer, self)
- preview.setWindowFlags(Qt.Window)
- preview.paintRequested.connect(lambda printer: editor.print_(printer))
- self.redirect_stdio.emit(False)
- preview.exec_()
- self.redirect_stdio.emit(True)
-
- @Slot()
- def close_file(self):
- """Close current file"""
- editorstack = self.get_current_editorstack()
- editorstack.close_file()
-
- @Slot()
- def close_all_files(self):
- """Close all opened scripts"""
- self.editorstacks[0].close_all_files()
-
- @Slot()
- def save(self, index=None, force=False):
- """Save file"""
- editorstack = self.get_current_editorstack()
- return editorstack.save(index=index, force=force)
-
- @Slot()
- def save_as(self):
- """Save *as* the currently edited file"""
- editorstack = self.get_current_editorstack()
- if editorstack.save_as():
- fname = editorstack.get_current_filename()
- self.__add_recent_file(fname)
-
- @Slot()
- def save_copy_as(self):
- """Save *copy as* the currently edited file"""
- editorstack = self.get_current_editorstack()
- editorstack.save_copy_as()
-
- @Slot()
- def save_all(self):
- """Save all opened files"""
- self.get_current_editorstack().save_all()
-
- @Slot()
- def revert(self):
- """Revert the currently edited file from disk"""
- editorstack = self.get_current_editorstack()
- editorstack.revert()
-
- @Slot()
- def find(self):
- """Find slot"""
- editorstack = self.get_current_editorstack()
- editorstack.find_widget.show()
- editorstack.find_widget.search_text.setFocus()
-
- @Slot()
- def find_next(self):
- """Fnd next slot"""
- editorstack = self.get_current_editorstack()
- editorstack.find_widget.find_next()
-
- @Slot()
- def find_previous(self):
- """Find previous slot"""
- editorstack = self.get_current_editorstack()
- editorstack.find_widget.find_previous()
-
- @Slot()
- def replace(self):
- """Replace slot"""
- editorstack = self.get_current_editorstack()
- editorstack.find_widget.show_replace()
-
- def open_last_closed(self):
- """ Reopens the last closed tab."""
- editorstack = self.get_current_editorstack()
- last_closed_files = editorstack.get_last_closed_files()
- if (len(last_closed_files) > 0):
- file_to_open = last_closed_files[0]
- last_closed_files.remove(file_to_open)
- editorstack.set_last_closed_files(last_closed_files)
- self.load(file_to_open)
-
- #------ Explorer widget
- def close_file_from_name(self, filename):
- """Close file from its name"""
- filename = osp.abspath(to_text_string(filename))
- index = self.editorstacks[0].has_filename(filename)
- if index is not None:
- self.editorstacks[0].close_file(index)
-
- def removed(self, filename):
- """File was removed in file explorer widget or in project explorer"""
- self.close_file_from_name(filename)
-
- def removed_tree(self, dirname):
- """Directory was removed in project explorer widget"""
- dirname = osp.abspath(to_text_string(dirname))
- for fname in self.get_filenames():
- if osp.abspath(fname).startswith(dirname):
- self.close_file_from_name(fname)
-
- def renamed(self, source, dest):
- """File was renamed in file explorer widget or in project explorer"""
- filename = osp.abspath(to_text_string(source))
- index = self.editorstacks[0].has_filename(filename)
- if index is not None:
- for editorstack in self.editorstacks:
- editorstack.rename_in_data(filename,
- new_filename=to_text_string(dest))
-
- def renamed_tree(self, source, dest):
- """Directory was renamed in file explorer or in project explorer."""
- dirname = osp.abspath(to_text_string(source))
- tofile = to_text_string(dest)
- for fname in self.get_filenames():
- if osp.abspath(fname).startswith(dirname):
- new_filename = fname.replace(dirname, tofile)
- self.renamed(source=fname, dest=new_filename)
-
- #------ Source code
- @Slot()
- def indent(self):
- """Indent current line or selection"""
- editor = self.get_current_editor()
- if editor is not None:
- editor.indent()
-
- @Slot()
- def unindent(self):
- """Unindent current line or selection"""
- editor = self.get_current_editor()
- if editor is not None:
- editor.unindent()
-
- @Slot()
- def text_uppercase (self):
- """Change current line or selection to uppercase."""
- editor = self.get_current_editor()
- if editor is not None:
- editor.transform_to_uppercase()
-
- @Slot()
- def text_lowercase(self):
- """Change current line or selection to lowercase."""
- editor = self.get_current_editor()
- if editor is not None:
- editor.transform_to_lowercase()
-
- @Slot()
- def toggle_comment(self):
- """Comment current line or selection"""
- editor = self.get_current_editor()
- if editor is not None:
- editor.toggle_comment()
-
- @Slot()
- def blockcomment(self):
- """Block comment current line or selection"""
- editor = self.get_current_editor()
- if editor is not None:
- editor.blockcomment()
-
- @Slot()
- def unblockcomment(self):
- """Un-block comment current line or selection"""
- editor = self.get_current_editor()
- if editor is not None:
- editor.unblockcomment()
- @Slot()
- def go_to_next_todo(self):
- editor = self.get_current_editor()
- position = editor.go_to_next_todo()
- filename = self.get_current_filename()
- self.add_cursor_position_to_history(filename, position)
-
- @Slot()
- def go_to_next_warning(self):
- editor = self.get_current_editor()
- position = editor.go_to_next_warning()
- filename = self.get_current_filename()
- self.add_cursor_position_to_history(filename, position)
-
- @Slot()
- def go_to_previous_warning(self):
- editor = self.get_current_editor()
- position = editor.go_to_previous_warning()
- filename = self.get_current_filename()
- self.add_cursor_position_to_history(filename, position)
-
- @Slot()
- def run_winpdb(self):
- """Run winpdb to debug current file"""
- if self.save():
- fname = self.get_current_filename()
- runconf = get_run_configuration(fname)
- if runconf is None:
- args = []
- wdir = None
- else:
- args = runconf.get_arguments().split()
- wdir = runconf.get_working_directory()
- # Handle the case where wdir comes back as an empty string
- # when the working directory dialog checkbox is unchecked.
- # (subprocess "cwd" default is None, so empty str
- # must be changed to None in this case.)
- programs.run_program(WINPDB_PATH, [fname] + args, cwd=wdir or None)
-
- def toggle_eol_chars(self, os_name, checked):
- if checked:
- editor = self.get_current_editor()
- if self.__set_eol_chars:
- editor.set_eol_chars(sourcecode.get_eol_chars_from_os_name(os_name))
-
- @Slot()
- def remove_trailing_spaces(self):
- editorstack = self.get_current_editorstack()
- editorstack.remove_trailing_spaces()
-
- @Slot()
- def fix_indentation(self):
- editorstack = self.get_current_editorstack()
- editorstack.fix_indentation()
-
- #------ Cursor position history management
- def update_cursorpos_actions(self):
- self.previous_edit_cursor_action.setEnabled(
- self.last_edit_cursor_pos is not None)
- self.previous_cursor_action.setEnabled(
- self.cursor_pos_index is not None and self.cursor_pos_index > 0)
- self.next_cursor_action.setEnabled(self.cursor_pos_index is not None \
- and self.cursor_pos_index < len(self.cursor_pos_history)-1)
-
- def add_cursor_position_to_history(self, filename, position, fc=False):
- if self.__ignore_cursor_position:
- return
- for index, (fname, pos) in enumerate(self.cursor_pos_history[:]):
- if fname == filename:
- if pos == position or pos == 0:
- if fc:
- self.cursor_pos_history[index] = (filename, position)
- self.cursor_pos_index = index
- self.update_cursorpos_actions()
- return
- else:
- if self.cursor_pos_index >= index:
- self.cursor_pos_index -= 1
- self.cursor_pos_history.pop(index)
- break
- if self.cursor_pos_index is not None:
- self.cursor_pos_history = \
- self.cursor_pos_history[:self.cursor_pos_index+1]
- self.cursor_pos_history.append((filename, position))
- self.cursor_pos_index = len(self.cursor_pos_history)-1
- self.update_cursorpos_actions()
-
- def cursor_moved(self, filename0, position0, filename1, position1):
- """Cursor was just moved: 'go to'"""
- if position0 is not None:
- self.add_cursor_position_to_history(filename0, position0)
- self.add_cursor_position_to_history(filename1, position1)
-
- def text_changed_at(self, filename, position):
- self.last_edit_cursor_pos = (to_text_string(filename), position)
-
- def current_file_changed(self, filename, position):
- self.add_cursor_position_to_history(to_text_string(filename), position,
- fc=True)
-
- @Slot()
- def go_to_last_edit_location(self):
- if self.last_edit_cursor_pos is not None:
- filename, position = self.last_edit_cursor_pos
- if not osp.isfile(filename):
- self.last_edit_cursor_pos = None
- return
- else:
- self.load(filename)
- editor = self.get_current_editor()
- if position < editor.document().characterCount():
- editor.set_cursor_position(position)
-
- def __move_cursor_position(self, index_move):
- if self.cursor_pos_index is None:
- return
- filename, _position = self.cursor_pos_history[self.cursor_pos_index]
- self.cursor_pos_history[self.cursor_pos_index] = ( filename,
- self.get_current_editor().get_position('cursor') )
- self.__ignore_cursor_position = True
- old_index = self.cursor_pos_index
- self.cursor_pos_index = min([
- len(self.cursor_pos_history)-1,
- max([0, self.cursor_pos_index+index_move])
- ])
- filename, position = self.cursor_pos_history[self.cursor_pos_index]
- if not osp.isfile(filename):
- self.cursor_pos_history.pop(self.cursor_pos_index)
- if self.cursor_pos_index < old_index:
- old_index -= 1
- self.cursor_pos_index = old_index
- else:
- self.load(filename)
- editor = self.get_current_editor()
- if position < editor.document().characterCount():
- editor.set_cursor_position(position)
- self.__ignore_cursor_position = False
- self.update_cursorpos_actions()
-
- @Slot()
- def go_to_previous_cursor_position(self):
- self.__move_cursor_position(-1)
-
- @Slot()
- def go_to_next_cursor_position(self):
- self.__move_cursor_position(1)
-
- @Slot()
- def go_to_line(self, line=None):
- """Open 'go to line' dialog"""
- editorstack = self.get_current_editorstack()
- if editorstack is not None:
- editorstack.go_to_line(line)
-
- @Slot()
- def set_or_clear_breakpoint(self):
- """Set/Clear breakpoint"""
- editorstack = self.get_current_editorstack()
- if editorstack is not None:
- editorstack.set_or_clear_breakpoint()
-
- @Slot()
- def set_or_edit_conditional_breakpoint(self):
- """Set/Edit conditional breakpoint"""
- editorstack = self.get_current_editorstack()
- if editorstack is not None:
- editorstack.set_or_edit_conditional_breakpoint()
-
- @Slot()
- def clear_all_breakpoints(self):
- """Clear breakpoints in all files"""
- clear_all_breakpoints()
- self.breakpoints_saved.emit()
- editorstack = self.get_current_editorstack()
- if editorstack is not None:
- for data in editorstack.data:
- data.editor.clear_breakpoints()
- self.refresh_plugin()
-
- def clear_breakpoint(self, filename, lineno):
- """Remove a single breakpoint"""
- clear_breakpoint(filename, lineno)
- self.breakpoints_saved.emit()
- editorstack = self.get_current_editorstack()
- if editorstack is not None:
- index = self.is_file_opened(filename)
- if index is not None:
- editorstack.data[index].editor.add_remove_breakpoint(lineno)
-
- def debug_command(self, command):
- """Debug actions"""
- self.main.ipyconsole.write_to_stdin(command)
- focus_widget = self.main.ipyconsole.get_focus_widget()
- if focus_widget:
- focus_widget.setFocus()
-
- #------ Run Python script
- @Slot()
- def edit_run_configurations(self):
- dialog = RunConfigDialog(self)
- dialog.size_change.connect(lambda s: self.set_dialog_size(s))
- if self.dialog_size is not None:
- dialog.resize(self.dialog_size)
- fname = osp.abspath(self.get_current_filename())
- dialog.setup(fname)
- if dialog.exec_():
- fname = dialog.file_to_run
- if fname is not None:
- self.load(fname)
- self.run_file()
-
- @Slot()
- def run_file(self, debug=False):
- """Run script inside current interpreter or in a new one"""
- editorstack = self.get_current_editorstack()
- if editorstack.save():
- editor = self.get_current_editor()
- fname = osp.abspath(self.get_current_filename())
-
- # Escape single and double quotes in fname (Fixes Issue 2158)
- fname = fname.replace("'", r"\'")
- fname = fname.replace('"', r'\"')
-
- runconf = get_run_configuration(fname)
- if runconf is None:
- dialog = RunConfigOneDialog(self)
- dialog.size_change.connect(lambda s: self.set_dialog_size(s))
- if self.dialog_size is not None:
- dialog.resize(self.dialog_size)
- dialog.setup(fname)
- if CONF.get('run', 'open_at_least_once',
- not running_under_pytest()):
- # Open Run Config dialog at least once: the first time
- # a script is ever run in Spyder, so that the user may
- # see it at least once and be conscious that it exists
- show_dlg = True
- CONF.set('run', 'open_at_least_once', False)
- else:
- # Open Run Config dialog only
- # if ALWAYS_OPEN_FIRST_RUN_OPTION option is enabled
- show_dlg = CONF.get('run', ALWAYS_OPEN_FIRST_RUN_OPTION)
- if show_dlg and not dialog.exec_():
- return
- runconf = dialog.get_configuration()
-
- args = runconf.get_arguments()
- python_args = runconf.get_python_arguments()
- interact = runconf.interact
- post_mortem = runconf.post_mortem
- current = runconf.current
- systerm = runconf.systerm
- clear_namespace = runconf.clear_namespace
-
- if runconf.file_dir:
- wdir = osp.dirname(fname)
- elif runconf.cw_dir:
- wdir = ''
- elif osp.isdir(runconf.dir):
- wdir = runconf.dir
- else:
- wdir = ''
-
- python = True # Note: in the future, it may be useful to run
- # something in a terminal instead of a Python interp.
- self.__last_ec_exec = (fname, wdir, args, interact, debug,
- python, python_args, current, systerm,
- post_mortem, clear_namespace)
- self.re_run_file()
- if not interact and not debug:
- # If external console dockwidget is hidden, it will be
- # raised in top-level and so focus will be given to the
- # current external shell automatically
- # (see SpyderPluginWidget.visibility_changed method)
- editor.setFocus()
-
- def set_dialog_size(self, size):
- self.dialog_size = size
-
- @Slot()
- def debug_file(self):
- """Debug current script"""
- self.run_file(debug=True)
-
- @Slot()
- def re_run_file(self):
- """Re-run last script"""
- if self.get_option('save_all_before_run'):
- self.save_all()
- if self.__last_ec_exec is None:
- return
- (fname, wdir, args, interact, debug,
- python, python_args, current, systerm,
- post_mortem, clear_namespace) = self.__last_ec_exec
- if not systerm:
- self.run_in_current_ipyclient.emit(fname, wdir, args,
- debug, post_mortem,
- current, clear_namespace)
- else:
- self.main.open_external_console(fname, wdir, args, interact,
- debug, python, python_args,
- systerm, post_mortem)
-
- @Slot()
- def run_selection(self):
- """Run selection or current line in external console"""
- editorstack = self.get_current_editorstack()
- editorstack.run_selection()
-
- @Slot()
- def run_cell(self):
- """Run current cell"""
- editorstack = self.get_current_editorstack()
- editorstack.run_cell()
-
- @Slot()
- def run_cell_and_advance(self):
- """Run current cell and advance to the next one"""
- editorstack = self.get_current_editorstack()
- editorstack.run_cell_and_advance()
-
- @Slot()
- def re_run_last_cell(self):
- """Run last executed cell."""
- editorstack = self.get_current_editorstack()
- editorstack.re_run_last_cell()
-
- #------ Zoom in/out/reset
- def zoom(self, factor):
- """Zoom in/out/reset"""
- editor = self.get_current_editorstack().get_current_editor()
- if factor == 0:
- font = self.get_plugin_font()
- editor.set_font(font)
- else:
- font = editor.font()
- size = font.pointSize() + factor
- if size > 0:
- font.setPointSize(size)
- editor.set_font(font)
- editor.update_tab_stop_width_spaces()
-
- #------ Options
- def apply_plugin_settings(self, options):
- """Apply configuration file's plugin settings"""
- if self.editorstacks is not None:
- # --- syntax highlight and text rendering settings
- color_scheme_n = 'color_scheme_name'
- color_scheme_o = self.get_color_scheme()
- currentline_n = 'highlight_current_line'
- currentline_o = self.get_option(currentline_n)
- currentcell_n = 'highlight_current_cell'
- currentcell_o = self.get_option(currentcell_n)
- occurrence_n = 'occurrence_highlighting'
- occurrence_o = self.get_option(occurrence_n)
- occurrence_timeout_n = 'occurrence_highlighting/timeout'
- occurrence_timeout_o = self.get_option(occurrence_timeout_n)
- focus_to_editor_n = 'focus_to_editor'
- focus_to_editor_o = self.get_option(focus_to_editor_n)
-
- for editorstack in self.editorstacks:
- if color_scheme_n in options:
- editorstack.set_color_scheme(color_scheme_o)
- if currentline_n in options:
- editorstack.set_highlight_current_line_enabled(
- currentline_o)
- if currentcell_n in options:
- editorstack.set_highlight_current_cell_enabled(
- currentcell_o)
- if occurrence_n in options:
- editorstack.set_occurrence_highlighting_enabled(occurrence_o)
- if occurrence_timeout_n in options:
- editorstack.set_occurrence_highlighting_timeout(
- occurrence_timeout_o)
- if focus_to_editor_n in options:
- editorstack.set_focus_to_editor(focus_to_editor_o)
-
- # --- everything else
- tabbar_n = 'show_tab_bar'
- tabbar_o = self.get_option(tabbar_n)
- classfuncdropdown_n = 'show_class_func_dropdown'
- classfuncdropdown_o = self.get_option(classfuncdropdown_n)
- linenb_n = 'line_numbers'
- linenb_o = self.get_option(linenb_n)
- blanks_n = 'blank_spaces'
- blanks_o = self.get_option(blanks_n)
- scrollpastend_n = 'scroll_past_end'
- scrollpastend_o = self.get_option(scrollpastend_n)
- edgeline_n = 'edge_line'
- edgeline_o = self.get_option(edgeline_n)
- edgelinecols_n = 'edge_line_columns'
- edgelinecols_o = self.get_option(edgelinecols_n)
- wrap_n = 'wrap'
- wrap_o = self.get_option(wrap_n)
- indentguides_n = 'indent_guides'
- indentguides_o = self.get_option(indentguides_n)
- tabindent_n = 'tab_always_indent'
- tabindent_o = self.get_option(tabindent_n)
- ibackspace_n = 'intelligent_backspace'
- ibackspace_o = self.get_option(ibackspace_n)
- removetrail_n = 'always_remove_trailing_spaces'
- removetrail_o = self.get_option(removetrail_n)
- converteol_n = 'convert_eol_on_save'
- converteol_o = self.get_option(converteol_n)
- converteolto_n = 'convert_eol_on_save_to'
- converteolto_o = self.get_option(converteolto_n)
- autocomp_n = 'codecompletion/auto'
- autocomp_o = self.get_option(autocomp_n)
- case_comp_n = 'codecompletion/case_sensitive'
- case_comp_o = self.get_option(case_comp_n)
- enter_key_n = 'codecompletion/enter_key'
- enter_key_o = self.get_option(enter_key_n)
- calltips_n = 'calltips'
- calltips_o = self.get_option(calltips_n)
- gotodef_n = 'go_to_definition'
- gotodef_o = self.get_option(gotodef_n)
- closepar_n = 'close_parentheses'
- closepar_o = self.get_option(closepar_n)
- close_quotes_n = 'close_quotes'
- close_quotes_o = self.get_option(close_quotes_n)
- add_colons_n = 'add_colons'
- add_colons_o = self.get_option(add_colons_n)
- autounindent_n = 'auto_unindent'
- autounindent_o = self.get_option(autounindent_n)
- indent_chars_n = 'indent_chars'
- indent_chars_o = self.get_option(indent_chars_n)
- tab_stop_width_spaces_n = 'tab_stop_width_spaces'
- tab_stop_width_spaces_o = self.get_option(tab_stop_width_spaces_n)
- help_n = 'connect_to_oi'
- help_o = CONF.get('help', 'connect/editor')
- todo_n = 'todo_list'
- todo_o = self.get_option(todo_n)
- pyflakes_n = 'code_analysis/pyflakes'
- pyflakes_o = self.get_option(pyflakes_n)
- pep8_n = 'code_analysis/pep8'
- pep8_o = self.get_option(pep8_n)
- rt_analysis_n = 'realtime_analysis'
- rt_analysis_o = self.get_option(rt_analysis_n)
- rta_timeout_n = 'realtime_analysis/timeout'
- rta_timeout_o = self.get_option(rta_timeout_n)
-
- finfo = self.get_current_finfo()
-
-
- for editorstack in self.editorstacks:
- if tabbar_n in options:
- editorstack.set_tabbar_visible(tabbar_o)
- if linenb_n in options:
- editorstack.set_linenumbers_enabled(linenb_o,
- current_finfo=finfo)
- if edgeline_n in options:
- editorstack.set_edgeline_enabled(edgeline_o)
- if edgelinecols_n in options:
- editorstack.set_edgeline_columns(edgelinecols_o)
- if wrap_n in options:
- editorstack.set_wrap_enabled(wrap_o)
- if tabindent_n in options:
- editorstack.set_tabmode_enabled(tabindent_o)
- if ibackspace_n in options:
- editorstack.set_intelligent_backspace_enabled(ibackspace_o)
- if removetrail_n in options:
- editorstack.set_always_remove_trailing_spaces(removetrail_o)
- if converteol_n in options:
- editorstack.set_convert_eol_on_save(converteol_o)
- if converteolto_n in options:
- editorstack.set_convert_eol_on_save_to(converteolto_o)
- if autocomp_n in options:
- editorstack.set_codecompletion_auto_enabled(autocomp_o)
- if case_comp_n in options:
- editorstack.set_codecompletion_case_enabled(case_comp_o)
- if enter_key_n in options:
- editorstack.set_codecompletion_enter_enabled(enter_key_o)
- if calltips_n in options:
- editorstack.set_calltips_enabled(calltips_o)
- if gotodef_n in options:
- editorstack.set_go_to_definition_enabled(gotodef_o)
- if closepar_n in options:
- editorstack.set_close_parentheses_enabled(closepar_o)
- if close_quotes_n in options:
- editorstack.set_close_quotes_enabled(close_quotes_o)
- if add_colons_n in options:
- editorstack.set_add_colons_enabled(add_colons_o)
- if autounindent_n in options:
- editorstack.set_auto_unindent_enabled(autounindent_o)
- if indent_chars_n in options:
- editorstack.set_indent_chars(indent_chars_o)
- if tab_stop_width_spaces_n in options:
- editorstack.set_tab_stop_width_spaces(tab_stop_width_spaces_o)
- if help_n in options:
- editorstack.set_help_enabled(help_o)
- if todo_n in options:
- editorstack.set_todolist_enabled(todo_o,
- current_finfo=finfo)
- if pyflakes_n in options:
- editorstack.set_pyflakes_enabled(pyflakes_o,
- current_finfo=finfo)
- if pep8_n in options:
- editorstack.set_pep8_enabled(pep8_o, current_finfo=finfo)
- if rt_analysis_n in options:
- editorstack.set_realtime_analysis_enabled(rt_analysis_o)
- if rta_timeout_n in options:
- editorstack.set_realtime_analysis_timeout(rta_timeout_o)
-
- for name, action in self.checkable_actions.items():
- if name in options:
- state = self.get_option(name)
- action.setChecked(state)
- action.trigger()
- # We must update the current editor after the others:
- # (otherwise, code analysis buttons state would correspond to the
- # last editor instead of showing the one of the current editor)
- if finfo is not None:
- if todo_n in options and todo_o:
- finfo.run_todo_finder()
- if pyflakes_n in options or pep8_n in options:
- finfo.run_code_analysis(pyflakes_o, pep8_o)
-
- # --- Open files
- def get_open_filenames(self):
- """Get the list of open files in the current stack"""
- editorstack = self.editorstacks[0]
- filenames = []
- filenames += [finfo.filename for finfo in editorstack.data]
- return filenames
-
- def set_open_filenames(self):
- """
- Set the recent opened files on editor based on active project.
-
- If no project is active, then editor filenames are saved, otherwise
- the opened filenames are stored in the project config info.
- """
- if self.projects is not None:
- if not self.projects.get_active_project():
- filenames = self.get_open_filenames()
- self.set_option('filenames', filenames)
-
- def setup_open_files(self):
- """Open the list of saved files per project"""
- self.set_create_new_file_if_empty(False)
- active_project_path = None
- if self.projects is not None:
- active_project_path = self.projects.get_active_project_path()
-
- if active_project_path:
- filenames = self.projects.get_project_filenames()
- else:
- filenames = self.get_option('filenames', default=[])
- self.close_all_files()
-
- if filenames and any([osp.isfile(f) for f in filenames]):
- filenames = self.reorder_filenames(filenames)
- layout = self.get_option('layout_settings', None)
- is_vertical, cfname, clines = layout.get('splitsettings')[0]
- self.load(filenames, goto=clines)
- if layout is not None:
- self.editorsplitter.set_layout_settings(layout,
- dont_goto=filenames[0])
- win_layout = self.get_option('windows_layout_settings', None)
- if win_layout:
- for layout_settings in win_layout:
- self.editorwindows_to_be_created.append(layout_settings)
- self.set_last_focus_editorstack(self, self.editorstacks[0])
- else:
- self.__load_temp_file()
- self.set_create_new_file_if_empty(True)
-
- def reorder_filenames(self, filenames):
- """Take the last session filenames and put the last open on first.
-
- It takes a list of filenames and using the current filename from the
- layout settings, sets the one that had focused last in the position 0.
- It also reorders the current lines for each file (supposing that they
- are in the same order as the filenames) and sets them back in the
- layout settings.
- """
- layout = self.get_option('layout_settings', None)
- if layout is None:
- return filenames
- splitsettings = layout.get('splitsettings')
- index_first_file = 0
- reordered_splitsettings = []
- for index, (is_vertical, cfname, clines) in enumerate(splitsettings):
- #the first element of filenames is now the one that last had focus
- if index == 0:
- if cfname in filenames:
- index_first_file = filenames.index(cfname)
- filenames.pop(index_first_file)
- filenames.insert(0, cfname)
- clines_first_file = clines[index_first_file]
- clines.pop(index_first_file)
- clines.insert(0, clines_first_file)
- else:
- cfname = filenames[0]
- index_first_file = 0
- reordered_splitsettings.append((is_vertical, cfname, clines))
- layout['splitsettings'] = reordered_splitsettings
- self.set_option('layout_settings', layout)
- return filenames
-
- def save_open_files(self):
- """Save the list of open files"""
- self.set_option('filenames', self.get_open_filenames())
-
- def set_create_new_file_if_empty(self, value):
- """Change the value of create_new_file_if_empty"""
- for editorstack in self.editorstacks:
- editorstack.create_new_file_if_empty = value
diff --git a/spyder/plugins/editor/__init__.py b/spyder/plugins/editor/__init__.py
new file mode 100644
index 00000000000..837acce64e0
--- /dev/null
+++ b/spyder/plugins/editor/__init__.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+
+"""
+spyder.plugins.editor
+=====================
+
+Editor Plugin.
+"""
diff --git a/spyder/plugins/editor/api/__init__.py b/spyder/plugins/editor/api/__init__.py
new file mode 100644
index 00000000000..26667c893c4
--- /dev/null
+++ b/spyder/plugins/editor/api/__init__.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+
+"""
+spyder.plugins.editor.api
+=========================
+
+API to interact with some features of Editor and CodeEditor.
+"""
diff --git a/spyder/plugins/editor/api/decoration.py b/spyder/plugins/editor/api/decoration.py
new file mode 100644
index 00000000000..098dd2037c9
--- /dev/null
+++ b/spyder/plugins/editor/api/decoration.py
@@ -0,0 +1,231 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2013-2016 Colin Duquesnoy and others (see pyqode/AUTHORS.rst)
+# Copyright (c) 2016- Spyder Project Contributors (see AUTHORS.txt)
+#
+# Distributed under the terms of the MIT License
+# (see NOTICE.txt in the Spyder root directory for details)
+# -----------------------------------------------------------------------------
+
+"""
+This module contains the text decoration API.
+
+Adapted from pyqode/core/api/decoration.py of the
+`PyQode project `_.
+Original file:
+
+"""
+
+# Third party imports
+from qtpy.QtWidgets import QTextEdit
+from qtpy.QtCore import QObject, Signal, Qt
+from qtpy.QtGui import (QTextCursor, QFont, QPen, QColor, QTextFormat,
+ QTextCharFormat)
+
+
+# DRAW_ORDERS are used for make some decorations appear in top of others,
+# and avoid a decoration from overlapping/hiding other decorations.
+#
+# For example, codefolding will appear in front of current cell but behind
+# other decorations.
+#
+# NOTE: If two decorations have the same draw_order smaller decoration will
+# appear in front of the other.
+
+DRAW_ORDERS = {'on_bottom': 0,
+ 'current_cell': 1,
+ 'codefolding': 2,
+ 'current_line': 3,
+ 'on_top': 4}
+
+
+class TextDecoration(QTextEdit.ExtraSelection):
+ """
+ Helper class to quickly create a text decoration.
+
+ The text decoration is an utility class that adds a few utility methods to
+ QTextEdit.ExtraSelection.
+
+ In addition to the helper methods, a tooltip can be added to a decoration.
+ (useful for errors markers and so on...)
+
+ Text decoration expose a **clicked** signal stored in a separate QObject:
+ :attr:`pyqode.core.api.TextDecoration.Signals`
+
+ .. code-block:: python
+
+ deco = TextDecoration()
+ deco.signals.clicked.connect(a_slot)
+
+ def a_slot(decoration):
+ print(decoration) # spyder: test-skip
+ """
+ class Signals(QObject):
+ """
+ Holds the signals for a TextDecoration (since we cannot make it a
+ QObject, we need to store its signals in an external QObject).
+ """
+ #: Signal emitted when a TextDecoration has been clicked.
+ clicked = Signal(object)
+
+ def __init__(self, cursor_or_bloc_or_doc, start_pos=None, end_pos=None,
+ start_line=None, end_line=None, draw_order=0, tooltip=None,
+ full_width=False, font=None):
+ """
+ Creates a text decoration.
+
+ .. note:: start_pos/end_pos and start_line/end_line pairs let you
+ easily specify the selected text. You should use one pair or the
+ other or they will conflict between each others. If you don't
+ specify any values, the selection will be based on the cursor.
+
+ :param cursor_or_bloc_or_doc: Reference to a valid
+ QTextCursor/QTextBlock/QTextDocument
+ :param start_pos: Selection start position
+ :param end_pos: Selection end position
+ :param start_line: Selection start line.
+ :param end_line: Selection end line.
+ :param draw_order: The draw order of the selection, highest values will
+ appear on top of the lowest values.
+ :param tooltip: An optional tooltips that will be automatically shown
+ when the mouse cursor hover the decoration.
+ :param full_width: True to select the full line width.
+
+ .. note:: Use the cursor selection if startPos and endPos are none.
+ """
+ super(TextDecoration, self).__init__()
+ self.signals = self.Signals()
+ self.draw_order = draw_order
+ self.tooltip = tooltip
+ self.cursor = QTextCursor(cursor_or_bloc_or_doc)
+ if full_width:
+ self.set_full_width(full_width)
+ if start_pos is not None:
+ self.cursor.setPosition(start_pos)
+ if end_pos is not None:
+ self.cursor.setPosition(end_pos, QTextCursor.KeepAnchor)
+ if start_line is not None:
+ self.cursor.movePosition(self.cursor.Start, self.cursor.MoveAnchor)
+ self.cursor.movePosition(self.cursor.Down, self.cursor.MoveAnchor,
+ start_line)
+ if end_line is not None:
+ self.cursor.movePosition(self.cursor.Down, self.cursor.KeepAnchor,
+ end_line - start_line)
+ if font is not None:
+ self.format.setFont(font)
+
+ def contains_cursor(self, cursor):
+ """
+ Checks if the textCursor is in the decoration.
+
+ :param cursor: The text cursor to test
+ :type cursor: QtGui.QTextCursor
+
+ :returns: True if the cursor is over the selection
+ """
+ start = self.cursor.selectionStart()
+ end = self.cursor.selectionEnd()
+ if cursor.atBlockEnd():
+ end -= 1
+ return start <= cursor.position() <= end
+
+ def set_as_bold(self):
+ """Uses bold text."""
+ self.format.setFontWeight(QFont.Bold)
+
+ def set_foreground(self, color):
+ """Sets the foreground color.
+ :param color: Color
+ :type color: QtGui.QColor
+ """
+ self.format.setForeground(color)
+
+ def set_background(self, brush):
+ """
+ Sets the background brush.
+
+ :param brush: Brush
+ :type brush: QtGui.QBrush
+ """
+ self.format.setBackground(brush)
+
+ def set_outline(self, color):
+ """
+ Uses an outline rectangle.
+
+ :param color: Color of the outline rect
+ :type color: QtGui.QColor
+ """
+ self.format.setProperty(QTextFormat.OutlinePen,
+ QPen(color))
+
+ def select_line(self):
+ """
+ Select the entire line but starts at the first non whitespace character
+ and stops at the non-whitespace character.
+ :return:
+ """
+ self.cursor.movePosition(self.cursor.StartOfBlock)
+ text = self.cursor.block().text()
+ lindent = len(text) - len(text.lstrip())
+ self.cursor.setPosition(self.cursor.block().position() + lindent)
+ self.cursor.movePosition(self.cursor.EndOfBlock,
+ self.cursor.KeepAnchor)
+
+ def set_full_width(self, flag=True, clear=True):
+ """
+ Enables FullWidthSelection (the selection does not stops at after the
+ character instead it goes up to the right side of the widget).
+
+ :param flag: True to use full width selection.
+ :type flag: bool
+
+ :param clear: True to clear any previous selection. Default is True.
+ :type clear: bool
+ """
+ if clear:
+ self.cursor.clearSelection()
+ self.format.setProperty(QTextFormat.FullWidthSelection, flag)
+
+ def set_as_underlined(self, color=Qt.blue):
+ """
+ Underlines the text.
+
+ :param color: underline color.
+ """
+ self.format.setUnderlineStyle(
+ QTextCharFormat.SingleUnderline)
+ self.format.setUnderlineColor(color)
+
+ def set_as_spell_check(self, color=Qt.blue):
+ """
+ Underlines text as a spellcheck error.
+
+ :param color: Underline color
+ :type color: QtGui.QColor
+ """
+ self.format.setUnderlineStyle(
+ QTextCharFormat.SpellCheckUnderline)
+ self.format.setUnderlineColor(color)
+
+ def set_as_error(self, color=Qt.red):
+ """
+ Highlights text as a syntax error.
+
+ :param color: Underline color
+ :type color: QtGui.QColor
+ """
+ self.format.setUnderlineStyle(
+ QTextCharFormat.WaveUnderline)
+ self.format.setUnderlineColor(color)
+
+ def set_as_warning(self, color=QColor("orange")):
+ """
+ Highlights text as a syntax warning.
+
+ :param color: Underline color
+ :type color: QtGui.QColor
+ """
+ self.format.setUnderlineStyle(
+ QTextCharFormat.WaveUnderline)
+ self.format.setUnderlineColor(color)
diff --git a/spyder/plugins/editor/api/folding.py b/spyder/plugins/editor/api/folding.py
new file mode 100644
index 00000000000..f6b7d6d6aa9
--- /dev/null
+++ b/spyder/plugins/editor/api/folding.py
@@ -0,0 +1,165 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2013-2016 Colin Duquesnoy and others (see pyqode/AUTHORS.rst)
+# Copyright (c) 2016- Spyder Project Contributors (see AUTHORS.txt)
+#
+# Distributed under the terms of the MIT License
+# (see NOTICE.txt in the Spyder root directory for details)
+# -----------------------------------------------------------------------------
+
+"""
+This module contains the code folding API.
+
+Adapted from pyqode/core/api/folding.py of the
+`PyQode project `_.
+Original file:
+
+"""
+
+# Future imports
+from __future__ import print_function
+
+# Standard library imports
+import sys
+
+# Local imports
+from spyder.plugins.editor.utils.editor import TextBlockHelper
+
+
+def print_tree(editor, file=sys.stdout, print_blocks=False, return_list=False):
+ """
+ Prints the editor fold tree to stdout, for debugging purpose.
+
+ :param editor: CodeEditor instance.
+ :param file: file handle where the tree will be printed. Default is stdout.
+ :param print_blocks: True to print all blocks, False to only print blocks
+ that are fold triggers
+ """
+ output_list = []
+
+ block = editor.document().firstBlock()
+ while block.isValid():
+ trigger = TextBlockHelper().is_fold_trigger(block)
+ trigger_state = TextBlockHelper().is_collapsed(block)
+ lvl = TextBlockHelper().get_fold_lvl(block)
+ visible = 'V' if block.isVisible() else 'I'
+ if trigger:
+ trigger = '+' if trigger_state else '-'
+ if return_list:
+ output_list.append([block.blockNumber() + 1, lvl, visible])
+ else:
+ print('l%d:%s%s%s' %
+ (block.blockNumber() + 1, lvl, trigger, visible),
+ file=file)
+ elif print_blocks:
+ if return_list:
+ output_list.append([block.blockNumber() + 1, lvl, visible])
+ else:
+ print('l%d:%s%s' %
+ (block.blockNumber() + 1, lvl, visible), file=file)
+ block = block.next()
+
+ if return_list:
+ return output_list
+
+class FoldDetector(object):
+ """
+ Base class for fold detectors.
+
+ A fold detector takes care of detecting the text blocks fold levels that
+ are used by the FoldingPanel to render the document outline.
+
+ To use a FoldDetector, simply set it on a syntax_highlighter::
+
+ editor.syntax_highlighter.fold_detector = my_fold_detector
+
+ Some implementations of fold detectors can be found in:
+ ``spyder/widgets/sourcecode/folding.py``.
+ """
+ @property
+ def editor(self):
+ if self._editor:
+ return self._editor()
+ return None
+
+ def __init__(self):
+ # Reference to the parent editor, automatically set by the syntax
+ # highlighter before process any block.
+ self._editor = None
+ # Fold level limit, any level greater or equal is skipped.
+ # Default is sys.maxsize (i.e. all levels are accepted)
+ self.limit = sys.maxsize
+
+ def process_block(self, current_block, previous_block, text):
+ """
+ Processes a block and setup its folding info.
+
+ This method call ``detect_fold_level`` and handles most of the tricky
+ corner cases so that all you have to do is focus on getting the proper
+ fold level foreach meaningful block, skipping the blank ones.
+
+ :param current_block: current block to process
+ :param previous_block: previous block
+ :param text: current block text
+ """
+ prev_fold_level = TextBlockHelper.get_fold_lvl(previous_block)
+ if text.strip() == '' or self.editor.is_comment(current_block):
+ # blank or comment line always have the same level
+ # as the previous line
+ fold_level = prev_fold_level
+ else:
+ fold_level = self.detect_fold_level(
+ previous_block, current_block)
+ if fold_level > self.limit:
+ fold_level = self.limit
+
+ prev_fold_level = TextBlockHelper.get_fold_lvl(previous_block)
+
+ if fold_level > prev_fold_level:
+ # apply on previous blank or comment lines
+ block = current_block.previous()
+ while block.isValid() and (block.text().strip() == ''
+ or self.editor.is_comment(block)):
+ TextBlockHelper.set_fold_lvl(block, fold_level)
+ block = block.previous()
+ TextBlockHelper.set_fold_trigger(
+ block, True)
+
+ # update block fold level
+ if text.strip() and not self.editor.is_comment(previous_block):
+ TextBlockHelper.set_fold_trigger(
+ previous_block, fold_level > prev_fold_level)
+ TextBlockHelper.set_fold_lvl(current_block, fold_level)
+
+ # user pressed enter at the beginning of a fold trigger line
+ # the previous blank or comment line will keep the trigger state
+ # and the new line (which actually contains the trigger) must use
+ # the prev state (and prev state must then be reset).
+ prev = current_block.previous() # real prev block (may be blank)
+ if (prev and prev.isValid() and
+ (prev.text().strip() == '' or self.editor.is_comment(prev)) and
+ TextBlockHelper.is_fold_trigger(prev)):
+ # prev line has the correct trigger fold state
+ TextBlockHelper.set_collapsed(
+ current_block, TextBlockHelper.is_collapsed(
+ prev))
+ # make empty or comment line not a trigger
+ TextBlockHelper.set_fold_trigger(prev, False)
+ TextBlockHelper.set_collapsed(prev, False)
+
+ def detect_fold_level(self, prev_block, block):
+ """
+ Detects the block fold level.
+
+ The default implementation is based on the block **indentation**.
+
+ .. note:: Blocks fold level must be contiguous, there cannot be
+ a difference greater than 1 between two successive block fold
+ levels.
+
+ :param prev_block: first previous **non-blank** block or None if this
+ is the first line of the document
+ :param block: The block to process.
+ :return: Fold level
+ """
+ raise NotImplementedError
diff --git a/spyder/plugins/editor/confpage.py b/spyder/plugins/editor/confpage.py
new file mode 100644
index 00000000000..73695f63dcc
--- /dev/null
+++ b/spyder/plugins/editor/confpage.py
@@ -0,0 +1,324 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Editor config page."""
+
+from qtpy.QtCore import Qt
+from qtpy.QtWidgets import (QGridLayout, QGroupBox, QHBoxLayout, QLabel,
+ QTabWidget, QVBoxLayout, QWidget)
+
+from spyder.api.preferences import PluginConfigPage
+from spyder.config.base import _
+from spyder.config.main import CONF
+import spyder.utils.icon_manager as ima
+
+
+NUMPYDOC = "https://numpydoc.readthedocs.io/en/latest/format.html"
+GOOGLEDOC = "https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html"
+DOCSTRING_SHORTCUT = CONF.get('shortcuts', 'editor/docstring')
+
+
+class EditorConfigPage(PluginConfigPage):
+ def get_name(self):
+ return _("Editor")
+
+ def get_icon(self):
+ return ima.icon('edit')
+
+ def setup_page(self):
+ newcb = self.create_checkbox
+
+ # --- Display tab ---
+ showtabbar_box = newcb(_("Show tab bar"), 'show_tab_bar')
+ showclassfuncdropdown_box = newcb(
+ _("Show selector for classes and functions"),
+ 'show_class_func_dropdown')
+ showindentguides_box = newcb(_("Show indent guides"),
+ 'indent_guides')
+ linenumbers_box = newcb(_("Show line numbers"), 'line_numbers')
+ blanks_box = newcb(_("Show blank spaces"), 'blank_spaces')
+ currentline_box = newcb(_("Highlight current line"),
+ 'highlight_current_line')
+ currentcell_box = newcb(_("Highlight current cell"),
+ 'highlight_current_cell')
+ wrap_mode_box = newcb(_("Wrap lines"), 'wrap')
+ scroll_past_end_box = newcb(_("Scroll past the end"),
+ 'scroll_past_end')
+
+ edgeline_box = newcb(_("Show vertical lines at"), 'edge_line')
+ edgeline_edit = self.create_lineedit(
+ "",
+ 'edge_line_columns',
+ tip=("Enter values separated by commas"),
+ alignment=Qt.Horizontal,
+ regex="[0-9]+(,[0-9]+)*")
+ edgeline_edit_label = QLabel(_("characters"))
+ edgeline_box.toggled.connect(edgeline_edit.setEnabled)
+ edgeline_box.toggled.connect(edgeline_edit_label.setEnabled)
+ edgeline_edit.setEnabled(self.get_option('edge_line'))
+ edgeline_edit_label.setEnabled(self.get_option('edge_line'))
+
+ occurrence_box = newcb(_("Highlight occurrences after"),
+ 'occurrence_highlighting')
+ occurrence_spin = self.create_spinbox(
+ "", _(" ms"),
+ 'occurrence_highlighting/timeout',
+ min_=100, max_=1000000, step=100)
+ occurrence_box.toggled.connect(occurrence_spin.spinbox.setEnabled)
+ occurrence_box.toggled.connect(occurrence_spin.slabel.setEnabled)
+ occurrence_spin.spinbox.setEnabled(
+ self.get_option('occurrence_highlighting'))
+ occurrence_spin.slabel.setEnabled(
+ self.get_option('occurrence_highlighting'))
+
+ display_g_layout = QGridLayout()
+ display_g_layout.addWidget(edgeline_box, 0, 0)
+ display_g_layout.addWidget(edgeline_edit.textbox, 0, 1)
+ display_g_layout.addWidget(edgeline_edit_label, 0, 2)
+ display_g_layout.addWidget(occurrence_box, 1, 0)
+ display_g_layout.addWidget(occurrence_spin.spinbox, 1, 1)
+ display_g_layout.addWidget(occurrence_spin.slabel, 1, 2)
+
+ display_h_layout = QHBoxLayout()
+ display_h_layout.addLayout(display_g_layout)
+ display_h_layout.addStretch(1)
+
+ display_layout = QVBoxLayout()
+ display_layout.addWidget(showtabbar_box)
+ display_layout.addWidget(showclassfuncdropdown_box)
+ display_layout.addWidget(showindentguides_box)
+ display_layout.addWidget(linenumbers_box)
+ display_layout.addWidget(blanks_box)
+ display_layout.addWidget(currentline_box)
+ display_layout.addWidget(currentcell_box)
+ display_layout.addWidget(wrap_mode_box)
+ display_layout.addWidget(scroll_past_end_box)
+ display_layout.addLayout(display_h_layout)
+
+ display_widget = QWidget()
+ display_widget.setLayout(display_layout)
+
+ # --- Source code tab ---
+ closepar_box = newcb(
+ _("Automatic insertion of parentheses, braces and brackets"),
+ 'close_parentheses')
+ close_quotes_box = newcb(
+ _("Automatic insertion of closing quotes"),
+ 'close_quotes')
+ add_colons_box = newcb(
+ _("Automatic insertion of colons after 'for', 'if', 'def', etc"),
+ 'add_colons')
+ autounindent_box = newcb(
+ _("Automatic indentation after 'else', 'elif', etc."),
+ 'auto_unindent')
+ tab_mode_box = newcb(
+ _("Tab always indent"),
+ 'tab_always_indent', default=False,
+ tip=_("If enabled, pressing Tab will always indent,\n"
+ "even when the cursor is not at the beginning\n"
+ "of a line (when this option is enabled, code\n"
+ "completion may be triggered using the alternate\n"
+ "shortcut: Ctrl+Space)"))
+ strip_mode_box = newcb(
+ _("Automatically strip trailing spaces on changed lines"),
+ 'strip_trailing_spaces_on_modify', default=True,
+ tip=_("If enabled, modified lines of code (excluding strings)\n"
+ "will have their trailing whitespace stripped when leaving them.\n"
+ "If disabled, only whitespace added by Spyder will be stripped."))
+ ibackspace_box = newcb(
+ _("Intelligent backspace"),
+ 'intelligent_backspace',
+ default=True)
+ removetrail_box = newcb(
+ _("Automatically remove trailing spaces when saving files"),
+ 'always_remove_trailing_spaces',
+ default=False)
+
+ indent_chars_box = self.create_combobox(
+ _("Indentation characters: "),
+ ((_("2 spaces"), '* *'),
+ (_("3 spaces"), '* *'),
+ (_("4 spaces"), '* *'),
+ (_("5 spaces"), '* *'),
+ (_("6 spaces"), '* *'),
+ (_("7 spaces"), '* *'),
+ (_("8 spaces"), '* *'),
+ (_("Tabulations"), '*\t*')),
+ 'indent_chars')
+ tabwidth_spin = self.create_spinbox(
+ _("Tab stop width:"),
+ _("spaces"),
+ 'tab_stop_width_spaces',
+ 4, 1, 8, 1)
+
+ def enable_tabwidth_spin(index):
+ if index == 7: # Tabulations
+ tabwidth_spin.plabel.setEnabled(True)
+ tabwidth_spin.spinbox.setEnabled(True)
+ else:
+ tabwidth_spin.plabel.setEnabled(False)
+ tabwidth_spin.spinbox.setEnabled(False)
+
+ indent_chars_box.combobox.currentIndexChanged.connect(
+ enable_tabwidth_spin)
+
+ indent_tab_grid_layout = QGridLayout()
+ indent_tab_grid_layout.addWidget(indent_chars_box.label, 0, 0)
+ indent_tab_grid_layout.addWidget(indent_chars_box.combobox, 0, 1)
+ indent_tab_grid_layout.addWidget(tabwidth_spin.plabel, 1, 0)
+ indent_tab_grid_layout.addWidget(tabwidth_spin.spinbox, 1, 1)
+ indent_tab_grid_layout.addWidget(tabwidth_spin.slabel, 1, 2)
+
+ indent_tab_layout = QHBoxLayout()
+ indent_tab_layout.addLayout(indent_tab_grid_layout)
+ indent_tab_layout.addStretch(1)
+
+ sourcecode_layout = QVBoxLayout()
+ sourcecode_layout.addWidget(closepar_box)
+ sourcecode_layout.addWidget(autounindent_box)
+ sourcecode_layout.addWidget(add_colons_box)
+ sourcecode_layout.addWidget(close_quotes_box)
+ sourcecode_layout.addWidget(tab_mode_box)
+ sourcecode_layout.addWidget(ibackspace_box)
+ sourcecode_layout.addWidget(removetrail_box)
+ sourcecode_layout.addWidget(strip_mode_box)
+ sourcecode_layout.addLayout(indent_tab_layout)
+
+ sourcecode_widget = QWidget()
+ sourcecode_widget.setLayout(sourcecode_layout)
+
+ # --- Run code tab ---
+ saveall_box = newcb(_("Save all files before running script"),
+ 'save_all_before_run')
+ focus_box = newcb(_("Maintain focus in the Editor after running cells "
+ "or selections"), 'focus_to_editor')
+ run_cell_box = newcb(_("Copy full cell contents to the console when "
+ "running code cells"), 'run_cell_copy')
+
+ run_layout = QVBoxLayout()
+ run_layout.addWidget(saveall_box)
+ run_layout.addWidget(focus_box)
+ run_layout.addWidget(run_cell_box)
+
+ run_widget = QWidget()
+ run_widget.setLayout(run_layout)
+
+ # --- Advanced tab ---
+ # -- Templates
+ template_btn = self.create_button(_("Edit template for new files"),
+ self.plugin.edit_template)
+
+ # -- Autosave
+ autosave_group = QGroupBox(_('Autosave'))
+ autosave_checkbox = newcb(
+ _('Automatically save a copy of files with unsaved changes'),
+ 'autosave_enabled')
+ autosave_spinbox = self.create_spinbox(
+ _('Autosave interval: '),
+ _('seconds'),
+ 'autosave_interval',
+ min_=1, max_=3600)
+ autosave_checkbox.toggled.connect(autosave_spinbox.setEnabled)
+
+ autosave_layout = QVBoxLayout()
+ autosave_layout.addWidget(autosave_checkbox)
+ autosave_layout.addWidget(autosave_spinbox)
+ autosave_group.setLayout(autosave_layout)
+
+ # -- Docstring
+ docstring_group = QGroupBox(_('Docstring type'))
+
+ numpy_url = "Numpy".format(NUMPYDOC)
+ googledoc_url = "Google".format(GOOGLEDOC)
+ docstring_label = QLabel(
+ _("Here you can select the type of docstrings ({} or {}) you "
+ "want the editor to automatically introduce when pressing "
+ "{} after a function/method/class "
+ "declaration.").format(
+ numpy_url, googledoc_url, DOCSTRING_SHORTCUT))
+ docstring_label.setOpenExternalLinks(True)
+ docstring_label.setWordWrap(True)
+
+ docstring_combo_choices = ((_("Numpy"), 'Numpydoc'),
+ (_("Google"), 'Googledoc'),)
+ docstring_combo = self.create_combobox(
+ "Type:",
+ docstring_combo_choices,
+ 'docstring_type')
+
+ docstring_layout = QVBoxLayout()
+ docstring_layout.addWidget(docstring_label)
+ docstring_layout.addWidget(docstring_combo)
+ docstring_group.setLayout(docstring_layout)
+
+ # -- Annotations
+ annotations_group = QGroupBox(_("Annotations"))
+ annotations_label = QLabel(
+ _("Display a marker to the left of line numbers when the "
+ "following annotations appear at the beginning of a comment: "
+ "TODO, FIXME, XXX, HINT, TIP, @todo, HACK, BUG, OPTIMIZE, "
+ "!!!, ???"))
+ annotations_label.setWordWrap(True)
+ todolist_box = newcb(
+ _("Display code annotations"),
+ 'todo_list')
+
+ annotations_layout = QVBoxLayout()
+ annotations_layout.addWidget(annotations_label)
+ annotations_layout.addWidget(todolist_box)
+ annotations_group.setLayout(annotations_layout)
+
+ # -- EOL
+ eol_group = QGroupBox(_("End-of-line characters"))
+ eol_label = QLabel(_("When opening a text file containing "
+ "mixed end-of-line characters (this may "
+ "raise syntax errors in the consoles "
+ "on Windows platforms), Spyder may fix the "
+ "file automatically."))
+ eol_label.setWordWrap(True)
+ check_eol_box = newcb(_("Fix automatically and show warning "
+ "message box"),
+ 'check_eol_chars', default=True)
+ convert_eol_on_save_box = newcb(_("On Save: convert EOL characters"
+ " to"),
+ 'convert_eol_on_save', default=False)
+ eol_combo_choices = ((_("LF (UNIX)"), 'LF'),
+ (_("CRLF (Windows)"), 'CRLF'),
+ (_("CR (Mac)"), 'CR'),
+ )
+ convert_eol_on_save_combo = self.create_combobox("",
+ eol_combo_choices,
+ ('convert_eol_on_'
+ 'save_to'),
+ )
+ convert_eol_on_save_box.toggled.connect(
+ convert_eol_on_save_combo.setEnabled)
+ convert_eol_on_save_combo.setEnabled(
+ self.get_option('convert_eol_on_save'))
+
+ eol_on_save_layout = QHBoxLayout()
+ eol_on_save_layout.addWidget(convert_eol_on_save_box)
+ eol_on_save_layout.addWidget(convert_eol_on_save_combo)
+
+ eol_layout = QVBoxLayout()
+ eol_layout.addWidget(eol_label)
+ eol_layout.addWidget(check_eol_box)
+ eol_layout.addLayout(eol_on_save_layout)
+ eol_group.setLayout(eol_layout)
+
+ # --- Tabs ---
+ tabs = QTabWidget()
+ tabs.addTab(self.create_tab(display_widget), _("Display"))
+ tabs.addTab(self.create_tab(sourcecode_widget), _("Source code"))
+ tabs.addTab(self.create_tab(run_widget), _('Run Code'))
+ tabs.addTab(self.create_tab(template_btn, autosave_group,
+ docstring_group, annotations_group,
+ eol_group),
+ _("Advanced settings"))
+
+ vlayout = QVBoxLayout()
+ vlayout.addWidget(tabs)
+ self.setLayout(vlayout)
diff --git a/spyder/plugins/editor/extensions/__init__.py b/spyder/plugins/editor/extensions/__init__.py
new file mode 100644
index 00000000000..72ba8f22d28
--- /dev/null
+++ b/spyder/plugins/editor/extensions/__init__.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+
+"""
+Editor Extensions classes and manager.
+"""
+
+from .closebrackets import CloseBracketsExtension
+from .closequotes import CloseQuotesExtension
+from .docstring import DocstringWriterExtension, QMenuOnlyForEnter
+from .manager import EditorExtensionsManager
diff --git a/spyder/plugins/editor/extensions/closebrackets.py b/spyder/plugins/editor/extensions/closebrackets.py
new file mode 100644
index 00000000000..2f26b2fae88
--- /dev/null
+++ b/spyder/plugins/editor/extensions/closebrackets.py
@@ -0,0 +1,115 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+"""This module contains the close quotes editor extension."""
+
+from qtpy.QtCore import Qt
+from qtpy.QtGui import QTextCursor
+
+from spyder.api.editorextension import EditorExtension
+
+
+class CloseBracketsExtension(EditorExtension):
+ """Editor Extension for insert brackets automatically."""
+ BRACKETS_LIST = ["(", ")", "{", "}", "[", "]"]
+ BRACKETS_KEYS = [Qt.Key_ParenLeft, Qt.Key_ParenRight,
+ Qt.Key_BraceLeft, Qt.Key_BraceRight,
+ Qt.Key_BracketLeft, Qt.Key_BracketRight]
+ BRACKETS_CHAR = dict(zip(BRACKETS_KEYS, BRACKETS_LIST))
+ BRACKETS_LEFT = dict(zip(BRACKETS_KEYS[::2], BRACKETS_LIST[::2]))
+ BRACKETS_RIGHT = dict(zip(BRACKETS_KEYS[1::2], BRACKETS_LIST[1::2]))
+ BRACKETS_PAIR = {Qt.Key_ParenLeft: "()", Qt.Key_ParenRight: "()",
+ Qt.Key_BraceLeft: "{}", Qt.Key_BraceRight: "{}",
+ Qt.Key_BracketLeft: "[]", Qt.Key_BracketRight: "[]"}
+
+ def on_state_changed(self, state):
+ """Connect/disconnect sig_key_pressed signal."""
+ if state:
+ self.editor.sig_key_pressed.connect(self._on_key_pressed)
+ else:
+ self.editor.sig_key_pressed.disconnect(self._on_key_pressed)
+
+ def _on_key_pressed(self, event):
+ if event.isAccepted():
+ return
+
+ key = event.key()
+ if key in self.BRACKETS_CHAR and self.enabled:
+ self.editor.completion_widget.hide()
+ self._autoinsert_brackets(key)
+ self.editor.document_did_change()
+ event.accept()
+
+ def unmatched_brackets_in_line(self, text, closing_brackets_type=None):
+ """
+ Checks if there is an unmatched brackets in the 'text'.
+
+ The brackets type can be general or specified by closing_brackets_type
+ (')', ']' or '}')
+ """
+ if closing_brackets_type is None:
+ opening_brackets = self.BRACKETS_LEFT.values()
+ closing_brackets = self.BRACKETS_RIGHT.values()
+ else:
+ closing_brackets = [closing_brackets_type]
+ opening_brackets = [{')': '(', '}': '{',
+ ']': '['}[closing_brackets_type]]
+ block = self.editor.textCursor().block()
+ line_pos = block.position()
+ for pos, char in enumerate(text):
+ if char in opening_brackets:
+ match = self.editor.find_brace_match(line_pos+pos, char,
+ forward=True)
+ if (match is None) or (match > line_pos+len(text)):
+ return True
+ if char in closing_brackets:
+ match = self.editor.find_brace_match(line_pos+pos, char,
+ forward=False)
+ if (match is None) or (match < line_pos):
+ return True
+ return False
+
+ def _autoinsert_brackets(self, key):
+ """Control automatic insertation of brackets in various situations."""
+ char = self.BRACKETS_CHAR[key]
+ pair = self.BRACKETS_PAIR[key]
+
+ line_text = self.editor.get_text('sol', 'eol')
+ line_to_cursor = self.editor.get_text('sol', 'cursor')
+ cursor = self.editor.textCursor()
+ trailing_text = self.editor.get_text('cursor', 'eol').strip()
+
+ if self.editor.has_selected_text():
+ text = self.editor.get_selected_text()
+ self.editor.insert_text("{0}{1}{2}".format(pair[0], text, pair[1]))
+ # Keep text selected, for inserting multiple brackets
+ cursor.movePosition(QTextCursor.Left, QTextCursor.MoveAnchor, 1)
+ cursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor,
+ len(text))
+ self.editor.setTextCursor(cursor)
+ elif key in self.BRACKETS_LEFT:
+ if (not trailing_text or
+ trailing_text[0] in self.BRACKETS_RIGHT.values() or
+ trailing_text[0] in [',', ':', ';']):
+ # Automatic insertion of brackets
+ self.editor.insert_text(pair)
+ cursor.movePosition(QTextCursor.PreviousCharacter)
+ self.editor.setTextCursor(cursor)
+ else:
+ self.editor.insert_text(char)
+ if char in self.editor.signature_completion_characters:
+ self.editor.request_signature()
+ elif key in self.BRACKETS_RIGHT:
+ if (self.editor.next_char() == char and
+ not self.editor.textCursor().atBlockEnd() and
+ not self.unmatched_brackets_in_line(
+ cursor.block().text(), char)):
+ # Overwrite an existing brackets if all in line are matched
+ cursor.movePosition(QTextCursor.NextCharacter,
+ QTextCursor.KeepAnchor, 1)
+ cursor.clearSelection()
+ self.editor.setTextCursor(cursor)
+ else:
+ self.editor.insert_text(char)
diff --git a/spyder/widgets/sourcecode/extensions/closequotes.py b/spyder/plugins/editor/extensions/closequotes.py
similarity index 90%
rename from spyder/widgets/sourcecode/extensions/closequotes.py
rename to spyder/plugins/editor/extensions/closequotes.py
index a1b81c8e127..3e73238a114 100644
--- a/spyder/widgets/sourcecode/extensions/closequotes.py
+++ b/spyder/plugins/editor/extensions/closequotes.py
@@ -54,7 +54,9 @@ def _on_key_pressed(self, event):
key = event.key()
if key in (Qt.Key_QuoteDbl, Qt.Key_Apostrophe) and self.enabled:
+ self.editor.completion_widget.hide()
self._autoinsert_quotes(key)
+ self.editor.document_did_change()
event.accept()
def _autoinsert_quotes(self, key):
@@ -78,11 +80,12 @@ def _autoinsert_quotes(self, key):
self.editor.setTextCursor(cursor)
elif self.editor.in_comment():
self.editor.insert_text(char)
- elif len(trailing_text) > 0 and not \
- unmatched_quotes_in_line(line_to_cursor) == char:
+ elif (len(trailing_text) > 0 and
+ not unmatched_quotes_in_line(line_to_cursor) == char and
+ not trailing_text[0] in (',', ':', ';', ')', ']', '}')):
self.editor.insert_text(char)
- elif unmatched_quotes_in_line(line_text) and \
- (not last_three == 3*char):
+ elif (unmatched_quotes_in_line(line_text) and
+ (not last_three == 3*char)):
self.editor.insert_text(char)
# Move to the right if we are before a quote
elif self.editor.next_char() == char:
@@ -102,6 +105,7 @@ def _autoinsert_quotes(self, key):
# probably the user wants to write a docstring
elif last_two == 2*char:
self.editor.insert_text(char)
+ self.editor.delayed_popup_docstring()
# Automatic insertion of quotes
else:
self.editor.insert_text(2*char)
diff --git a/spyder/plugins/editor/extensions/docstring.py b/spyder/plugins/editor/extensions/docstring.py
new file mode 100644
index 00000000000..83c3e43e8a2
--- /dev/null
+++ b/spyder/plugins/editor/extensions/docstring.py
@@ -0,0 +1,851 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Generate Docstring."""
+
+# Standard library imports
+import re
+from collections import OrderedDict
+
+# Third party imports
+from qtpy.QtGui import QTextCursor
+from qtpy.QtCore import Qt
+from qtpy.QtWidgets import QMenu
+
+# Local imports
+from spyder.config.main import CONF
+from spyder.py3compat import to_text_string
+
+
+def is_start_of_function(text):
+ """Return True if text is the beginning of the function definition."""
+ if isinstance(text, str) or isinstance(text, unicode):
+ function_prefix = ['def', 'async def']
+ text = text.lstrip()
+
+ for prefix in function_prefix:
+ if text.startswith(prefix):
+ return True
+
+ return False
+
+
+def get_indent(text):
+ """Get indent of text.
+
+ https://stackoverflow.com/questions/2268532/grab-a-lines-whitespace-
+ indention-with-python
+ """
+ indent = ''
+
+ ret = re.match(r'(\s*)', text)
+ if ret:
+ indent = ret.group(1)
+
+ return indent
+
+
+class DocstringWriterExtension(object):
+ """Class for insert docstring template automatically."""
+
+ def __init__(self, code_editor):
+ """Initialize and Add code_editor to the variable."""
+ self.code_editor = code_editor
+ self.quote3 = '"""'
+ self.quote3_other = "'''"
+ self.line_number_cursor = None
+
+ @staticmethod
+ def is_beginning_triple_quotes(text):
+ """Return True if there are only triple quotes in text."""
+ docstring_triggers = ['"""', 'r"""', "'''", "r'''"]
+ if text.lstrip() in docstring_triggers:
+ return True
+
+ return False
+
+ def get_function_definition_from_first_line(self):
+ """Get func def when the cursor is located on the first def line."""
+ document = self.code_editor.document()
+ cursor = QTextCursor(
+ document.findBlockByLineNumber(self.line_number_cursor - 1))
+
+ func_text = ''
+ func_indent = ''
+
+ is_first_line = True
+ line_number = cursor.blockNumber() + 1
+
+ number_of_lines = self.code_editor.blockCount()
+ remain_lines = number_of_lines - line_number + 1
+ number_of_lines_of_function = 0
+
+ for __ in range(min(remain_lines, 20)):
+ cur_text = to_text_string(cursor.block().text()).rstrip()
+
+ if is_first_line:
+ if not is_start_of_function(cur_text):
+ return None
+
+ func_indent = get_indent(cur_text)
+ is_first_line = False
+ else:
+ cur_indent = get_indent(cur_text)
+ if cur_indent <= func_indent:
+ return None
+ if is_start_of_function(cur_text):
+ return None
+ if cur_text.strip == '':
+ return None
+
+ if cur_text[-1] == '\\':
+ cur_text = cur_text[:-1]
+
+ func_text += cur_text
+ number_of_lines_of_function += 1
+
+ if cur_text.endswith(':'):
+ return func_text, number_of_lines_of_function
+
+ cursor.movePosition(QTextCursor.NextBlock)
+
+ return None
+
+ def get_function_definition_from_below_last_line(self):
+ """Get func def when the cursor is located below the last def line."""
+ cursor = self.code_editor.textCursor()
+ func_text = ''
+ is_first_line = True
+ line_number = cursor.blockNumber() + 1
+ number_of_lines_of_function = 0
+
+ for idx in range(min(line_number, 20)):
+ if cursor.block().blockNumber() == 0:
+ return None
+
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ prev_text = to_text_string(cursor.block().text()).rstrip()
+
+ if is_first_line:
+ if not prev_text.endswith(':'):
+ return None
+ is_first_line = False
+ elif prev_text.endswith(':') or prev_text == '':
+ return None
+
+ if prev_text[-1] == '\\':
+ prev_text = prev_text[:-1]
+
+ func_text = prev_text + func_text
+
+ number_of_lines_of_function += 1
+ if is_start_of_function(prev_text):
+ return func_text, number_of_lines_of_function
+
+ return None
+
+ def get_function_body(self, func_indent):
+ """Get the function body text."""
+ cursor = self.code_editor.textCursor()
+ line_number = cursor.blockNumber() + 1
+ number_of_lines = self.code_editor.blockCount()
+ body_list = []
+
+ for idx in range(number_of_lines - line_number + 1):
+ text = to_text_string(cursor.block().text())
+ text_indent = get_indent(text)
+
+ if text.strip() == '':
+ pass
+ elif len(text_indent) <= len(func_indent):
+ break
+
+ body_list.append(text)
+
+ cursor.movePosition(QTextCursor.NextBlock)
+
+ return '\n'.join(body_list)
+
+ def write_docstring(self):
+ """Write docstring to editor."""
+ line_to_cursor = self.code_editor.get_text('sol', 'cursor')
+ if self.is_beginning_triple_quotes(line_to_cursor):
+ cursor = self.code_editor.textCursor()
+ prev_pos = cursor.position()
+
+ quote = line_to_cursor[-1]
+ docstring_type = CONF.get('editor', 'docstring_type')
+ docstring = self._generate_docstring(docstring_type, quote)
+
+ if docstring:
+ self.code_editor.insert_text(docstring)
+
+ cursor = self.code_editor.textCursor()
+ cursor.setPosition(prev_pos, QTextCursor.KeepAnchor)
+ cursor.movePosition(QTextCursor.NextBlock)
+ cursor.movePosition(QTextCursor.EndOfLine,
+ QTextCursor.KeepAnchor)
+ cursor.clearSelection()
+ self.code_editor.setTextCursor(cursor)
+ return True
+
+ return False
+
+ def write_docstring_at_first_line_of_function(self):
+ """Write docstring to editor at mouse position."""
+ result = self.get_function_definition_from_first_line()
+ editor = self.code_editor
+ if result:
+ func_text, number_of_line_func = result
+ line_number_function = (self.line_number_cursor +
+ number_of_line_func - 1)
+
+ cursor = editor.textCursor()
+ line_number_cursor = cursor.blockNumber() + 1
+ offset = line_number_function - line_number_cursor
+ if offset > 0:
+ for __ in range(offset):
+ cursor.movePosition(QTextCursor.NextBlock)
+ else:
+ for __ in range(abs(offset)):
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ cursor.movePosition(QTextCursor.EndOfLine, QTextCursor.MoveAnchor)
+ editor.setTextCursor(cursor)
+
+ indent = get_indent(func_text)
+ editor.insert_text('\n{}{}"""'.format(indent, editor.indent_chars))
+ self.write_docstring()
+
+ def write_docstring_for_shortcut(self):
+ """Write docstring to editor by shortcut of code editor."""
+ # cursor placed below function definition
+ result = self.get_function_definition_from_below_last_line()
+ if result is not None:
+ __, number_of_lines_of_function = result
+ cursor = self.code_editor.textCursor()
+ for __ in range(number_of_lines_of_function):
+ cursor.movePosition(QTextCursor.PreviousBlock)
+
+ self.code_editor.setTextCursor(cursor)
+
+ cursor = self.code_editor.textCursor()
+ self.line_number_cursor = cursor.blockNumber() + 1
+
+ self.write_docstring_at_first_line_of_function()
+
+ def _generate_docstring(self, doc_type, quote):
+ """Generate docstring."""
+ docstring = None
+
+ self.quote3 = quote * 3
+ if quote == '"':
+ self.quote3_other = "'''"
+ else:
+ self.quote3_other = '"""'
+
+ result = self.get_function_definition_from_below_last_line()
+
+ if result:
+ func_def, __ = result
+ func_info = FunctionInfo()
+ func_info.parse_def(func_def)
+
+ if func_info.has_info:
+ func_body = self.get_function_body(func_info.func_indent)
+ if func_body:
+ func_info.parse_body(func_body)
+
+ if doc_type == 'Numpydoc':
+ docstring = self._generate_numpy_doc(func_info)
+ elif doc_type == 'Googledoc':
+ docstring = self._generate_google_doc(func_info)
+
+ return docstring
+
+ def _generate_numpy_doc(self, func_info):
+ """Generate a docstring of numpy type."""
+ numpy_doc = ''
+
+ arg_names = func_info.arg_name_list
+ arg_types = func_info.arg_type_list
+ arg_values = func_info.arg_value_list
+
+ if len(arg_names) > 0 and arg_names[0] == 'self':
+ del arg_names[0]
+ del arg_types[0]
+ del arg_values[0]
+
+ indent1 = func_info.func_indent + self.code_editor.indent_chars
+ indent2 = func_info.func_indent + self.code_editor.indent_chars * 2
+
+ numpy_doc += '\n{}\n'.format(indent1)
+
+ if len(arg_names) > 0:
+ numpy_doc += '\n{}Parameters'.format(indent1)
+ numpy_doc += '\n{}----------\n'.format(indent1)
+
+ arg_text = ''
+ for arg_name, arg_type, arg_value in zip(arg_names, arg_types,
+ arg_values):
+ arg_text += '{}{} : '.format(indent1, arg_name)
+ if arg_type:
+ arg_text += '{}'.format(arg_type)
+ else:
+ arg_text += 'TYPE'
+
+ if arg_value:
+ arg_text += ', optional'
+
+ arg_text += '\n{}DESCRIPTION.'.format(indent2)
+
+ if arg_value:
+ arg_value = arg_value.replace(self.quote3, self.quote3_other)
+ arg_text += ' The default is {}.'.format(arg_value)
+
+ arg_text += '\n'
+
+ numpy_doc += arg_text
+
+ if func_info.raise_list:
+ numpy_doc += '\n{}Raises'.format(indent1)
+ numpy_doc += '\n{}------'.format(indent1)
+ for raise_type in func_info.raise_list:
+ numpy_doc += '\n{}{}'.format(indent1, raise_type)
+ numpy_doc += '\n{}DESCRIPTION.'.format(indent2)
+ numpy_doc += '\n'
+
+ numpy_doc += '\n'
+ if func_info.has_yield:
+ header = '{0}Yields\n{0}------\n'.format(indent1)
+ else:
+ header = '{0}Returns\n{0}-------\n'.format(indent1)
+
+ return_type_annotated = func_info.return_type_annotated
+ if return_type_annotated:
+ return_section = '{}{}{}'.format(header, indent1,
+ return_type_annotated)
+ return_section += '\n{}DESCRIPTION.'.format(indent2)
+ else:
+ return_element_type = indent1 + '{return_type}\n' + indent2 + \
+ 'DESCRIPTION.'
+ placeholder = return_element_type.format(return_type='TYPE')
+ return_element_name = indent1 + '{return_name} : ' + \
+ placeholder.lstrip()
+
+ try:
+ return_section = self._generate_docstring_return_section(
+ func_info.return_value_in_body, header,
+ return_element_name, return_element_type, placeholder,
+ indent1)
+ except (ValueError, IndexError):
+ return_section = '{}{}None.'.format(header, indent1)
+
+ numpy_doc += return_section
+ numpy_doc += '\n\n{}{}'.format(indent1, self.quote3)
+
+ return numpy_doc
+
+ def _generate_google_doc(self, func_info):
+ """Generate a docstring of google type."""
+ google_doc = ''
+
+ arg_names = func_info.arg_name_list
+ arg_types = func_info.arg_type_list
+ arg_values = func_info.arg_value_list
+
+ if len(arg_names) > 0 and arg_names[0] == 'self':
+ del arg_names[0]
+ del arg_types[0]
+ del arg_values[0]
+
+ indent1 = func_info.func_indent + self.code_editor.indent_chars
+ indent2 = func_info.func_indent + self.code_editor.indent_chars * 2
+
+ google_doc += '\n{}\n'.format(indent1)
+
+ if len(arg_names) > 0:
+ google_doc += '\n{0}Args:\n'.format(indent1)
+
+ arg_text = ''
+ for arg_name, arg_type, arg_value in zip(arg_names, arg_types,
+ arg_values):
+ arg_text += '{}{} '.format(indent2, arg_name)
+
+ arg_text += '('
+ if arg_type:
+ arg_text += '{}'.format(arg_type)
+ else:
+ arg_text += 'TYPE'
+
+ if arg_value:
+ arg_text += ', optional'
+ arg_text += '):'
+
+ arg_text += ' DESCRIPTION.'
+
+ if arg_value:
+ arg_value = arg_value.replace(self.quote3, self.quote3_other)
+ arg_text += ' Defaults to {}.\n'.format(arg_value)
+ else:
+ arg_text += '\n'
+
+ google_doc += arg_text
+
+ if func_info.raise_list:
+ google_doc += '\n{0}Raises:'.format(indent1)
+ for raise_type in func_info.raise_list:
+ google_doc += '\n{}{}'.format(indent2, raise_type)
+ google_doc += ': DESCRIPTION.'
+ google_doc += '\n'
+
+ google_doc += '\n'
+ if func_info.has_yield:
+ header = '{}Yields:\n'.format(indent1)
+ else:
+ header = '{}Returns:\n'.format(indent1)
+
+ return_type_annotated = func_info.return_type_annotated
+ if return_type_annotated:
+ return_section = '{}{}{}: DESCRIPTION.'.format(
+ header, indent2, return_type_annotated)
+ else:
+ return_element_type = indent2 + '{return_type}: DESCRIPTION.'
+ placeholder = return_element_type.format(return_type='TYPE')
+ return_element_name = indent2 + '{return_name} ' + \
+ '(TYPE): DESCRIPTION.'
+
+ try:
+ return_section = self._generate_docstring_return_section(
+ func_info.return_value_in_body, header,
+ return_element_name, return_element_type, placeholder,
+ indent2)
+ except (ValueError, IndexError):
+ return_section = '{}{}None.'.format(header, indent2)
+
+ google_doc += return_section
+ google_doc += '\n\n{}{}'.format(indent1, self.quote3)
+
+ return google_doc
+
+ @staticmethod
+ def find_top_level_bracket_locations(string_toparse):
+ """Get the locations of top-level brackets in a string."""
+ bracket_stack = []
+ replace_args_list = []
+ bracket_type = None
+ literal_type = ''
+ brackets = {'(': ')', '[': ']', '{': '}'}
+ for idx, character in enumerate(string_toparse):
+ if (not bracket_stack and character in brackets.keys()
+ or character == bracket_type):
+ bracket_stack.append(idx)
+ bracket_type = character
+ elif bracket_type and character == brackets[bracket_type]:
+ begin_idx = bracket_stack.pop()
+ if not bracket_stack:
+ if not literal_type:
+ if bracket_type == '(':
+ literal_type = '(None)'
+ elif bracket_type == '[':
+ literal_type = '[list]'
+ elif bracket_type == '{':
+ if idx - begin_idx <= 1:
+ literal_type = '{dict}'
+ else:
+ literal_type = '{set}'
+ replace_args_list.append(
+ (string_toparse[begin_idx:idx + 1],
+ literal_type, 1))
+ bracket_type = None
+ literal_type = ''
+ elif len(bracket_stack) == 1:
+ if bracket_type == '(' and character == ',':
+ literal_type = '(tuple)'
+ elif bracket_type == '{' and character == ':':
+ literal_type = '{dict}'
+ elif bracket_type == '(' and character == ':':
+ literal_type = '[slice]'
+
+ if bracket_stack:
+ raise IndexError('Bracket mismatch')
+ for replace_args in replace_args_list:
+ string_toparse = string_toparse.replace(*replace_args)
+ return string_toparse
+
+ @staticmethod
+ def parse_return_elements(return_vals_group, return_element_name,
+ return_element_type, placeholder):
+ """Return the appropriate text for a group of return elements."""
+ all_eq = (return_vals_group.count(return_vals_group[0])
+ == len(return_vals_group))
+ if all([{'[list]', '(tuple)', '{dict}', '{set}'}.issuperset(
+ return_vals_group)]) and all_eq:
+ return return_element_type.format(
+ return_type=return_vals_group[0][1:-1])
+ # Output placeholder if special Python chars present in name
+ py_chars = {' ', '+', '-', '*', '/', '%', '@', '<', '>', '&', '|', '^',
+ '~', '=', ',', ':', ';', '#', '(', '[', '{', '}', ']',
+ ')', }
+ if any([any([py_char in return_val for py_char in py_chars])
+ for return_val in return_vals_group]):
+ return placeholder
+ # Output str type and no name if only string literals
+ if all(['"' in return_val or '\'' in return_val
+ for return_val in return_vals_group]):
+ return return_element_type.format(return_type='str')
+ # Output bool type and no name if only bool literals
+ if {'True', 'False'}.issuperset(return_vals_group):
+ return return_element_type.format(return_type='bool')
+ # Output numeric types and no name if only numeric literals
+ try:
+ [float(return_val) for return_val in return_vals_group]
+ num_not_int = 0
+ for return_val in return_vals_group:
+ try:
+ int(return_val)
+ except ValueError: # If not an integer (EAFP)
+ num_not_int = num_not_int + 1
+ if num_not_int == 0:
+ return return_element_type.format(return_type='int')
+ elif num_not_int == len(return_vals_group):
+ return return_element_type.format(return_type='float')
+ else:
+ return return_element_type.format(return_type='numeric')
+ except ValueError: # Not a numeric if float conversion didn't work
+ pass
+ # If names are not equal, don't contain "." or are a builtin
+ if ({'self', 'cls', 'None'}.isdisjoint(return_vals_group) and all_eq
+ and all(['.' not in return_val
+ for return_val in return_vals_group])):
+ return return_element_name.format(return_name=return_vals_group[0])
+ return placeholder
+
+ def _generate_docstring_return_section(self, return_vals, header,
+ return_element_name,
+ return_element_type,
+ placeholder, indent):
+ """Generate the Returns section of a function/method docstring."""
+ # If all return values are None, return none
+ non_none_vals = [return_val for return_val in return_vals
+ if return_val and return_val != 'None']
+ if not non_none_vals:
+ return header + indent + 'None.'
+
+ # Get only values with matching brackets that can be cleaned up
+ non_none_vals = [return_val.strip(' ()\t\n').rstrip(',')
+ for return_val in non_none_vals]
+ non_none_vals = [re.sub('([\"\'])(?:(?=(\\\\?))\\2.)*?\\1',
+ '"string"', return_val)
+ for return_val in non_none_vals]
+ unambiguous_vals = []
+ for return_val in non_none_vals:
+ try:
+ cleaned_val = self.find_top_level_bracket_locations(return_val)
+ except IndexError:
+ continue
+ unambiguous_vals.append(cleaned_val)
+ if not unambiguous_vals:
+ return header + placeholder
+
+ # If remaining are a mix of tuples and not, return single placeholder
+ single_vals, tuple_vals = [], []
+ for return_val in unambiguous_vals:
+ (tuple_vals.append(return_val) if ',' in return_val
+ else single_vals.append(return_val))
+ if single_vals and tuple_vals:
+ return header + placeholder
+
+ # If return values are tuples of different length, return a placeholder
+ if tuple_vals:
+ num_elements = [return_val.count(',') + 1
+ for return_val in tuple_vals]
+ if num_elements.count(num_elements[0]) != len(num_elements):
+ return header + placeholder
+ num_elements = num_elements[0]
+ else:
+ num_elements = 1
+
+ # If all have the same len but some ambiguous return that placeholders
+ if len(unambiguous_vals) != len(non_none_vals):
+ return header + '\n'.join(
+ [placeholder for __ in range(num_elements)])
+
+ # Handle tuple (or single) values position by position
+ return_vals_grouped = zip(*[
+ [return_element.strip() for return_element in
+ return_val.split(',')]
+ for return_val in unambiguous_vals])
+ return_elements_out = []
+ for return_vals_group in return_vals_grouped:
+ return_elements_out.append(
+ self.parse_return_elements(return_vals_group,
+ return_element_name,
+ return_element_type,
+ placeholder))
+
+ return header + '\n'.join(return_elements_out)
+
+
+class FunctionInfo(object):
+ """Parse function definition text."""
+
+ def __init__(self):
+ """."""
+ self.has_info = False
+ self.func_text = ''
+ self.args_text = ''
+ self.func_indent = ''
+ self.arg_name_list = []
+ self.arg_type_list = []
+ self.arg_value_list = []
+ self.return_type_annotated = None
+ self.return_value_in_body = []
+ self.raise_list = None
+ self.has_yield = False
+
+ @staticmethod
+ def is_char_in_pairs(pos_char, pairs):
+ """Return True if the charactor is in pairs of brackets or quotes."""
+ for pos_left, pos_right in pairs.items():
+ if pos_left < pos_char < pos_right:
+ return True
+
+ return False
+
+ @staticmethod
+ def _find_quote_position(text):
+ """Return the start and end position of pairs of quotes."""
+ pos = {}
+ is_found_left_quote = False
+
+ for idx, character in enumerate(text):
+ if is_found_left_quote is False:
+ if character == "'" or character == '"':
+ is_found_left_quote = True
+ quote = character
+ left_pos = idx
+ else:
+ if character == quote and text[idx - 1] != '\\':
+ pos[left_pos] = idx
+ is_found_left_quote = False
+
+ if is_found_left_quote:
+ raise IndexError("No matching close quote at: " + str(left_pos))
+
+ return pos
+
+ def _find_bracket_position(self, text, bracket_left, bracket_right,
+ pos_quote):
+ """Return the start and end position of pairs of brackets.
+
+ https://stackoverflow.com/questions/29991917/
+ indices-of-matching-parentheses-in-python
+ """
+ pos = {}
+ pstack = []
+
+ for idx, character in enumerate(text):
+ if character == bracket_left and \
+ not self.is_char_in_pairs(idx, pos_quote):
+ pstack.append(idx)
+ elif character == bracket_right and \
+ not self.is_char_in_pairs(idx, pos_quote):
+ if len(pstack) == 0:
+ raise IndexError(
+ "No matching closing parens at: " + str(idx))
+ pos[pstack.pop()] = idx
+
+ if len(pstack) > 0:
+ raise IndexError(
+ "No matching opening parens at: " + str(pstack.pop()))
+
+ return pos
+
+ def split_arg_to_name_type_value(self, args_list):
+ """Split argument text to name, type, value."""
+ for arg in args_list:
+ arg_type = None
+ arg_value = None
+
+ has_type = False
+ has_value = False
+
+ pos_colon = arg.find(':')
+ pos_equal = arg.find('=')
+
+ if pos_equal > -1:
+ has_value = True
+
+ if pos_colon > -1:
+ if not has_value:
+ has_type = True
+ elif pos_equal > pos_colon: # exception for def foo(arg1=":")
+ has_type = True
+
+ if has_value and has_type:
+ arg_name = arg[0:pos_colon].strip()
+ arg_type = arg[pos_colon + 1:pos_equal].strip()
+ arg_value = arg[pos_equal + 1:].strip()
+ elif not has_value and has_type:
+ arg_name = arg[0:pos_colon].strip()
+ arg_type = arg[pos_colon + 1:].strip()
+ elif has_value and not has_type:
+ arg_name = arg[0:pos_equal].strip()
+ arg_value = arg[pos_equal + 1:].strip()
+ else:
+ arg_name = arg.strip()
+
+ self.arg_name_list.append(arg_name)
+ self.arg_type_list.append(arg_type)
+ self.arg_value_list.append(arg_value)
+
+ def split_args_text_to_list(self, args_text):
+ """Split the text including multiple arguments to list.
+
+ This function uses a comma to separate arguments and ignores a comma in
+ brackets ans quotes.
+ """
+ args_list = []
+ idx_find_start = 0
+ idx_arg_start = 0
+
+ try:
+ pos_quote = self._find_quote_position(args_text)
+ pos_round = self._find_bracket_position(args_text, '(', ')',
+ pos_quote)
+ pos_curly = self._find_bracket_position(args_text, '{', '}',
+ pos_quote)
+ pos_square = self._find_bracket_position(args_text, '[', ']',
+ pos_quote)
+ except IndexError:
+ return None
+
+ while True:
+ pos_comma = args_text.find(',', idx_find_start)
+
+ if pos_comma == -1:
+ break
+
+ idx_find_start = pos_comma + 1
+
+ if self.is_char_in_pairs(pos_comma, pos_round) or \
+ self.is_char_in_pairs(pos_comma, pos_curly) or \
+ self.is_char_in_pairs(pos_comma, pos_square) or \
+ self.is_char_in_pairs(pos_comma, pos_quote):
+ continue
+
+ args_list.append(args_text[idx_arg_start:pos_comma])
+ idx_arg_start = pos_comma + 1
+
+ if idx_arg_start < len(args_text):
+ args_list.append(args_text[idx_arg_start:])
+
+ return args_list
+
+ def parse_def(self, text):
+ """Parse the function definition text."""
+ self.__init__()
+
+ if not is_start_of_function(text):
+ return
+
+ self.func_indent = get_indent(text)
+
+ text = text.strip()
+ text = text.replace('\r\n', '')
+ text = text.replace('\n', '')
+
+ return_type_re = re.search(r'->[ ]*([a-zA-Z0-9_,()\[\] ]*):$', text)
+ if return_type_re:
+ self.return_type_annotated = return_type_re.group(1)
+ text_end = text.rfind(return_type_re.group(0))
+ else:
+ self.return_type_annotated = None
+ text_end = len(text)
+
+ pos_args_start = text.find('(') + 1
+ pos_args_end = text.rfind(')', pos_args_start, text_end)
+
+ self.args_text = text[pos_args_start:pos_args_end]
+
+ args_list = self.split_args_text_to_list(self.args_text)
+ if args_list is not None:
+ self.has_info = True
+ self.split_arg_to_name_type_value(args_list)
+
+ def parse_body(self, text):
+ """Parse the function body text."""
+ re_raise = re.findall(r'[ \t]raise ([a-zA-Z0-9_]*)', text)
+ if len(re_raise) > 0:
+ self.raise_list = [x.strip() for x in re_raise]
+ # remove duplicates from list while keeping it in the order
+ # in python 2.7
+ # stackoverflow.com/questions/7961363/removing-duplicates-in-lists
+ self.raise_list = list(OrderedDict.fromkeys(self.raise_list))
+
+ re_yield = re.search(r'[ \t]yield ', text)
+ if re_yield:
+ self.has_yield = True
+
+ # get return value
+ pattern_return = r'return |yield '
+ line_list = text.split('\n')
+ is_found_return = False
+ line_return_tmp = ''
+
+ for line in line_list:
+ line = line.strip()
+
+ if is_found_return is False:
+ if re.match(pattern_return, line):
+ is_found_return = True
+
+ if is_found_return:
+ line_return_tmp += line
+ # check the integrity of line
+ try:
+ pos_quote = self._find_quote_position(line_return_tmp)
+
+ if line_return_tmp[-1] == '\\':
+ line_return_tmp = line_return_tmp[:-1]
+ continue
+
+ self._find_bracket_position(line_return_tmp, '(', ')',
+ pos_quote)
+ self._find_bracket_position(line_return_tmp, '{', '}',
+ pos_quote)
+ self._find_bracket_position(line_return_tmp, '[', ']',
+ pos_quote)
+ except IndexError:
+ continue
+
+ return_value = re.sub(pattern_return, '', line_return_tmp)
+ self.return_value_in_body.append(return_value)
+
+ is_found_return = False
+ line_return_tmp = ''
+
+
+class QMenuOnlyForEnter(QMenu):
+ """The class executes the selected action when "enter key" is input.
+
+ If a input of keyboard is not the "enter key", the menu is closed and
+ the input is inserted to code editor.
+ """
+
+ def __init__(self, code_editor):
+ """Init QMenu."""
+ super(QMenuOnlyForEnter, self).__init__(code_editor)
+ self.code_editor = code_editor
+
+ def keyPressEvent(self, event):
+ """Close the instance if key is not enter key."""
+ key = event.key()
+ if key not in (Qt.Key_Enter, Qt.Key_Return):
+ self.code_editor.keyPressEvent(event)
+ self.close()
+ else:
+ super(QMenuOnlyForEnter, self).keyPressEvent(event)
diff --git a/spyder/plugins/editor/extensions/manager.py b/spyder/plugins/editor/extensions/manager.py
new file mode 100644
index 00000000000..df218f6f5a0
--- /dev/null
+++ b/spyder/plugins/editor/extensions/manager.py
@@ -0,0 +1,106 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2013-2016 Colin Duquesnoy and others (see pyqode/AUTHORS.rst)
+# Copyright (c) 2016- Spyder Project Contributors (see AUTHORS.txt)
+#
+# Distributed under the terms of the MIT License
+# (see NOTICE.txt in the Spyder root directory for details)
+# -----------------------------------------------------------------------------
+
+"""
+This module contains the editor extensions controller.
+
+Adapted from pyqode/core/managers/modes.py of the
+`PyQode project `_.
+Original file:
+
+"""
+
+# Stdlib imports
+import logging
+
+# Local imports
+from spyder.api.manager import Manager
+
+
+logger = logging.getLogger(__name__)
+
+
+class EditorExtensionsManager(Manager):
+ """Manages the list of editor extensions of the CodeEdit widget."""
+
+ def __init__(self, editor):
+ """Initialize and add a reference to the editor."""
+ super(EditorExtensionsManager, self).__init__(editor)
+ self._extensions = {}
+
+ def add(self, extension):
+ """
+ Add a extension to the editor.
+
+ :param extension: The extension instance to add.
+
+ """
+ logger.debug('adding extension {}'.format(extension.name))
+ self._extensions[extension.name] = extension
+ extension.on_install(self.editor)
+ return extension
+
+ def remove(self, name_or_klass):
+ """
+ Remove a extension from the editor.
+
+ :param name_or_klass: The name (or class) of the extension to remove.
+ :returns: The removed extension.
+ """
+ logger.debug('removing extension {}'.format(name_or_klass))
+ extension = self.get(name_or_klass)
+ extension.on_uninstall()
+ self._extensions.pop(extension.name)
+ return extension
+
+ def clear(self):
+ """
+ Remove all extensions from the editor.
+
+ All extensions are removed fromlist and deleted.
+ """
+ while len(self._extensions):
+ key = sorted(list(self._extensions.keys()))[0]
+ self.remove(key)
+
+ def get(self, name_or_klass):
+ """
+ Get a extension by name (or class).
+
+ :param name_or_klass: The name or the class of the extension to get
+ :type name_or_klass: str or type
+ :rtype: spyder.api.mode.EditorExtension
+ """
+ if not isinstance(name_or_klass, str):
+ name_or_klass = name_or_klass.__name__
+ return self._extensions[name_or_klass]
+
+ def keys(self):
+ """
+ Return the list of the names of the installed extensions.
+ """
+ return self._extensions.keys()
+
+ def values(self):
+ """
+ Return the list of installed extensions.
+ """
+ return self._extensions.values()
+
+ def __len__(self):
+ """Return the amount of installed extensions."""
+ return len(list(self._extensions.values()))
+
+ def __iter__(self):
+ """
+ Return the list of extensions.
+
+ :return:
+ """
+ return iter([v for k, v in sorted(self._extensions.items())])
diff --git a/spyder/widgets/sourcecode/extensions/tests/__init__.py b/spyder/plugins/editor/extensions/tests/__init__.py
similarity index 100%
rename from spyder/widgets/sourcecode/extensions/tests/__init__.py
rename to spyder/plugins/editor/extensions/tests/__init__.py
diff --git a/spyder/plugins/editor/extensions/tests/test_closebrackets.py b/spyder/plugins/editor/extensions/tests/test_closebrackets.py
new file mode 100644
index 00000000000..2a998763e1d
--- /dev/null
+++ b/spyder/plugins/editor/extensions/tests/test_closebrackets.py
@@ -0,0 +1,194 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+"""Tests for close brackets."""
+
+# Third party imports
+import pytest
+from qtpy.QtGui import QTextCursor
+
+# Local imports
+from spyder.utils.qthelpers import qapplication
+from spyder.plugins.editor.widgets.codeeditor import CodeEditor
+from spyder.plugins.editor.utils.editor import TextHelper
+from spyder.plugins.editor.extensions.closebrackets import (
+ CloseBracketsExtension)
+
+
+# =============================================================================
+# ---- Fixtures
+# =============================================================================
+@pytest.fixture
+def editor_close_brackets():
+ """Set up Editor with close brackets activated."""
+ app = qapplication()
+ editor = CodeEditor(parent=None)
+ kwargs = {}
+ kwargs['language'] = 'Python'
+ kwargs['close_parentheses'] = True
+ editor.setup_editor(**kwargs)
+ return editor
+
+
+# =============================================================================
+# ---- Tests
+# =============================================================================
+@pytest.mark.parametrize(
+ 'text, expected_text, cursor_column',
+ [
+ ("(", "()", 1), # Close brackets
+ ("{", "{}", 1),
+ ("[", "[]", 1),
+ ])
+def test_close_brackets(qtbot, editor_close_brackets, text, expected_text,
+ cursor_column):
+ """Test insertion of brackets."""
+ editor = editor_close_brackets
+
+ qtbot.keyClicks(editor, text)
+ assert editor.toPlainText() == expected_text
+
+ assert cursor_column == TextHelper(editor).current_column_nbr()
+
+
+@pytest.mark.parametrize(
+ 'text, expected_text, cursor_column',
+ [
+ ('()', '(())', 2), # Complete in brackets
+ ('{}', '{()}', 2),
+ ('[]', '[()]', 2),
+ (',', '(),', 1), # Complete before commas, colons and semi-colons
+ (':', '():', 1),
+ (';', '();', 1),
+ ])
+def test_nested_brackets(qtbot, editor_close_brackets, text, expected_text,
+ cursor_column):
+ """
+ Test completion of brackets inside brackets and before commas,
+ colons and semi-colons.
+ """
+ editor = editor_close_brackets
+
+ qtbot.keyClicks(editor, text)
+ editor.move_cursor(-1)
+ qtbot.keyClicks(editor, '(')
+ assert editor.toPlainText() == expected_text
+
+ assert cursor_column == TextHelper(editor).current_column_nbr()
+
+
+def test_selected_text(qtbot, editor_close_brackets):
+ """Test insert surronding brackets to selected text."""
+ editor = editor_close_brackets
+ editor.set_text("some text")
+
+ # select some
+ cursor = editor.textCursor()
+ cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, 4)
+ editor.setTextCursor(cursor)
+
+ qtbot.keyClicks(editor, "(")
+ assert editor.toPlainText() == "(some) text"
+
+ qtbot.keyClicks(editor, "}")
+ assert editor.toPlainText() == "({some}) text"
+
+ qtbot.keyClicks(editor, "[")
+ assert editor.toPlainText() == "({[some]}) text"
+
+
+def test_selected_text_multiple_lines(qtbot, editor_close_brackets):
+ """Test insert surronding brackets to multiple lines selected text."""
+ editor = editor_close_brackets
+ text = ("some text\n"
+ "\n"
+ "some text")
+ editor.set_text(text)
+
+ # select until second some
+ cursor = editor.textCursor()
+ cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, 4)
+ cursor.movePosition(QTextCursor.Down, QTextCursor.KeepAnchor, 2)
+ editor.setTextCursor(cursor)
+
+ qtbot.keyClicks(editor, ")")
+ assert editor.toPlainText() == ("(some text\n"
+ "\n"
+ "some) text")
+
+ qtbot.keyClicks(editor, "{")
+ assert editor.toPlainText() == ("({some text\n"
+ "\n"
+ "some}) text")
+
+ qtbot.keyClicks(editor, "]")
+ assert editor.toPlainText() == ("({[some text\n"
+ "\n"
+ "some]}) text")
+
+
+def test_complex_completion(qtbot, editor_close_brackets):
+ """Test bracket completion in nested brackets."""
+ editor = editor_close_brackets
+ # Test completion when following character is a right bracket
+ editor.textCursor().insertText('foo(bar)')
+ editor.move_cursor(-1)
+ qtbot.keyClicks(editor, '(')
+ assert editor.toPlainText() == 'foo(bar())'
+ assert editor.textCursor().columnNumber() == 8
+ # Test normal insertion when next character is not a right bracket
+ editor.move_cursor(-1)
+ qtbot.keyClicks(editor, '[')
+ assert editor.toPlainText() == 'foo(bar[())'
+ assert editor.textCursor().columnNumber() == 8
+ # Test completion when following character is a comma
+ qtbot.keyClicks(editor, ',')
+ editor.move_cursor(-1)
+ qtbot.keyClicks(editor, '{')
+ assert editor.toPlainText() == 'foo(bar[{},())'
+ assert editor.textCursor().columnNumber() == 9
+
+
+def test_bracket_closing(qtbot, editor_close_brackets):
+ """Test bracket completion with existing brackets."""
+ editor = editor_close_brackets
+ editor.textCursor().insertText('foo(bar(x')
+ qtbot.keyClicks(editor, ')')
+ assert editor.toPlainText() == 'foo(bar(x)'
+ assert editor.textCursor().columnNumber() == 10
+ qtbot.keyClicks(editor, ')')
+ assert editor.toPlainText() == 'foo(bar(x))'
+ assert editor.textCursor().columnNumber() == 11
+ # same ')' closing with existing brackets starting at 'foo(bar(x|))'
+ editor.move_cursor(-2)
+ qtbot.keyClicks(editor, ')')
+ assert editor.toPlainText() == 'foo(bar(x))'
+ assert editor.textCursor().columnNumber() == 10
+ qtbot.keyClicks(editor, ')')
+ assert editor.toPlainText() == 'foo(bar(x))'
+ assert editor.textCursor().columnNumber() == 11
+
+
+def test_activate_deactivate(qtbot, editor_close_brackets):
+ """Test activating/desctivating close quotes editor extension."""
+ editor = editor_close_brackets
+ bracket_extension = editor.editor_extensions.get(CloseBracketsExtension)
+
+ qtbot.keyClicks(editor, "(")
+ assert editor.toPlainText() == "()"
+
+ editor.set_text("")
+ bracket_extension.enabled = False
+ qtbot.keyClicks(editor, "(")
+ assert editor.toPlainText() == "("
+
+ editor.set_text("")
+ bracket_extension.enabled = True
+ qtbot.keyClicks(editor, "(")
+ assert editor.toPlainText() == "()"
+
+
+if __name__ == '__main__':
+ pytest.main()
diff --git a/spyder/plugins/editor/extensions/tests/test_closequotes.py b/spyder/plugins/editor/extensions/tests/test_closequotes.py
new file mode 100644
index 00000000000..fcf0fd3ec68
--- /dev/null
+++ b/spyder/plugins/editor/extensions/tests/test_closequotes.py
@@ -0,0 +1,197 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+"""Tests for close quotes."""
+
+# Third party imports
+import pytest
+from qtpy.QtCore import Qt
+from qtpy.QtGui import QTextCursor
+
+# Local imports
+from spyder.utils.qthelpers import qapplication
+from spyder.plugins.editor.widgets.codeeditor import CodeEditor
+from spyder.plugins.editor.utils.editor import TextHelper
+from spyder.plugins.editor.extensions.closequotes import (
+ CloseQuotesExtension)
+
+
+# --- Fixtures
+# -----------------------------------------------------------------------------
+@pytest.fixture
+def editor_close_quotes():
+ """Set up Editor with close quotes activated."""
+ app = qapplication()
+ editor = CodeEditor(parent=None)
+ kwargs = {}
+ kwargs['language'] = 'Python'
+ kwargs['close_quotes'] = True
+ editor.setup_editor(**kwargs)
+ return editor
+
+# --- Tests
+# -----------------------------------------------------------------------------
+
+
+@pytest.mark.parametrize(
+ 'text, expected_text, cursor_column',
+ [
+ ('"', '""', 1), # Complete single quotes
+ ("'", "''", 1),
+ ('#"', '#"', 2), # In comment, dont add extra quote
+ ("#'", "#'", 2),
+ ('"""', '"""', 3), # Three quotes, dont add extra quotes
+ ("'''", "'''", 3),
+ ('""""', '""""""', 3), # Four, complete docstring quotes
+ ("''''", "''''''", 3),
+ ('"some_string"', '"some_string"', 13), # Write a string
+ ("'some_string'", "'some_string'", 13),
+ ])
+def test_close_quotes(qtbot, editor_close_quotes, text, expected_text,
+ cursor_column):
+ """Test insertion of extra quotes."""
+ editor = editor_close_quotes
+
+ qtbot.keyClicks(editor, text)
+ assert editor.toPlainText() == expected_text
+
+ assert cursor_column == TextHelper(editor).current_column_nbr()
+
+
+@pytest.mark.parametrize(
+ 'text, expected_text, cursor_column',
+ [
+ ('()', '("")', 2), # Complete in brackets
+ ('{}', '{""}', 2),
+ ('[]', '[""]', 2),
+ (',', '"",', 1), # Complete before commas, colons and semi-colons
+ (':', '"":', 1),
+ (';', '"";', 1),
+ ('a', '"a', 1), # No Completion before other text
+ ])
+def test_trailing_text(qtbot, editor_close_quotes, text, expected_text,
+ cursor_column):
+ """
+ Test insertion of extra quotes inside brackets and before commas,
+ colons and semi-colons.
+ """
+ editor = editor_close_quotes
+
+ qtbot.keyClicks(editor, text)
+ editor.move_cursor(-1)
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == expected_text
+
+ assert cursor_column == TextHelper(editor).current_column_nbr()
+
+
+def test_selected_text(qtbot, editor_close_quotes):
+ """Test insert surronding quotes to selected text."""
+ editor = editor_close_quotes
+ editor.set_text('some text')
+
+ # select some
+ cursor = editor.textCursor()
+ cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, 4)
+ editor.setTextCursor(cursor)
+
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == '"some" text'
+
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == '""some"" text'
+
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == '"""some""" text'
+
+
+def test_selected_text_multiple_lines(qtbot, editor_close_quotes):
+ """Test insert surronding quotes to multiple lines selected text."""
+ editor = editor_close_quotes
+ text = ('some text\n'
+ '\n'
+ 'some text')
+ editor.set_text(text)
+
+ # select until second some
+ cursor = editor.textCursor()
+ cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor, 4)
+ cursor.movePosition(QTextCursor.Down, QTextCursor.KeepAnchor, 2)
+ editor.setTextCursor(cursor)
+
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == ('"some text\n'
+ '\n'
+ 'some" text')
+
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == ('""some text\n'
+ '\n'
+ 'some"" text')
+
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == ('"""some text\n'
+ '\n'
+ 'some""" text')
+
+
+def test_close_quotes_in_brackets(qtbot, editor_close_quotes):
+ """Test quote completion in nested brackets."""
+ editor = editor_close_quotes
+ # Test closing when following character is a right parentheses
+ editor.textCursor().insertText('foo()')
+ editor.move_cursor(-1)
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == 'foo("")'
+ assert editor.textCursor().columnNumber() == 5
+ # Test not closing when single quote is before a bracket
+ qtbot.keyPress(editor, Qt.Key_Delete) # now 'foo(")'
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == 'foo("")'
+ assert editor.textCursor().columnNumber() == 6
+ # Test closing when following character is a comma
+ qtbot.keyClicks(editor, ', ,')
+ editor.move_cursor(-1)
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == 'foo("", "",)'
+ assert editor.textCursor().columnNumber() == 9
+ # Test closing when following character is a right brace
+ # and white preceding the next character
+ editor.move_cursor(2)
+ qtbot.keyClicks(editor, ' { },')
+ editor.move_cursor(-3)
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == 'foo("", "", {"" },)'
+ assert editor.textCursor().columnNumber() == 14
+ # Test not closing otherwise
+ editor.move_cursor(4)
+ qtbot.keyClicks(editor, ' bar')
+ editor.move_cursor(-3)
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == 'foo("", "", {"" }, "bar)'
+ assert editor.textCursor().columnNumber() == 20
+
+
+def test_activate_deactivate(qtbot, editor_close_quotes):
+ """Test activating/desctivating close quotes editor extension."""
+ editor = editor_close_quotes
+ quote_extension = editor.editor_extensions.get(CloseQuotesExtension)
+
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == '""'
+
+ editor.set_text('')
+ quote_extension.enabled = False
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == '"'
+
+ editor.set_text('')
+ quote_extension.enabled = True
+ qtbot.keyClicks(editor, '"')
+ assert editor.toPlainText() == '""'
+
+
+if __name__ == '__main__':
+ pytest.main()
diff --git a/spyder/plugins/editor/extensions/tests/test_docstring.py b/spyder/plugins/editor/extensions/tests/test_docstring.py
new file mode 100644
index 00000000000..11e7999c1e3
--- /dev/null
+++ b/spyder/plugins/editor/extensions/tests/test_docstring.py
@@ -0,0 +1,534 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see LICENSE.txt for details)
+
+"""Tests for docstring generation."""
+
+# Third party imports
+import pytest
+from qtpy.QtCore import Qt
+from qtpy.QtGui import QTextCursor
+
+# Local imports
+from spyder.config.main import CONF
+from spyder.utils.qthelpers import qapplication
+from spyder.plugins.editor.widgets.codeeditor import CodeEditor
+from spyder.plugins.editor.extensions.docstring import FunctionInfo
+
+
+# =============================================================================
+# ---- Fixtures
+# =============================================================================
+@pytest.fixture
+def editor_auto_docstring():
+ """Set up Editor with auto docstring activated."""
+ app = qapplication()
+ editor = CodeEditor(parent=None)
+ kwargs = {}
+ kwargs['language'] = 'Python'
+ kwargs['close_quotes'] = True
+ kwargs['close_parentheses'] = True
+ editor.setup_editor(**kwargs)
+ return editor
+
+
+# =============================================================================
+# ---- Tests
+# =============================================================================
+@pytest.mark.parametrize(
+ "text, indent, name_list, type_list, value_list, rtype",
+ [
+ ('def foo():', '', [], [], [], None),
+ (""" def foo(arg0, arg1=':', arg2: str='-> (float, str):') -> \
+ (float, int): """,
+ ' ', ['arg0', 'arg1', 'arg2'], [None, None, 'str'],
+ [None, "':'", "'-> (float, str):'"],
+ '(float, int)')
+ ])
+def test_parse_function_definition(text, indent, name_list, type_list,
+ value_list, rtype):
+ """Test the parse_def method of FunctionInfo class."""
+ func_info = FunctionInfo()
+ func_info.parse_def(text)
+
+ assert func_info.func_indent == indent
+ assert func_info.arg_name_list == name_list
+ assert func_info.arg_type_list == type_list
+ assert func_info.arg_value_list == value_list
+ assert func_info.return_type_annotated == rtype
+
+
+@pytest.mark.parametrize(
+ "text, indent, expected",
+ [
+ (""" def foo():\n
+ if 1:
+ raise ValueError
+ else:
+ return\n
+ class F:""",
+ " ",
+ """\n if 1:
+ raise ValueError
+ else:
+ return\n"""),
+ ("""def foo():
+ return""",
+ "",
+ """ return""")
+ ])
+def test_get_function_body(editor_auto_docstring, text, indent, expected):
+ """Test get function body."""
+ editor = editor_auto_docstring
+ editor.set_text(text)
+
+ cursor = editor.textCursor()
+ cursor.setPosition(0, QTextCursor.MoveAnchor)
+ cursor.movePosition(QTextCursor.NextBlock)
+ editor.setTextCursor(cursor)
+
+ writer = editor.writer_docstring
+ result = writer.get_function_body(indent)
+
+ assert expected == result
+
+
+@pytest.mark.parametrize("use_shortcut", [True, False])
+@pytest.mark.parametrize(
+ "doc_type, text, expected",
+ [
+ ('Numpydoc',
+ '',
+ ''
+ ),
+ ('Numpydoc',
+ 'if 1:\n ',
+ 'if 1:\n '
+ ),
+ ('Numpydoc',
+ '''async def foo():
+ raise
+ raise ValueError
+ raise ValueError("test")
+ raise TypeError("test")
+ yield ''',
+ '''async def foo():
+ """\n \n
+ Raises
+ ------
+ ValueError
+ DESCRIPTION.
+ TypeError
+ DESCRIPTION.\n
+ Yields
+ ------
+ None.
+
+ """
+ raise
+ raise ValueError
+ raise ValueError("test")
+ raise TypeError("test")
+ yield '''
+ ),
+ ('Numpydoc',
+ ''' def foo():
+ print('{}' % foo_raise Value)
+ foo_yield''',
+ ''' def foo():
+ """\n \n
+ Returns
+ -------
+ None.
+
+ """
+ print('{}' % foo_raise Value)
+ foo_yield''',
+ ),
+ ('Numpydoc',
+ '''def foo(arg, arg0, arg1: int, arg2: List[Tuple[str, float]],
+ arg3='-> (float, int):', arg4=':float, int[', arg5: str='""') -> \
+ (List[Tuple[str, float]], str, float):
+ ''',
+ '''def foo(arg, arg0, arg1: int, arg2: List[Tuple[str, float]],
+ arg3='-> (float, int):', arg4=':float, int[', arg5: str='""') -> \
+ (List[Tuple[str, float]], str, float):
+ """\n \n
+ Parameters
+ ----------
+ arg : TYPE
+ DESCRIPTION.
+ arg0 : TYPE
+ DESCRIPTION.
+ arg1 : int
+ DESCRIPTION.
+ arg2 : List[Tuple[str, float]]
+ DESCRIPTION.
+ arg3 : TYPE, optional
+ DESCRIPTION. The default is '-> (float, int):'.
+ arg4 : TYPE, optional
+ DESCRIPTION. The default is ':float, int['.
+ arg5 : str, optional
+ DESCRIPTION. The default is '""'.
+
+ Returns
+ -------
+ (List[Tuple[str, float]], str, float)
+ DESCRIPTION.
+
+ """
+ '''),
+ ('Googledoc',
+ '''async def foo():
+ raise
+ raise ValueError
+ raise TypeError("test")
+ yield value
+ ''',
+ '''async def foo():
+ """\n \n
+ Raises:
+ ValueError: DESCRIPTION.
+ TypeError: DESCRIPTION.\n
+ Yields:
+ value (TYPE): DESCRIPTION.
+
+ """
+ raise
+ raise ValueError
+ raise TypeError("test")
+ yield value
+ '''
+ ),
+ ('Googledoc',
+ ''' def foo():
+ ''',
+ ''' def foo():
+ """\n \n
+ Returns:
+ None.
+
+ """
+ ''',
+ ),
+ ('Googledoc',
+ '''def foo(arg, arg0, arg1: int, arg2: List[Tuple[str, float]],
+ arg3='-> (float, int):', arg4=':float, int[', arg5: str='""') -> \
+ (List[Tuple[str, float]], str, float):
+ ''',
+ '''def foo(arg, arg0, arg1: int, arg2: List[Tuple[str, float]],
+ arg3='-> (float, int):', arg4=':float, int[', arg5: str='""') -> \
+ (List[Tuple[str, float]], str, float):
+ """\n \n
+ Args:
+ arg (TYPE): DESCRIPTION.
+ arg0 (TYPE): DESCRIPTION.
+ arg1 (int): DESCRIPTION.
+ arg2 (List[Tuple[str, float]]): DESCRIPTION.
+ arg3 (TYPE, optional): DESCRIPTION. Defaults to '-> (float, int):'.
+ arg4 (TYPE, optional): DESCRIPTION. Defaults to ':float, int['.
+ arg5 (str, optional): DESCRIPTION. Defaults to '""'.
+
+ Returns:
+ (List[Tuple[str, float]], str, float): DESCRIPTION.
+
+ """
+ '''),
+ ])
+def test_editor_docstring_by_shortcut(editor_auto_docstring, doc_type,
+ text, expected, use_shortcut):
+ """Test auto docstring by shortcut."""
+ CONF.set('editor', 'docstring_type', doc_type)
+ editor = editor_auto_docstring
+ editor.set_text(text)
+
+ cursor = editor.textCursor()
+ cursor.setPosition(0, QTextCursor.MoveAnchor)
+ editor.setTextCursor(cursor)
+ writer = editor.writer_docstring
+
+ if use_shortcut:
+ writer.write_docstring_for_shortcut()
+ else:
+ pos = editor.cursorRect().bottomRight()
+ pos = editor.mapToGlobal(pos)
+ writer.line_number_cursor = editor.get_line_number_at(pos)
+ writer.write_docstring_at_first_line_of_function()
+
+ assert editor.toPlainText() == expected
+
+
+@pytest.mark.parametrize(
+ 'text, expected',
+ [
+ (''' def foo():
+ ''',
+ ''' def foo():
+ """\n \n
+ Returns
+ -------
+ None.
+
+ """
+ ''',)
+ ])
+def test_editor_docstring_below_def_by_shortcut(qtbot, editor_auto_docstring,
+ text, expected):
+ """Test auto docstring below function definition by shortcut."""
+ CONF.set('editor', 'docstring_type', 'Numpydoc')
+ editor = editor_auto_docstring
+ editor.set_text(text)
+
+ cursor = editor.textCursor()
+ cursor.movePosition(QTextCursor.NextBlock)
+ cursor.setPosition(QTextCursor.End, QTextCursor.MoveAnchor)
+ editor.setTextCursor(cursor)
+
+ editor.writer_docstring.write_docstring_for_shortcut()
+
+ assert editor.toPlainText() == expected
+
+
+@pytest.mark.parametrize(
+ 'text, expected, key',
+ [
+ ('''def foo():
+''',
+ '''def foo():
+ """\n \n
+ Returns
+ -------
+ None.
+
+ """''',
+ Qt.Key_Enter),
+ ('''def foo():
+''',
+ '''def foo():
+ """a''',
+ Qt.Key_A)
+ ])
+def test_editor_docstring_delayed_popup(qtbot, editor_auto_docstring,
+ text, expected, key):
+ """Test auto docstring using delayed popup."""
+ CONF.set('editor', 'docstring_type', 'Numpydoc')
+ editor = editor_auto_docstring
+ editor.set_text(text)
+
+ cursor = editor.textCursor()
+ cursor.movePosition(QTextCursor.NextBlock)
+ cursor.setPosition(QTextCursor.EndOfLine, QTextCursor.MoveAnchor)
+ editor.setTextCursor(cursor)
+
+ qtbot.keyPress(editor, Qt.Key_Space)
+ qtbot.keyPress(editor, Qt.Key_Space)
+ qtbot.keyPress(editor, Qt.Key_Space)
+ qtbot.keyPress(editor, Qt.Key_Space)
+ qtbot.keyPress(editor, Qt.Key_QuoteDbl)
+ qtbot.keyPress(editor, Qt.Key_QuoteDbl)
+ qtbot.keyPress(editor, Qt.Key_QuoteDbl)
+ qtbot.wait(1000)
+ qtbot.keyPress(editor.menu_docstring, key)
+ qtbot.wait(1000)
+
+ assert editor.toPlainText() == expected
+
+
+@pytest.mark.parametrize(
+ 'text, expected',
+ [
+ (''' def foo():
+ raise
+ foo_raise()
+ raisefoo()
+ raise ValueError
+ is_yield()
+ raise ValueError('tt')
+ yieldfoo()
+ \traise TypeError('tt')
+ _yield
+ ''',
+ ''' def foo():
+ """\n \n
+ Raises
+ ------
+ ValueError
+ DESCRIPTION.
+ TypeError
+ DESCRIPTION.\n
+ Returns
+ -------
+ None.
+
+ """
+ raise
+ foo_raise()
+ raisefoo()
+ raise ValueError
+ is_yield()
+ raise ValueError('tt')
+ yieldfoo()
+ \traise TypeError('tt')
+ _yield
+ ''',),
+ ('''def foo():
+ return None
+ return "f, b", v1, v2, 3.0, .7, (,), {}, [ab], f(a), None, a.b, a+b, True
+ return "f, b", v1, v3, 420, 5., (,), {}, [ab], f(a), None, a.b, a+b, False
+ ''',
+ '''def foo():
+ """\n \n
+ Returns
+ -------
+ str
+ DESCRIPTION.
+ v1 : TYPE
+ DESCRIPTION.
+ TYPE
+ DESCRIPTION.
+ numeric
+ DESCRIPTION.
+ float
+ DESCRIPTION.
+ tuple
+ DESCRIPTION.
+ dict
+ DESCRIPTION.
+ list
+ DESCRIPTION.
+ TYPE
+ DESCRIPTION.
+ TYPE
+ DESCRIPTION.
+ TYPE
+ DESCRIPTION.
+ TYPE
+ DESCRIPTION.
+ bool
+ DESCRIPTION.
+
+ """
+ return None
+ return "f, b", v1, v2, 3.0, .7, (,), {}, [ab], f(a), None, a.b, a+b, True
+ return "f, b", v1, v3, 420, 5., (,), {}, [ab], f(a), None, a.b, a+b, False
+ '''),
+ ('''def foo():
+ return no, (ano, eo, dken)
+ ''',
+ '''def foo():
+ """\n \n
+ Returns
+ -------
+ TYPE
+ DESCRIPTION.
+
+ """
+ return no, (ano, eo, dken)
+ ''')
+ ])
+def test_editor_docstring_with_body_numpydoc(qtbot, editor_auto_docstring,
+ text, expected):
+ """Test auto docstring of numpydoc when the function body is complex."""
+ CONF.set('editor', 'docstring_type', 'Numpydoc')
+ editor = editor_auto_docstring
+ editor.set_text(text)
+
+ cursor = editor.textCursor()
+ cursor.setPosition(0, QTextCursor.MoveAnchor)
+ editor.setTextCursor(cursor)
+ writer = editor.writer_docstring
+
+ writer.write_docstring_for_shortcut()
+
+ assert editor.toPlainText() == expected
+
+
+@pytest.mark.parametrize(
+ 'text, expected',
+ [
+ (''' def foo():
+ raise
+ foo_raise()
+ raisefoo()
+ raise ValueError
+ is_yield()
+ raise ValueError('tt')
+ yieldfoo()
+ \traise TypeError('tt')
+ _yield
+ ''',
+ ''' def foo():
+ """\n \n
+ Raises:
+ ValueError: DESCRIPTION.
+ TypeError: DESCRIPTION.\n
+ Returns:
+ None.
+
+ """
+ raise
+ foo_raise()
+ raisefoo()
+ raise ValueError
+ is_yield()
+ raise ValueError('tt')
+ yieldfoo()
+ \traise TypeError('tt')
+ _yield
+ ''',),
+ ('''def foo():
+ return None
+ return "f, b", v1, v2, 3.0, .7, (,), {}, [ab], f(a), None, a.b, a+b, True
+ return "f, b", v1, v3, 420, 5., (,), {}, [ab], f(a), None, a.b, a+b, False
+ ''',
+ '''def foo():
+ """\n \n
+ Returns:
+ str: DESCRIPTION.
+ v1 (TYPE): DESCRIPTION.
+ TYPE: DESCRIPTION.
+ numeric: DESCRIPTION.
+ float: DESCRIPTION.
+ tuple: DESCRIPTION.
+ dict: DESCRIPTION.
+ list: DESCRIPTION.
+ TYPE: DESCRIPTION.
+ TYPE: DESCRIPTION.
+ TYPE: DESCRIPTION.
+ TYPE: DESCRIPTION.
+ bool: DESCRIPTION.
+
+ """
+ return None
+ return "f, b", v1, v2, 3.0, .7, (,), {}, [ab], f(a), None, a.b, a+b, True
+ return "f, b", v1, v3, 420, 5., (,), {}, [ab], f(a), None, a.b, a+b, False
+ '''),
+ ('''def foo():
+ return no, (ano, eo, dken)
+ ''',
+ '''def foo():
+ """\n \n
+ Returns:
+ TYPE: DESCRIPTION.
+
+ """
+ return no, (ano, eo, dken)
+ ''')
+ ])
+def test_editor_docstring_with_body_googledoc(qtbot, editor_auto_docstring,
+ text, expected):
+ """Test auto docstring of googledoc when the function body is complex."""
+ CONF.set('editor', 'docstring_type', 'Googledoc')
+ editor = editor_auto_docstring
+ editor.set_text(text)
+
+ cursor = editor.textCursor()
+ cursor.setPosition(0, QTextCursor.MoveAnchor)
+ editor.setTextCursor(cursor)
+ writer = editor.writer_docstring
+
+ writer.write_docstring_for_shortcut()
+
+ assert editor.toPlainText() == expected
diff --git a/spyder/plugins/editor/lsp/__init__.py b/spyder/plugins/editor/lsp/__init__.py
new file mode 100644
index 00000000000..2712292243f
--- /dev/null
+++ b/spyder/plugins/editor/lsp/__init__.py
@@ -0,0 +1,498 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+
+"""
+LSP client, code introspection and linting utilities.
+"""
+
+from spyder.config.base import DEV
+
+
+# Language server communication verbosity at server logs.
+TRACE = 'messages'
+if DEV:
+ TRACE = 'verbose'
+
+# Supported LSP programming languages
+LSP_LANGUAGES = [
+ 'C#', 'CSS/LESS/SASS', 'Go', 'GraphQL', 'Groovy', 'Haxe', 'HTML',
+ 'Java', 'JavaScript', 'JSON', 'Julia', 'OCaml', 'PHP',
+ 'Rust', 'Scala', 'Swift', 'TypeScript', 'Erlang', 'Fortran',
+ 'Elixir'
+]
+
+# -------------------- CLIENT CONFIGURATION SETTINGS --------------------------
+
+# WorkspaceClientCapabilities define capabilities the
+# editor / tool provides on the workspace
+
+WORKSPACE_CAPABILITIES = {
+ # The client supports applying batch edits to the workspace.
+ # Request: An array of `TextDocumentEdit`s to express changes
+ # to n different text documents
+ "applyEdit": True,
+
+ # The client supports versioned document changes.
+ "workspaceEdit": {
+ "documentChanges": False
+ },
+
+ # Did change configuration notification supports dynamic registration.
+ "didChangeConfiguration": {
+ # Reload server settings dynamically
+ "dynamicRegistration": True
+ },
+
+ # The watched files notification is sent from the client to the server
+ # when the client detects changes to files watched by
+ # the language client.
+ "didChangeWatchedFiles": {
+ # Can be turned on/off dynamically
+ "dynamicRegistration": True
+ },
+
+ # The workspace symbol request is sent from the client to the server to
+ # list project-wide symbols matching the query string.
+ "symbol": {
+ # Can be turned on/off dynamically
+ "dynamicRegistration": True
+ },
+
+ # The workspace/executeCommand request is sent from the client to the
+ # server to trigger command execution on the server. In most cases the
+ # server creates a WorkspaceEdit structure and applies the changes to
+ # the workspace using the request workspace/applyEdit which is sent from
+ # the server to the client.
+ "executeCommand": {
+ # Can be turned on/off dynamically
+ "dynamicRegistration": True
+ }
+}
+
+# TextDocumentClientCapabilities define capabilities the editor / tool
+# provides on text documents.
+
+TEXT_EDITOR_CAPABILITES = {
+ # Editor supports file watching and synchronization (Required)
+ "synchronization": {
+ # File synchronization can be turned on/off.
+ "dynamicRegistration": True,
+
+ # The client (Spyder) will send a willSave notification
+ # to the server when a file is about to be saved.
+ "willSave": True,
+
+ # The client (Spyder) supports sending a will save request and
+ # waits for a response providing text edits which will
+ # be applied to the document before it is saved.
+ "willSaveWaitUntil": True,
+
+ # The client (Spyder) supports did save notifications.
+ # The document save notification is sent from the client to
+ # the server when the document was saved in the client.
+ "didSave": True
+ },
+
+ # Editor supports code completion operations.
+ # The Completion request is sent from the client to the server to
+ # compute completion items at a given cursor position.
+ "completion": {
+ # Code completion can be turned on/off dynamically.
+ "dynamicRegistration": True,
+
+ # Client (Spyder) supports snippets as insert text.
+ # A snippet can define tab stops and placeholders with `$1`, `$2`
+ # and `${3:foo}`. `$0` defines the final tab stop, it defaults to
+ # the end of the snippet. Placeholders with equal identifiers are
+ # linked, that is typing in one will update others too.
+ "completionItem": {
+ "snippetSupport": True
+ }
+ },
+
+ # The hover request is sent from the client to the server to request
+ # hover information at a given text document position.
+ "hover": {
+ # Hover introspection can be turned on/off dynamically.
+ "dynamicRegistration": True
+ },
+
+ # The signature help request is sent from the client to the server to
+ # request signature information at a given cursor position.
+ "signatureHelp": {
+ # Function/Class/Method signature hinting can be turned on/off
+ # dynamically.
+ "dynamicRegistration": True
+ },
+
+ # Editor allows to find references.
+ # The references request is sent from the client to the server to resolve
+ # project-wide references for the symbol denoted by the given text
+ # document position.
+ "references": {
+ # Find references can be turned on/off dynamically.
+ "dynamicRegistration": True
+ },
+
+ # Editor allows to highlight different text sections at the same time.
+ # The document highlight request is sent from the client to the server to
+ # resolve a document highlights for a given text document position
+ "documentHighlight": {
+ # Code highlighting can be turned on/off dynamically.
+ "dynamicRegistration": True
+ },
+
+ # Editor supports finding symbols on a document.
+ # The document symbol request is sent from the client to the server to list
+ # all symbols found in a given text document.
+ "documentSymbol": {
+ # Find symbols on document can be turned on/off dynamically.
+ "dynamicRegistration": True
+ },
+
+ # Editor allows to autoformat all the document.
+ # The document formatting request is sent from the server to the client to
+ # format a whole document.
+ "formatting": {
+ # Document formatting can be turned on/off dynamically.
+ "dynamicRegistration": True
+ },
+
+ # Editor can autoformat only a selected region on a document.
+ # The document range formatting request is sent from the client to the
+ # server to format a given range in a document.
+ "rangeFormatting": {
+ # Partial document formatting can be turned on/off dynamically.
+ "dynamicRegistration": True
+ },
+
+ # Editor allows to format a document while an edit is taking place.
+ # The document on type formatting request is sent from the client to the
+ # server to format parts of the document during typing.
+ "onTypeFormatting": {
+ # On-Type formatting can be turned on/off dynamically.
+ "dynamicRegistration": True
+ },
+
+ # Editor has an option to go to a function/class/method definition.
+ # The goto definition request is sent from the client to the server to
+ # resolve the definition location of a symbol at a given text document
+ # position.
+ "definition": {
+ # Go-to-definition can be turned on/off dynamically.
+ "dynamicRegistration": True
+ },
+
+ # Editor can give/highlight refactor tips/solutions.
+ # The code action request is sent from the client to the server to compute
+ # commands for a given text document and range. These commands are
+ # typically code fixes to either fix problems or to beautify/refactor code.
+ "codeAction": {
+ # Code hints can be turned on/off dynamically.
+ "dynamicRegistration": True
+ },
+
+ # Editor can display additional commands/statistics per each line.
+ # The code lens request is sent from the client to the server to compute
+ # code lenses for a given text document.
+ # A code lens represents a command that should be shown along with
+ # source text, like the number of references, a way to run tests, etc.
+ "codeLens": {
+ # Code lens can be turned on/off dynamically.
+ "dynamicRegistration": True
+ },
+
+ # Editor allows to find cross-document link references.
+ # The document links request is sent from the client to the server to
+ # request the location of links in a document.
+ # A document link is a range in a text document that links to an internal
+ # or external resource, like another text document or a web site.
+ "documentLink": {
+ # Finding document cross-references can be turned on/off dynamically.
+ "dynamicRegistration": True
+ },
+
+ # Editor allows to rename a variable/function/reference globally
+ # on a document.
+ # The rename request is sent from the client to the server to perform
+ # a workspace-wide rename of a symbol.
+ "rename": {
+ "dynamicRegistration": True
+ }
+}
+
+
+# Spyder editor and workspace capabilities
+
+CLIENT_CAPABILITES = {
+ "workspace": WORKSPACE_CAPABILITIES,
+ "textDocument": TEXT_EDITOR_CAPABILITES
+}
+
+
+# -------------------- SERVER CONFIGURATION SETTINGS --------------------------
+
+# Text document synchronization mode constants
+
+class TextDocumentSyncKind:
+ """Text document synchronization modes supported by a lsp-server"""
+ NONE = 0 # Text synchronization is not supported
+ FULL = 1 # Text synchronization requires all document contents
+ INCREMENTAL = 2 # Partial text synchronization is supported
+
+
+# Save options.
+
+SAVE_OPTIONS = {
+ # The client is supposed to include the content on save.
+ 'includeText': True
+}
+
+# Text synchronization capabilities
+
+TEXT_DOCUMENT_SYNC_OPTIONS = {
+ # Open and close notifications are sent to the server.
+ 'openClose': True,
+
+ # Change notifications are sent to the server.
+ # See TextDocumentSyncKind.NONE, TextDocumentSyncKind.FULL
+ # and TextDocumentSyncKind.INCREMENTAL.
+ 'change': TextDocumentSyncKind.NONE,
+
+ # Will save notifications are sent to the server.
+ 'willSave': False,
+
+ # Will save wait until requests are sent to the server.
+ 'willSaveWaitUntil': False,
+
+ # Save notifications are sent to the server.
+ 'save': SAVE_OPTIONS
+}
+
+
+# Code completion options
+
+COMPLETION_OPTIONS = {
+ # The server provides support to resolve additional
+ # information for a completion item.
+ 'resolveProvider': False,
+
+ # The characters that trigger completion automatically.
+ 'triggerCharacters': []
+}
+
+# Signature help options
+
+SIGNATURE_HELP_OPTIONS = {
+ # The characters that trigger signature help automatically.
+ 'triggerCharacters': []
+}
+
+# Code lens options
+
+CODE_LENS_OPTIONS = {
+ # Code lens has a resolve provider as well.
+ 'resolveProvider': False
+}
+
+# Format document on type options
+
+DOCUMENT_ON_TYPE_FORMATTING_OPTIONS = {
+ # A character on which formatting should be triggered, like `}`.
+ 'firstTriggerCharacter': None,
+
+ # More trigger characters.
+ 'moreTriggerCharacter': [],
+}
+
+
+# Document link options
+
+DOCUMENT_LINK_OPTIONS = {
+ # Document links have a resolve provider as well.
+ 'resolveProvider': False
+}
+
+# Execute command options.
+
+EXECUTE_COMMAND_OPTIONS = {
+ # The commands to be executed on the server
+ 'commands': []
+}
+
+
+# Server available capabilites options as defined by the protocol.
+
+SERVER_CAPABILITES = {
+ # Defines how text documents are synced.
+ # Is either a detailed structure defining each notification or
+ # for backwards compatibility the TextDocumentSyncKind number.
+ 'textDocumentSync': TEXT_DOCUMENT_SYNC_OPTIONS,
+
+ # The server provides hover support.
+ 'hoverProvider': False,
+
+ # The server provides completion support.
+ 'completionProvider': COMPLETION_OPTIONS,
+
+ # The server provides signature help support.
+ 'signatureHelpProvider': SIGNATURE_HELP_OPTIONS,
+
+ # The server provides goto definition support.
+ 'definitionProvider': False,
+
+ # The server provides find references support.
+ 'referencesProvider': False,
+
+ # The server provides document highlight support.
+ 'documentHighlightProvider': False,
+
+ # The server provides document symbol support.
+ 'documentSymbolProvider': False,
+
+ # The server provides workspace symbol support.
+ 'workspaceSymbolProvider': False,
+
+ # The server provides code actions.
+ 'codeActionProvider': False,
+
+ # The server provides code lens.
+ 'codeLensProvider': CODE_LENS_OPTIONS,
+
+ # The server provides document formatting.
+ 'documentFormattingProvider': False,
+
+ # The server provides document range formatting.
+ 'documentRangeFormattingProvider': False,
+
+ # The server provides document formatting on typing.
+ 'documentOnTypeFormattingProvider': DOCUMENT_ON_TYPE_FORMATTING_OPTIONS,
+
+ # The server provides rename support.
+ 'renameProvider': False,
+
+ # The server provides document link support.
+ 'documentLinkProvider': DOCUMENT_LINK_OPTIONS,
+
+ # The server provides execute command support.
+ 'executeCommandProvider': EXECUTE_COMMAND_OPTIONS,
+
+ # Experimental server capabilities.
+ 'experimental': None
+}
+
+
+class LSPEventTypes:
+ """Language Server Protocol event types."""
+ DOCUMENT = 'textDocument'
+ WORKSPACE = 'workspace'
+ WINDOW = 'window'
+ CODE_LENS = 'codeLens'
+
+
+class LSPRequestTypes:
+ """Language Server Protocol request/response types."""
+ # General requests
+ INITIALIZE = 'initialize'
+ SHUTDOWN = 'shutdown'
+ EXIT = 'exit'
+ CANCEL_REQUEST = '$/cancelRequest'
+ # Window requests
+ WINDOW_SHOW_MESSAGE = 'window/showMessage'
+ WINDOW_SHOW_MESSAGE_REQUEST = 'window/showMessageRequest'
+ WINDOW_LOG_MESSAGE = 'window/logMessage'
+ TELEMETRY_EVENT = 'telemetry/event'
+ # Client capabilities requests
+ CLIENT_REGISTER_CAPABILITY = 'client/registerCapability'
+ CLIENT_UNREGISTER_CAPABILITY = 'client/unregisterCapability'
+ # Workspace requests
+ WORKSPACE_CONFIGURATION_CHANGE = 'workspace/didChangeConfiguration'
+ WORKSPACE_WATCHED_FILES_UPDATE = 'workspace/didChangeWatchedFiles'
+ WORKSPACE_SYMBOL = 'workspace/symbol'
+ WORKSPACE_EXECUTE_COMMAND = 'workspace/executeCommand'
+ WORKSPACE_APPLY_EDIT = 'workspace/applyEdit'
+ # Document requests
+ DOCUMENT_PUBLISH_DIAGNOSTICS = 'textDocument/publishDiagnostics'
+ DOCUMENT_DID_OPEN = 'textDocument/didOpen'
+ DOCUMENT_DID_CHANGE = 'textDocument/didChange'
+ DOCUMENT_WILL_SAVE = 'textDocument/willSave'
+ DOCUMENT_WILL_SAVE_UNTIL = 'textDocument/willSaveWaitUntil'
+ DOCUMENT_DID_SAVE = 'textDocument/didSave'
+ DOCUMENT_DID_CLOSE = 'textDocument/didClose'
+ DOCUMENT_COMPLETION = 'textDocument/completion'
+ COMPLETION_RESOLVE = 'completionItem/resolve'
+ DOCUMENT_HOVER = 'textDocument/hover'
+ DOCUMENT_SIGNATURE = 'textDocument/signatureHelp'
+ DOCUMENT_REFERENCES = ' textDocument/references'
+ DOCUMENT_HIGHLIGHT = 'textDocument/documentHighlight'
+ DOCUMENT_SYMBOL = 'textDocument/documentSymbol'
+ DOCUMENT_FORMATTING = 'textDocument/formatting'
+ DOCUMENT_RANGE_FORMATTING = 'textDocument/rangeFormatting'
+ DOCUMENT_ON_TYPE_FORMATTING = 'textDocument/onTypeFormatting'
+ DOCUMENT_DEFINITION = 'textDocument/definition'
+ DOCUMENT_CODE_ACTION = 'textDocument/codeAction'
+ DOCUMENT_CODE_LENS = 'textDocument/codeLens'
+ CODE_LENS_RESOLVE = 'codeLens/resolve'
+ DOCUMENT_LINKS = 'textDocument/documentLink'
+ DOCUMENT_LINK_RESOLVE = 'documentLink/resolve'
+ DOCUMENT_RENAME = 'textDocument/rename'
+
+# -------------------- LINTING RESPONSE RELATED VALUES ------------------------
+
+
+class DiagnosticSeverity:
+ """LSP diagnostic severity levels."""
+ ERROR = 1
+ WARNING = 2
+ INFORMATION = 3
+ HINT = 4
+
+# ----------------- AUTO-COMPLETION RESPONSE RELATED VALUES -------------------
+
+
+class CompletionItemKind:
+ """LSP completion element categories."""
+ TEXT = 1
+ METHOD = 2
+ FUNCTION = 3
+ CONSTRUCTOR = 4
+ FIELD = 5
+ VARIABLE = 6
+ CLASS = 7
+ INTERFACE = 8
+ MODULE = 9
+ PROPERTY = 10
+ UNIT = 11
+ VALUE = 12
+ ENUM = 13
+ KEYWORD = 14
+ SNIPPET = 15
+ COLOR = 16
+ FILE = 17
+ REFERENCE = 18
+
+
+class InsertTextFormat:
+ """LSP completion text interpretations."""
+ PLAIN_TEXT = 1
+ SNIPPET = 2
+
+# ----------------- SAVING REQUEST RELATED VALUES -------------------
+
+
+class TextDocumentSaveReason:
+ """LSP text document saving action causes."""
+ MANUAL = 1
+ AFTER_DELAY = 2
+ FOCUS_OUT = 3
+
+# ----------------------- INTERNAL CONSTANTS ------------------------
+
+
+class ClientConstants:
+ """Internal LSP Client constants."""
+ CANCEL = 'lsp-cancel'
diff --git a/spyder/plugins/editor/lsp/client.py b/spyder/plugins/editor/lsp/client.py
new file mode 100644
index 00000000000..ead5c31d344
--- /dev/null
+++ b/spyder/plugins/editor/lsp/client.py
@@ -0,0 +1,387 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+Spyder Language Server Protocol Client implementation.
+
+This client implements the calls and procedures required to
+communicate with a v3.0 Language Server Protocol server.
+"""
+
+# Standard library imports
+import logging
+import os
+import os.path as osp
+import signal
+import subprocess
+import sys
+
+# Third-party imports
+from qtpy.QtCore import QObject, Signal, QSocketNotifier, Slot
+import zmq
+
+# Local imports
+from spyder.py3compat import PY2
+from spyder.config.base import get_conf_path, get_debug_level
+from spyder.plugins.editor.lsp import (
+ CLIENT_CAPABILITES, SERVER_CAPABILITES, TRACE,
+ TEXT_DOCUMENT_SYNC_OPTIONS, LSPRequestTypes,
+ ClientConstants)
+from spyder.plugins.editor.lsp.decorators import (
+ send_request, class_register, handles)
+from spyder.plugins.editor.lsp.providers import LSPMethodProviderMixIn
+from spyder.utils.misc import getcwd_or_home
+
+# Conditional imports
+if PY2:
+ import pathlib2 as pathlib
+else:
+ import pathlib
+
+# Main constants
+LOCATION = osp.realpath(osp.join(os.getcwd(),
+ osp.dirname(__file__)))
+PENDING = 'pending'
+SERVER_READY = 'server_ready'
+
+
+logger = logging.getLogger(__name__)
+
+
+@class_register
+class LSPClient(QObject, LSPMethodProviderMixIn):
+ """Language Server Protocol v3.0 client implementation."""
+ #: Signal to inform the editor plugin that the client has
+ # started properly and it's ready to be used.
+ sig_initialize = Signal(dict, str)
+
+ #: Signal to report internal server errors through Spyder's
+ # facilities.
+ sig_server_error = Signal(str)
+
+ # Constants
+ external_server_fmt = ('--server-host %(host)s '
+ '--server-port %(port)s ')
+
+ def __init__(self, parent,
+ server_settings={},
+ folder=getcwd_or_home(),
+ language='python'):
+ QObject.__init__(self)
+ # LSPMethodProviderMixIn.__init__(self)
+ self.manager = parent
+ self.zmq_in_socket = None
+ self.zmq_out_socket = None
+ self.zmq_in_port = None
+ self.zmq_out_port = None
+ self.transport_client = None
+ self.language = language
+
+ self.initialized = False
+ self.ready_to_close = False
+ self.request_seq = 1
+ self.req_status = {}
+ self.watched_files = {}
+ self.req_reply = {}
+
+ self.transport_args = [sys.executable, '-u',
+ osp.join(LOCATION, 'transport', 'main.py')]
+ self.external_server = server_settings.get('external', False)
+ self.stdio = server_settings.get('stdio', False)
+ # Setting stdio on implies that external_server is off
+ if self.stdio and self.external_server:
+ error = ('If server is set to use stdio communication, '
+ 'then it cannot be an external server')
+ logger.error(error)
+ raise AssertionError(error)
+
+ self.folder = folder
+ self.plugin_configurations = server_settings.get('configurations', {})
+ self.client_capabilites = CLIENT_CAPABILITES
+ self.server_capabilites = SERVER_CAPABILITES
+ self.context = zmq.Context()
+
+ server_args_fmt = server_settings.get('args', '')
+ server_args = server_args_fmt.format(**server_settings)
+ transport_args = self.external_server_fmt % (server_settings)
+
+ self.server_args = []
+ if language == 'python':
+ self.server_args += [sys.executable, '-m']
+ self.server_args += [server_settings['cmd']]
+ if len(server_args) > 0:
+ self.server_args += server_args.split(' ')
+
+ self.transport_args += transport_args.split(' ')
+ self.transport_args += ['--folder', folder]
+ self.transport_args += ['--transport-debug', str(get_debug_level())]
+ if not self.stdio:
+ self.transport_args += ['--external-server']
+ else:
+ self.transport_args += ['--stdio-server']
+ self.external_server = True
+
+ def start(self):
+ self.zmq_out_socket = self.context.socket(zmq.PAIR)
+ self.zmq_out_port = self.zmq_out_socket.bind_to_random_port('tcp://*')
+ self.zmq_in_socket = self.context.socket(zmq.PAIR)
+ self.zmq_in_socket.set_hwm(0)
+ self.zmq_in_port = self.zmq_in_socket.bind_to_random_port('tcp://*')
+ self.transport_args += ['--zmq-in-port', self.zmq_out_port,
+ '--zmq-out-port', self.zmq_in_port]
+
+ server_log = subprocess.PIPE
+ if get_debug_level() > 0:
+ # Create server log file
+ server_log_fname = 'server_{0}.log'.format(self.language)
+ server_log_file = get_conf_path(osp.join('lsp_logs',
+ server_log_fname))
+ if not osp.exists(osp.dirname(server_log_file)):
+ os.makedirs(osp.dirname(server_log_file))
+ server_log = open(server_log_file, 'w')
+ if self.stdio:
+ server_log.close()
+ if self.language == 'python':
+ self.server_args += ['--log-file', server_log_file]
+ self.transport_args += ['--server-log-file', server_log_file]
+
+ # Start server with logging options
+ if get_debug_level() == 2:
+ self.server_args.append('-v')
+ elif get_debug_level() == 3:
+ self.server_args.append('-vv')
+
+ server_stdin = subprocess.PIPE
+ server_stdout = server_log
+ server_stderr = subprocess.STDOUT
+
+ if not self.external_server:
+ logger.info('Starting server: {0}'.format(
+ ' '.join(self.server_args)))
+ creation_flags = 0
+ if os.name == 'nt':
+ creation_flags = (subprocess.CREATE_NEW_PROCESS_GROUP
+ | 0x08000000) # CREATE_NO_WINDOW
+
+ if os.environ.get('CI') and os.name == 'nt':
+ # The following patching avoids:
+ #
+ # OSError: [WinError 6] The handle is invalid
+ #
+ # while running our tests in CI services on Windows
+ # (they run fine locally).
+ # See this comment for an explanation:
+ # https://stackoverflow.com/q/43966523/
+ # 438386#comment74964124_43966523
+ def patched_cleanup():
+ pass
+ subprocess._cleanup = patched_cleanup
+
+ self.lsp_server = subprocess.Popen(
+ self.server_args,
+ stdout=server_stdout,
+ stdin=server_stdin,
+ stderr=server_stderr,
+ creationflags=creation_flags)
+
+ client_log = subprocess.PIPE
+ if get_debug_level() > 0:
+ # Client log file
+ client_log_fname = 'client_{0}.log'.format(self.language)
+ client_log_file = get_conf_path(osp.join('lsp_logs',
+ client_log_fname))
+ if not osp.exists(osp.dirname(client_log_file)):
+ os.makedirs(osp.dirname(client_log_file))
+ client_log = open(client_log_file, 'w')
+
+ new_env = dict(os.environ)
+ python_path = os.pathsep.join(sys.path)[1:]
+ new_env['PYTHONPATH'] = python_path
+ self.transport_args = list(map(str, self.transport_args))
+ logger.info('Starting transport: {0}'
+ .format(' '.join(self.transport_args)))
+ if self.stdio:
+ transport_stdin = subprocess.PIPE
+ transport_stdout = subprocess.PIPE
+ transport_stderr = client_log
+ self.transport_args += self.server_args
+ else:
+ transport_stdout = client_log
+ transport_stdin = subprocess.PIPE
+ transport_stderr = subprocess.STDOUT
+ self.transport_client = subprocess.Popen(self.transport_args,
+ stdout=transport_stdout,
+ stdin=transport_stdin,
+ stderr=transport_stderr,
+ env=new_env)
+
+ fid = self.zmq_in_socket.getsockopt(zmq.FD)
+ self.notifier = QSocketNotifier(fid, QSocketNotifier.Read, self)
+ self.notifier.activated.connect(self.on_msg_received)
+
+ # This is necessary for tests to pass locally!
+ logger.debug('LSP {} client started!'.format(self.language))
+
+ def stop(self):
+ # self.shutdown()
+ # self.exit()
+ logger.info('Stopping {} client...'.format(self.language))
+ if self.notifier is not None:
+ self.notifier.activated.disconnect(self.on_msg_received)
+ self.notifier.setEnabled(False)
+ self.notifier = None
+ # if os.name == 'nt':
+ # self.transport_client.send_signal(signal.CTRL_BREAK_EVENT)
+ # else:
+ self.transport_client.kill()
+ self.context.destroy()
+ if not self.external_server:
+ self.lsp_server.kill()
+
+ def send(self, method, params, requires_response):
+ if ClientConstants.CANCEL in params:
+ return
+ msg = {
+ 'id': self.request_seq,
+ 'method': method,
+ 'params': params
+ }
+ if requires_response:
+ self.req_status[self.request_seq] = method
+
+ logger.debug('{} request: {}'.format(self.language, method))
+ self.zmq_out_socket.send_pyobj(msg)
+ self.request_seq += 1
+ return int(msg['id'])
+
+ @Slot()
+ def on_msg_received(self):
+ self.notifier.setEnabled(False)
+ while True:
+ try:
+ # events = self.zmq_in_socket.poll(1500)
+ resp = self.zmq_in_socket.recv_pyobj(flags=zmq.NOBLOCK)
+
+ try:
+ method = resp['method']
+ logger.debug(
+ '{} response: {}'.format(self.language, method))
+ except KeyError:
+ pass
+
+ if 'error' in resp:
+ logger.debug('{} Response error: {}'
+ .format(self.language, repr(resp['error'])))
+ if self.language == 'python':
+ traceback = (resp['error'].get('data', {}).
+ get('traceback'))
+ if traceback:
+ traceback = ''.join(traceback)
+ self.sig_server_error.emit(traceback)
+ elif 'method' in resp:
+ if resp['method'][0] != '$':
+ if resp['method'] in self.handler_registry:
+ handler_name = (
+ self.handler_registry[resp['method']])
+ handler = getattr(self, handler_name)
+ handler(resp['params'])
+ if 'id' in resp:
+ self.request_seq = resp['id']
+ elif 'result' in resp:
+ if resp['result'] is not None:
+ req_id = resp['id']
+ if req_id in self.req_status:
+ req_type = self.req_status[req_id]
+ if req_type in self.handler_registry:
+ handler_name = self.handler_registry[req_type]
+ handler = getattr(self, handler_name)
+ handler(resp['result'], req_id)
+ self.req_status.pop(req_id)
+ if req_id in self.req_reply:
+ self.req_reply.pop(req_id)
+ except zmq.ZMQError:
+ self.notifier.setEnabled(True)
+ return
+
+ def perform_request(self, method, params):
+ if method in self.sender_registry:
+ handler_name = self.sender_registry[method]
+ handler = getattr(self, handler_name)
+ _id = handler(params)
+ if 'response_codeeditor' in params:
+ if params['requires_response']:
+ self.req_reply[_id] = params['response_codeeditor']
+ return _id
+
+ # ------ LSP initialization methods --------------------------------
+ @handles(SERVER_READY)
+ @send_request(method=LSPRequestTypes.INITIALIZE)
+ def initialize(self, *args, **kwargs):
+ params = {
+ 'processId': self.transport_client.pid,
+ 'rootUri': pathlib.Path(osp.abspath(self.folder)).as_uri(),
+ 'capabilities': self.client_capabilites,
+ 'trace': TRACE
+ }
+ return params
+
+ @send_request(method=LSPRequestTypes.SHUTDOWN)
+ def shutdown(self):
+ params = {}
+ return params
+
+ @handles(LSPRequestTypes.SHUTDOWN)
+ def handle_shutdown(self, response, *args):
+ self.ready_to_close = True
+
+ @send_request(method=LSPRequestTypes.EXIT, requires_response=False)
+ def exit(self):
+ params = {}
+ return params
+
+ @handles(LSPRequestTypes.INITIALIZE)
+ def process_server_capabilities(self, server_capabilites, *args):
+ self.send_plugin_configurations(self.plugin_configurations)
+ self.initialized = True
+ server_capabilites = server_capabilites['capabilities']
+
+ if isinstance(server_capabilites['textDocumentSync'], int):
+ kind = server_capabilites['textDocumentSync']
+ server_capabilites['textDocumentSync'] = TEXT_DOCUMENT_SYNC_OPTIONS
+ server_capabilites['textDocumentSync']['change'] = kind
+ if server_capabilites['textDocumentSync'] is None:
+ server_capabilites.pop('textDocumentSync')
+
+ self.server_capabilites.update(server_capabilites)
+
+ self.sig_initialize.emit(self.server_capabilites, self.language)
+
+ @send_request(method=LSPRequestTypes.WORKSPACE_CONFIGURATION_CHANGE,
+ requires_response=False)
+ def send_plugin_configurations(self, configurations, *args):
+ self.plugin_configurations = configurations
+ params = {
+ 'settings': configurations
+ }
+ return params
+
+
+def test():
+ """Test LSP client."""
+ from spyder.utils.qthelpers import qapplication
+ app = qapplication(test_time=8)
+ server_args_fmt = '--host %(host)s --port %(port)s --tcp'
+ server_settings = {'host': '127.0.0.1', 'port': 2087, 'cmd': 'pyls'}
+ lsp = LSPClient(app, server_args_fmt, server_settings)
+ lsp.start()
+
+ app.aboutToQuit.connect(lsp.stop)
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+ sys.exit(app.exec_())
+
+
+if __name__ == "__main__":
+ test()
diff --git a/spyder/plugins/editor/lsp/decorators.py b/spyder/plugins/editor/lsp/decorators.py
new file mode 100644
index 00000000000..0bdd325f4ab
--- /dev/null
+++ b/spyder/plugins/editor/lsp/decorators.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Spyder Language Server Protocol Client auxiliar decorators."""
+
+import functools
+
+
+def send_request(req=None, method=None, requires_response=True):
+ """Call function req and then send its results via ZMQ."""
+ if req is None:
+ return functools.partial(send_request, method=method,
+ requires_response=requires_response)
+
+ @functools.wraps(req)
+ def wrapper(self, *args, **kwargs):
+ params = req(self, *args, **kwargs)
+ _id = self.send(method, params, requires_response)
+ return _id
+ wrapper._sends = method
+ return wrapper
+
+
+def class_register(cls):
+ """Class decorator that allows to map LSP method names to class methods."""
+ cls.handler_registry = {}
+ cls.sender_registry = {}
+ for method_name in dir(cls):
+ method = getattr(cls, method_name)
+ if hasattr(method, '_handle'):
+ cls.handler_registry.update({method._handle: method_name})
+ if hasattr(method, '_sends'):
+ cls.sender_registry.update({method._sends: method_name})
+ return cls
+
+
+def handles(method_name):
+ """Assign an LSP method name to a python handler."""
+ def wrapper(func):
+ func._handle = method_name
+ return func
+ return wrapper
diff --git a/spyder/plugins/editor/lsp/manager.py b/spyder/plugins/editor/lsp/manager.py
new file mode 100644
index 00000000000..ac986c9aa17
--- /dev/null
+++ b/spyder/plugins/editor/lsp/manager.py
@@ -0,0 +1,344 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+Manager for all LSP clients connected to the servers defined
+in our Preferences.
+"""
+
+# Standard library imports
+import logging
+import os
+import os.path as osp
+
+# Third-party imports
+from qtpy.QtCore import QObject, Slot
+
+# Local imports
+from spyder.config.base import get_conf_path, running_under_pytest
+from spyder.config.lsp import PYTHON_CONFIG
+from spyder.config.main import CONF
+from spyder.utils.misc import select_port, getcwd_or_home
+from spyder.plugins.editor.lsp import LSP_LANGUAGES
+from spyder.plugins.editor.lsp.client import LSPClient
+
+
+logger = logging.getLogger(__name__)
+
+
+class LSPManager(QObject):
+ """Language Server Protocol manager."""
+ STOPPED = 'stopped'
+ RUNNING = 'running'
+ CONF_SECTION = 'lsp-server'
+ LOCALHOST = ['127.0.0.1', 'localhost']
+
+ def __init__(self, parent):
+ QObject.__init__(self)
+ self.main = parent
+
+ self.clients = {}
+ self.requests = {}
+ self.register_queue = {}
+
+ # Register languages to create clients for
+ for language in self.get_languages():
+ self.clients[language] = {
+ 'status': self.STOPPED,
+ 'config': self.get_language_config(language),
+ 'instance': None
+ }
+ self.register_queue[language] = []
+
+ def register_file(self, language, filename, codeeditor):
+ if language in self.clients:
+ language_client = self.clients[language]['instance']
+ if language_client is None:
+ self.register_queue[language].append((filename, codeeditor))
+ else:
+ language_client.register_file(filename, codeeditor)
+
+ def get_option(self, option):
+ """Get an option from our config system."""
+ return CONF.get(self.CONF_SECTION, option)
+
+ def get_languages(self):
+ """
+ Get the list of languages we need to start servers and create
+ clients for.
+ """
+ languages = ['python']
+ all_options = CONF.options(self.CONF_SECTION)
+ for option in all_options:
+ if option in [l.lower() for l in LSP_LANGUAGES]:
+ languages.append(option)
+ return languages
+
+ def get_language_config(self, language):
+ """Get language configuration options from our config system."""
+ if language == 'python':
+ return self.generate_python_config()
+ else:
+ return self.get_option(language)
+
+ def get_root_path(self, language):
+ """
+ Get root path to pass to the LSP servers.
+
+ This can be the current project path or the output of
+ getcwd_or_home (except for Python, see below).
+ """
+ path = None
+
+ # Get path of the current project
+ if self.main and self.main.projects:
+ path = self.main.projects.get_active_project_path()
+
+ # If there's no project, use the output of getcwd_or_home.
+ if not path:
+ # We can't use getcwd_or_home for Python because if it
+ # returns home and you have a lot of Python files on it
+ # then computing Rope completions takes a long time
+ # and blocks the PyLS server.
+ # Instead we use an empty directory inside our config one,
+ # just like we did for Rope in Spyder 3.
+ if language == 'python':
+ path = get_conf_path('lsp_root_path')
+ if not osp.exists(path):
+ os.mkdir(path)
+ else:
+ path = getcwd_or_home()
+
+ return path
+
+ @Slot()
+ def reinitialize_all_clients(self):
+ """
+ Send a new initialize message to each LSP server when the project
+ path has changed so they can update the respective server root paths.
+ """
+ for language in self.clients:
+ language_client = self.clients[language]
+ if language_client['status'] == self.RUNNING:
+ folder = self.get_root_path(language)
+ instance = language_client['instance']
+ instance.folder = folder
+ instance.initialize()
+
+ @Slot(str)
+ def report_server_error(self, error):
+ """Report server errors in our error report dialog."""
+ self.main.console.exception_occurred(error, is_traceback=True,
+ is_pyls_error=True)
+
+ def start_client(self, language):
+ """Start an LSP client for a given language."""
+ started = False
+ if language in self.clients:
+ language_client = self.clients[language]
+ queue = self.register_queue[language]
+
+ # Don't start LSP services when testing unless we demand
+ # them.
+ if running_under_pytest():
+ if not os.environ.get('SPY_TEST_USE_INTROSPECTION'):
+ return started
+
+ # Start client
+ started = language_client['status'] == self.RUNNING
+ if language_client['status'] == self.STOPPED:
+ config = language_client['config']
+
+ if not config['external']:
+ port = select_port(default_port=config['port'])
+ config['port'] = port
+
+ language_client['instance'] = LSPClient(
+ parent=self,
+ server_settings=config,
+ folder=self.get_root_path(language),
+ language=language
+ )
+
+ self.register_client_instance(language_client['instance'])
+
+ logger.info("Starting LSP client for {}...".format(language))
+ language_client['instance'].start()
+ language_client['status'] = self.RUNNING
+ for entry in queue:
+ language_client.register_file(*entry)
+ self.register_queue[language] = []
+ return started
+
+ def register_client_instance(self, instance):
+ """Register signals emmited by a client instance."""
+ if self.main:
+ if self.main.editor:
+ instance.sig_initialize.connect(
+ self.main.editor.register_lsp_server_settings)
+ if self.main.console:
+ instance.sig_server_error.connect(self.report_server_error)
+
+ def shutdown(self):
+ logger.info("Shutting down LSP manager...")
+ for language in self.clients:
+ self.close_client(language)
+
+ def update_server_list(self):
+ for language in self.get_languages():
+ config = {'status': self.STOPPED,
+ 'config': self.get_language_config(language),
+ 'instance': None}
+ if language not in self.clients:
+ self.clients[language] = config
+ self.register_queue[language] = []
+ else:
+ logger.debug(
+ self.clients[language]['config'] != config['config'])
+ current_config = self.clients[language]['config']
+ new_config = config['config']
+ restart_diff = ['cmd', 'args', 'host',
+ 'port', 'external', 'stdio']
+ restart = any([current_config[x] != new_config[x]
+ for x in restart_diff])
+ if restart:
+ if self.clients[language]['status'] == self.STOPPED:
+ self.clients[language] = config
+ elif self.clients[language]['status'] == self.RUNNING:
+ self.main.editor.stop_lsp_services(language)
+ self.close_client(language)
+ self.clients[language] = config
+ self.start_client(language)
+ else:
+ if self.clients[language]['status'] == self.RUNNING:
+ client = self.clients[language]['instance']
+ client.send_plugin_configurations(
+ new_config['configurations'])
+
+ def update_client_status(self, active_set):
+ for language in self.clients:
+ if language not in active_set:
+ self.close_client(language)
+
+ def close_client(self, language):
+ if language in self.clients:
+ language_client = self.clients[language]
+ if language_client['status'] == self.RUNNING:
+ logger.info("Stopping LSP client for {}...".format(language))
+ # language_client['instance'].shutdown()
+ # language_client['instance'].exit()
+ language_client['instance'].stop()
+ language_client['status'] = self.STOPPED
+
+ def send_request(self, language, request, params):
+ if language in self.clients:
+ language_client = self.clients[language]
+ if language_client['status'] == self.RUNNING:
+ client = self.clients[language]['instance']
+ client.perform_request(request, params)
+
+ def generate_python_config(self):
+ """
+ Update Python server configuration with the options saved in our
+ config system.
+ """
+ python_config = PYTHON_CONFIG.copy()
+
+ # Server options
+ cmd = self.get_option('advanced/command_launch')
+ host = self.get_option('advanced/host')
+ port = self.get_option('advanced/port')
+
+ # Pycodestyle
+ cs_exclude = self.get_option('pycodestyle/exclude').split(',')
+ cs_filename = self.get_option('pycodestyle/filename').split(',')
+ cs_select = self.get_option('pycodestyle/select').split(',')
+ cs_ignore = self.get_option('pycodestyle/ignore').split(',')
+ cs_max_line_length = self.get_option('pycodestyle/max_line_length')
+
+ pycodestyle = {
+ 'enabled': self.get_option('pycodestyle'),
+ 'exclude': [exclude.strip() for exclude in cs_exclude if exclude],
+ 'filename': [filename.strip()
+ for filename in cs_filename if filename],
+ 'select': [select.strip() for select in cs_select if select],
+ 'ignore': [ignore.strip() for ignore in cs_ignore if ignore],
+ 'hangClosing': False,
+ 'maxLineLength': cs_max_line_length
+ }
+
+ # Linting - Pyflakes
+ pyflakes = {
+ 'enabled': self.get_option('pyflakes')
+ }
+
+ # Pydocstyle
+ convention = self.get_option('pydocstyle/convention')
+
+ if convention == 'Custom':
+ ds_ignore = self.get_option('pydocstyle/ignore').split(',')
+ ds_select = self.get_option('pydocstyle/select').split(',')
+ ds_add_ignore = []
+ ds_add_select = []
+ else:
+ ds_ignore = []
+ ds_select = []
+ ds_add_ignore = self.get_option('pydocstyle/ignore').split(',')
+ ds_add_select = self.get_option('pydocstyle/select').split(',')
+
+ pydocstyle = {
+ 'enabled': self.get_option('pydocstyle'),
+ 'convention': convention,
+ 'addIgnore': [ignore.strip()
+ for ignore in ds_add_ignore if ignore],
+ 'addSelect': [select.strip()
+ for select in ds_add_select if select],
+ 'ignore': [ignore.strip() for ignore in ds_ignore if ignore],
+ 'select': [select.strip() for select in ds_select if select],
+ 'match': self.get_option('pydocstyle/match'),
+ 'matchDir': self.get_option('pydocstyle/match_dir')
+ }
+
+ # Code completion
+ jedi_completion = {
+ 'enabled': self.get_option('code_completion'),
+ 'include_params': False
+ }
+
+ jedi_signature_help = {
+ 'enabled': self.get_option('jedi_signature_help')
+ }
+
+ jedi_definition = {
+ 'enabled': self.get_option('jedi_definition'),
+ 'follow_imports': self.get_option('jedi_definition/follow_imports')
+ }
+
+ # Advanced
+ external_server = self.get_option('advanced/external')
+ stdio = self.get_option('advanced/stdio')
+
+ # Setup options in json
+ python_config['cmd'] = cmd
+ if host in self.LOCALHOST and not stdio:
+ python_config['args'] = '--host {host} --port {port} --tcp'
+ else:
+ python_config['args'] = ''
+ python_config['external'] = external_server
+ python_config['stdio'] = stdio
+ python_config['host'] = host
+ python_config['port'] = port
+
+ plugins = python_config['configurations']['pyls']['plugins']
+ plugins['pycodestyle'] = pycodestyle
+ plugins['pyflakes'] = pyflakes
+ plugins['pydocstyle'] = pydocstyle
+ plugins['jedi_completion'] = jedi_completion
+ plugins['jedi_signature_help'] = jedi_signature_help
+ plugins['preload']['modules'] = self.get_option('preload_modules')
+ plugins['jedi_definition'] = jedi_definition
+
+ return python_config
diff --git a/spyder/plugins/editor/lsp/providers/__init__.py b/spyder/plugins/editor/lsp/providers/__init__.py
new file mode 100644
index 00000000000..656c9fe3ad5
--- /dev/null
+++ b/spyder/plugins/editor/lsp/providers/__init__.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Spyder Language Server Protocol Client method providers."""
+
+from .document import DocumentProvider
+from .window import WindowProvider
+
+
+class LSPMethodProviderMixIn(DocumentProvider, WindowProvider):
+ pass
diff --git a/spyder/plugins/editor/lsp/providers/document.py b/spyder/plugins/editor/lsp/providers/document.py
new file mode 100644
index 00000000000..3427fe1b9d3
--- /dev/null
+++ b/spyder/plugins/editor/lsp/providers/document.py
@@ -0,0 +1,262 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Spyder Language Server Protocol Client document handler routines."""
+
+import logging
+import os.path as osp
+
+from spyder.py3compat import PY2
+from spyder.plugins.editor.lsp import (
+ LSPRequestTypes, InsertTextFormat, CompletionItemKind,
+ ClientConstants)
+from spyder.plugins.editor.lsp.decorators import handles, send_request
+
+if PY2:
+ import pathlib2 as pathlib
+ from urlparse import urlparse
+ from urllib import url2pathname
+else:
+ import pathlib
+ from urllib.parse import urlparse
+ from urllib.request import url2pathname
+
+
+logger = logging.getLogger(__name__)
+
+
+def path_as_uri(path):
+ return pathlib.Path(osp.abspath(path)).as_uri()
+
+
+class DocumentProvider:
+ def register_file(self, filename, codeeditor):
+ filename = path_as_uri(filename)
+ if filename not in self.watched_files:
+ self.watched_files[filename] = []
+ self.watched_files[filename].append(codeeditor)
+
+ @handles(LSPRequestTypes.DOCUMENT_PUBLISH_DIAGNOSTICS)
+ def process_document_diagnostics(self, response, *args):
+ uri = response['uri']
+ diagnostics = response['diagnostics']
+ if uri in self.watched_files:
+ callbacks = self.watched_files[uri]
+ for callback in callbacks:
+ callback.handle_response(
+ LSPRequestTypes.DOCUMENT_PUBLISH_DIAGNOSTICS,
+ {'params': diagnostics})
+ else:
+ logger.debug("Received diagnotics for file not open: " + uri)
+
+ @send_request(
+ method=LSPRequestTypes.DOCUMENT_DID_CHANGE, requires_response=False)
+ def document_changed(self, params):
+ params = {
+ 'textDocument': {
+ 'uri': path_as_uri(params['file']),
+ 'version': params['version']
+ },
+ 'contentChanges': [{
+ 'text': params['text']
+ }]
+ }
+ return params
+
+ @send_request(
+ method=LSPRequestTypes.DOCUMENT_DID_OPEN, requires_response=False)
+ def document_open(self, editor_params):
+ uri = path_as_uri(editor_params['file'])
+ if uri not in self.watched_files:
+ self.register_file(
+ editor_params['file'], editor_params['codeeditor'])
+ params = {
+ 'textDocument': {
+ 'uri': uri,
+ 'languageId': editor_params['language'],
+ 'version': editor_params['version'],
+ 'text': editor_params['text']
+ }
+ }
+
+ return params
+
+ @send_request(method=LSPRequestTypes.DOCUMENT_COMPLETION)
+ def document_completion_request(self, params):
+ params = {
+ 'textDocument': {
+ 'uri': path_as_uri(params['file'])
+ },
+ 'position': {
+ 'line': params['line'],
+ 'character': params['column']
+ }
+ }
+
+ return params
+
+ @handles(LSPRequestTypes.DOCUMENT_COMPLETION)
+ def process_document_completion(self, response, req_id):
+ if isinstance(response, dict):
+ response = response['items']
+ if response is not None:
+ for item in response:
+ item['kind'] = item.get('kind', CompletionItemKind.TEXT)
+ item['detail'] = item.get('detail', '')
+ item['documentation'] = item.get('documentation', '')
+ item['sortText'] = item.get('sortText', item['label'])
+ item['filterText'] = item.get('filterText', item['label'])
+ item['insertTextFormat'] = item.get(
+ 'insertTextFormat', InsertTextFormat.PLAIN_TEXT)
+ item['insertText'] = item.get('insertText', item['label'])
+
+ if req_id in self.req_reply:
+ self.req_reply[req_id].handle_response(
+ LSPRequestTypes.DOCUMENT_COMPLETION, {'params': response})
+
+ @send_request(method=LSPRequestTypes.DOCUMENT_SIGNATURE)
+ def signature_help_request(self, params):
+ params = {
+ 'textDocument': {
+ 'uri': path_as_uri(params['file'])
+ },
+ 'position': {
+ 'line': params['line'],
+ 'character': params['column']
+ }
+ }
+
+ return params
+
+ @handles(LSPRequestTypes.DOCUMENT_SIGNATURE)
+ def process_signature_completion(self, response, req_id):
+ if len(response['signatures']) > 0:
+ response['signatures'] = response['signatures'][
+ response['activeSignature']]
+ else:
+ response = None
+ if req_id in self.req_reply:
+ self.req_reply[req_id].handle_response(
+ LSPRequestTypes.DOCUMENT_SIGNATURE,
+ {'params': response})
+
+ @send_request(method=LSPRequestTypes.DOCUMENT_HOVER)
+ def hover_request(self, params):
+ params = {
+ 'textDocument': {
+ 'uri': path_as_uri(params['file'])
+ },
+ 'position': {
+ 'line': params['line'],
+ 'character': params['column']
+ }
+ }
+
+ return params
+
+ @handles(LSPRequestTypes.DOCUMENT_HOVER)
+ def process_hover_result(self, result, req_id):
+ contents = result['contents']
+ if isinstance(contents, list):
+ contents = contents[0]
+ if isinstance(contents, dict):
+ contents = contents['value']
+ if req_id in self.req_reply:
+ self.req_reply[req_id].handle_response(
+ LSPRequestTypes.DOCUMENT_HOVER,
+ {'params': contents})
+
+ @send_request(method=LSPRequestTypes.DOCUMENT_DEFINITION)
+ def go_to_definition_request(self, params):
+ params = {
+ 'textDocument': {
+ 'uri': path_as_uri(params['file'])
+ },
+ 'position': {
+ 'line': params['line'],
+ 'character': params['column']
+ }
+ }
+
+ return params
+
+ @handles(LSPRequestTypes.DOCUMENT_DEFINITION)
+ def process_go_to_definition(self, result, req_id):
+ if isinstance(result, list):
+ if len(result) > 0:
+ result = result[0]
+ uri = urlparse(result['uri'])
+ netloc, path = uri.netloc, uri.path
+ # Prepend UNC share notation if we have a UNC path.
+ netloc = '\\\\' + netloc if netloc else netloc
+ result['file'] = url2pathname(netloc + path)
+ else:
+ result = None
+ if req_id in self.req_reply:
+ self.req_reply[req_id].handle_response(
+ LSPRequestTypes.DOCUMENT_DEFINITION,
+ {'params': result})
+
+ @send_request(method=LSPRequestTypes.DOCUMENT_WILL_SAVE,
+ requires_response=False)
+ def document_will_save_notification(self, params):
+ params = {
+ 'textDocument': {
+ 'uri': path_as_uri(params['file'])
+ },
+ 'reason': params['reason']
+ }
+ return params
+
+ @send_request(method=LSPRequestTypes.DOCUMENT_DID_SAVE,
+ requires_response=False)
+ def document_did_save_notification(self, params):
+ """
+ Handle the textDocument/didSave message received from an LSP server.
+ """
+ text = None
+ if 'text' in params:
+ text = params['text']
+ params = {
+ 'textDocument': {
+ 'uri': path_as_uri(params['file'])
+ }
+ }
+ if text is not None:
+ params['text'] = text
+ return params
+
+ @send_request(method=LSPRequestTypes.DOCUMENT_DID_CLOSE,
+ requires_response=False)
+ def document_did_close(self, params):
+ codeeditor = params['codeeditor']
+ logger.debug('[{0}] File: {1}'.format(
+ LSPRequestTypes.DOCUMENT_DID_CLOSE, params['file']))
+ filename = path_as_uri(params['file'])
+
+ params = {
+ 'textDocument': {
+ 'uri': filename
+ }
+ }
+ if filename not in self.watched_files:
+ params[ClientConstants.CANCEL] = True
+ else:
+ editors = self.watched_files[filename]
+ if len(editors) > 1:
+ params[ClientConstants.CANCEL] = True
+ idx = -1
+ for i, editor in enumerate(editors):
+ if id(codeeditor) == id(editor):
+ idx = i
+ break
+ if idx > 0:
+ editors.pop(idx)
+
+ if len(editors) == 0:
+ self.watched_files.pop(filename)
+
+ return params
diff --git a/spyder/plugins/editor/lsp/providers/window.py b/spyder/plugins/editor/lsp/providers/window.py
new file mode 100644
index 00000000000..d749f281737
--- /dev/null
+++ b/spyder/plugins/editor/lsp/providers/window.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Spyder Language Server Protocol Client window handler routines."""
+
+import logging
+
+from spyder.plugins.editor.lsp import LSPRequestTypes
+from spyder.plugins.editor.lsp.decorators import handles
+
+logger = logging.getLogger(__name__)
+
+
+class WindowProvider:
+ @handles(LSPRequestTypes.WINDOW_SHOW_MESSAGE)
+ def process_show_message(self, response, *args):
+ """Handle window/showMessage notifications from LSP server."""
+ logger.debug("Received showMessage: %r" % response)
+
+ @handles(LSPRequestTypes.WINDOW_LOG_MESSAGE)
+ def process_log_message(self, response, *args):
+ """Handle window/logMessage notifications from LSP server."""
+ logger.debug("Received logMessage: %r" % response)
diff --git a/spyder_breakpoints/widgets/__init__.py b/spyder/plugins/editor/lsp/tests/__init__.py
similarity index 100%
rename from spyder_breakpoints/widgets/__init__.py
rename to spyder/plugins/editor/lsp/tests/__init__.py
diff --git a/spyder/plugins/editor/lsp/tests/conftest.py b/spyder/plugins/editor/lsp/tests/conftest.py
new file mode 100644
index 00000000000..a0845154d8e
--- /dev/null
+++ b/spyder/plugins/editor/lsp/tests/conftest.py
@@ -0,0 +1,95 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+import os
+try:
+ from unittest.mock import Mock
+except ImportError:
+ from mock import Mock # Python 2
+
+from qtpy.QtCore import QObject, Signal, Slot
+import pytest
+from pytestqt.plugin import QtBot
+
+from spyder.config.main import CONF
+from spyder.plugins.editor.lsp import SERVER_CAPABILITES
+from spyder.plugins.editor.lsp.manager import LSPManager
+
+
+class EditorMock(QObject):
+ """
+ Mock for the Editor plugin with the interface needed by LSPManager.
+ """
+ sig_lsp_initialized = Signal()
+
+ def __init__(self):
+ QObject.__init__(self)
+ self.lsp_editor_settings = {}
+
+ @Slot(dict, str)
+ def register_lsp_server_settings(self, settings, language):
+ self.lsp_editor_settings[language] = settings
+ self.sig_lsp_initialized.emit()
+
+
+class MainWindowMock(QObject):
+ """Mock for the Main Window."""
+ def __init__(self):
+ QObject.__init__(self)
+ self.editor = EditorMock()
+
+ def __getattr__(self, attr):
+ if attr == 'editor':
+ return self.editor
+ elif attr == 'projects':
+ # TODO: Add tests for project switching
+ return None
+ else:
+ return Mock()
+
+
+@pytest.fixture(scope="module")
+def qtbot_module(qapp, request):
+ """Module fixture for qtbot."""
+ result = QtBot(request)
+ return result
+
+
+def lsp_context(is_stdio):
+ @pytest.fixture(scope='module')
+ def wrapper(qtbot_module, request):
+ # Activate pycodestyle and pydocstyle
+ CONF.set('lsp-server', 'pycodestyle', True)
+ CONF.set('lsp-server', 'pydocstyle', True)
+ CONF.set('lsp-server', 'stdio', is_stdio)
+
+ # Create the manager
+ os.environ['SPY_TEST_USE_INTROSPECTION'] = 'True'
+ manager = LSPManager(parent=MainWindowMock())
+ # Wait for the client to be started
+ editor = manager.main.editor
+ with qtbot_module.waitSignal(
+ editor.sig_lsp_initialized, timeout=30000):
+ manager.start_client('python')
+
+ settings = editor.lsp_editor_settings['python']
+ assert all(
+ [option in SERVER_CAPABILITES for option in settings.keys()])
+
+ def teardown():
+ manager.shutdown()
+
+ os.environ['SPY_TEST_USE_INTROSPECTION'] = 'False'
+ CONF.set('lsp-server', 'pycodestyle', False)
+ CONF.set('lsp-server', 'pydocstyle', False)
+
+ request.addfinalizer(teardown)
+ return manager
+ return wrapper
+
+
+lsp_manager = lsp_context(is_stdio=False)
+lsp_stdio_manager = lsp_context(is_stdio=True)
diff --git a/spyder/plugins/editor/lsp/tests/test_client.py b/spyder/plugins/editor/lsp/tests/test_client.py
new file mode 100644
index 00000000000..4e6763ddc78
--- /dev/null
+++ b/spyder/plugins/editor/lsp/tests/test_client.py
@@ -0,0 +1,218 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+import os
+from textwrap import dedent
+
+import pytest
+from qtpy.QtCore import QObject, Signal, Slot
+
+from spyder.config.lsp import PYTHON_CONFIG
+from spyder.plugins.editor.lsp.client import LSPClient
+from spyder.plugins.editor.lsp import LSPRequestTypes
+
+
+class LSPEditor(QObject):
+ """Dummy editor that can handle the responses of an LSP client."""
+ sig_response = Signal(str, dict)
+
+ @Slot(str, dict)
+ def handle_response(self, method, params):
+ self.sig_response.emit(method, params)
+
+
+@pytest.fixture(scope='module', params=[
+ pytest.lazy_fixture('lsp_manager'),
+ pytest.lazy_fixture('lsp_stdio_manager')])
+def lsp_client_and_editor(request):
+ """Create an LSP client/editor pair."""
+ editor = LSPEditor()
+ client = request.param.clients['python']['instance']
+ return client, editor
+
+
+@pytest.mark.slow
+@pytest.mark.third
+def test_didOpen(lsp_client_and_editor, qtbot):
+ client, editor = lsp_client_and_editor
+
+ # Parameters to perform a textDocument/didOpen request
+ params = {
+ 'file': 'test.py',
+ 'language': 'python',
+ 'version': 1,
+ 'text': "",
+ 'codeeditor': editor,
+ 'requires_response': False
+ }
+
+ # Wait for the client to be started
+ with qtbot.waitSignal(editor.sig_response, timeout=30000) as blocker:
+ client.perform_request(LSPRequestTypes.DOCUMENT_DID_OPEN, params)
+ response, _ = blocker.args
+
+ # Assert the response has what we expect
+ assert response == 'textDocument/publishDiagnostics'
+
+
+@pytest.mark.slow
+@pytest.mark.third
+def test_get_signature(lsp_client_and_editor, qtbot):
+ client, editor = lsp_client_and_editor
+
+ # Parameters to perform a textDocument/didChange request
+ params = {
+ 'file': 'test.py',
+ 'language': 'python',
+ 'version': 1,
+ 'text': "import os\nos.walk(\n",
+ 'codeeditor': editor,
+ 'requires_response': False
+ }
+
+ # Perform the request
+ with qtbot.waitSignal(editor.sig_response, timeout=30000):
+ client.perform_request(LSPRequestTypes.DOCUMENT_DID_CHANGE, params)
+
+ # Parameters to perform a textDocument/signatureHelp request
+ signature_params = {
+ 'file': 'test.py',
+ 'line': 1,
+ 'column': 10,
+ 'requires_response': True,
+ 'response_codeeditor': editor
+ }
+
+ # Perform the request
+ with qtbot.waitSignal(editor.sig_response, timeout=30000) as blocker:
+ client.perform_request(LSPRequestTypes.DOCUMENT_SIGNATURE,
+ signature_params)
+ _, response = blocker.args
+
+ # Assert the response has what we expect
+ assert response['params']['signatures']['label'].startswith('walk')
+
+
+@pytest.mark.slow
+@pytest.mark.third
+def test_get_completions(lsp_client_and_editor, qtbot):
+ client, editor = lsp_client_and_editor
+
+ # Parameters to perform a textDocument/didChange request
+ params = {
+ 'file': 'test.py',
+ 'language': 'python',
+ 'version': 1,
+ 'text': "import o",
+ 'codeeditor': editor,
+ 'requires_response': False
+ }
+
+ # Perform the request
+ with qtbot.waitSignal(editor.sig_response, timeout=30000):
+ client.perform_request(LSPRequestTypes.DOCUMENT_DID_CHANGE, params)
+
+ # Parameters to perform a textDocument/completion request
+ completion_params = {
+ 'file': 'test.py',
+ 'line': 0,
+ 'column': 8,
+ 'requires_response': True,
+ 'response_codeeditor': editor
+ }
+
+ # Perform the request
+ with qtbot.waitSignal(editor.sig_response, timeout=30000) as blocker:
+ client.perform_request(LSPRequestTypes.DOCUMENT_COMPLETION,
+ completion_params)
+ _, response = blocker.args
+
+ # Assert the response has what we expect
+ completions = response['params']
+ assert 'os' in [x['label'] for x in completions]
+
+
+@pytest.mark.slow
+@pytest.mark.third
+def test_go_to_definition(lsp_client_and_editor, qtbot):
+ client, editor = lsp_client_and_editor
+
+ # Parameters to perform a textDocument/didChange request
+ params = {
+ 'file': 'test.py',
+ 'language': 'python',
+ 'version': 1,
+ 'text': "import os\nos.walk\n",
+ 'codeeditor': editor,
+ 'requires_response': False
+ }
+
+ # Perform the request
+ with qtbot.waitSignal(editor.sig_response, timeout=30000):
+ client.perform_request(LSPRequestTypes.DOCUMENT_DID_CHANGE, params)
+
+ # Parameters to perform a textDocument/definition request
+ go_to_definition_params = {
+ 'file': 'test.py',
+ 'line': 0,
+ 'column': 19,
+ 'requires_response': True,
+ 'response_codeeditor': editor
+ }
+
+ # Perform the request
+ with qtbot.waitSignal(editor.sig_response, timeout=30000) as blocker:
+ client.perform_request(LSPRequestTypes.DOCUMENT_DEFINITION,
+ go_to_definition_params)
+ _, response = blocker.args
+
+ # Assert the response has what we expect
+ definition = response['params']
+ assert 'os.py' in definition['file']
+
+
+@pytest.mark.slow
+@pytest.mark.third
+def test_local_signature(lsp_client_and_editor, qtbot):
+ client, editor = lsp_client_and_editor
+
+ # Parameters to perform a textDocument/didOpen request
+ text = dedent('''
+ def test(a, b):
+ """Test docstring"""
+ pass
+ test''')
+ params = {
+ 'file': 'test.py',
+ 'language': 'python',
+ 'version': 1,
+ 'text': text,
+ 'codeeditor': editor,
+ 'requires_response': False
+ }
+
+ # Perform the request
+ with qtbot.waitSignal(editor.sig_response, timeout=30000) as blocker:
+ client.perform_request(LSPRequestTypes.DOCUMENT_DID_CHANGE, params)
+
+ # Parameters to perform a textDocument/hover request
+ signature_params = {
+ 'file': 'test.py',
+ 'line': 4,
+ 'column': 0,
+ 'requires_response': True,
+ 'response_codeeditor': editor
+ }
+
+ # Perform the request
+ with qtbot.waitSignal(editor.sig_response, timeout=30000) as blocker:
+ client.perform_request(LSPRequestTypes.DOCUMENT_HOVER,
+ signature_params)
+ _, response = blocker.args
+
+ # Assert the response has what we expect
+ definition = response['params']
+ assert 'Test docstring' in definition
diff --git a/spyder/plugins/editor/lsp/transport/__init__.py b/spyder/plugins/editor/lsp/transport/__init__.py
new file mode 100644
index 00000000000..243060bd50b
--- /dev/null
+++ b/spyder/plugins/editor/lsp/transport/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
diff --git a/spyder_profiler/widgets/__init__.py b/spyder/plugins/editor/lsp/transport/common/__init__.py
similarity index 100%
rename from spyder_profiler/widgets/__init__.py
rename to spyder/plugins/editor/lsp/transport/common/__init__.py
diff --git a/spyder/plugins/editor/lsp/transport/common/consumer.py b/spyder/plugins/editor/lsp/transport/common/consumer.py
new file mode 100644
index 00000000000..9532b05fdd3
--- /dev/null
+++ b/spyder/plugins/editor/lsp/transport/common/consumer.py
@@ -0,0 +1,136 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+
+"""
+Spyder MS Language Server Protocol v3.0 base transport proxy implementation.
+
+This module handles and processes incoming messages sent by an LSP server,
+then it relays the information to the actual Spyder LSP client via ZMQ.
+"""
+
+
+import os
+import json
+import socket
+import logging
+from threading import Thread, Lock
+
+if not os.name == 'nt':
+ from pexpect.fdpexpect import fdspawn
+
+
+TIMEOUT = 5000
+PID = os.getpid()
+
+
+logger = logging.getLogger(__name__)
+
+
+class IncomingMessageThread(Thread):
+ """Base LSP message consumer."""
+
+ def __init__(self):
+ Thread.__init__(self)
+ self.stopped = False
+ self.daemon = True
+ self.expect_body = False
+ self.mutex = Lock()
+
+ def initialize(self, fd, zmq_sock, req_status, expectable=False):
+ self.fd = fd
+ self.expect = None
+ self.expectable = expectable
+ logger.info('Reading thread initialized')
+ self.read_incoming = self.read_posix
+ self.expect = self.fd
+ if not expectable:
+ if os.name == 'nt':
+ self.read_incoming = self.expect_windows
+ else:
+ self.expect = fdspawn(self.fd)
+ self.zmq_sock = zmq_sock
+ self.req_status = req_status
+
+ def read_posix(self):
+ self.expect.expect('\r\n\r\n', timeout=None)
+ headers = self.expect.before
+ headers = self.parse_headers(headers)
+ logger.debug(headers)
+ content_length = int(headers[b'Content-Length'])
+ body = self.expect.read(size=content_length)
+ return self.encode_body(body, headers)
+
+ def encode_body(self, body, headers):
+ encoding = 'utf8'
+ if b'Content-Type' in headers:
+ encoding = headers[b'Content-Type'].split(b'=')[-1].decode('utf8')
+ body = body.decode(encoding)
+ return body
+
+ def expect_windows(self):
+ buffer = b''
+ headers = b''
+ continue_reading = True
+ while continue_reading:
+ try:
+ buffer += self.read_num_bytes(1)
+ if b'\r\n\r\n' in buffer:
+ split = buffer.split(b'\r\n\r\n')
+ if len(split) == 2:
+ headers, buffer = split
+ continue_reading = False
+ except socket.error as e:
+ logger.error(e)
+ raise e
+ headers = self.parse_headers(headers)
+ logger.debug(headers)
+ content_length = int(headers[b'Content-Length'])
+ pending_bytes = content_length - len(buffer)
+ while pending_bytes > 0:
+ logger.debug('Pending bytes...' + str(pending_bytes))
+ recv = self.read_num_bytes(min(1024, pending_bytes))
+ buffer += recv
+ pending_bytes -= len(recv)
+ return self.encode_body(buffer, headers)
+
+ def run(self):
+ while True:
+ with self.mutex:
+ if self.stopped:
+ logger.debug('Stopping Thread...')
+ break
+ try:
+ body = self.read_incoming()
+ err = False
+ try:
+ body = json.loads(body)
+ except (ValueError, TypeError) as e:
+ err = True
+ logger.error(e)
+ if not err:
+ logger.debug(body)
+ self.zmq_sock.send_pyobj(body)
+ logger.debug('Message sent')
+ except socket.error as e:
+ logger.error(e)
+ logger.debug('Thread stopped.')
+
+ def parse_headers(self, headers):
+ logger.debug(headers)
+ headers = headers.split(b'\r\n')
+ header_dict = dict([x.split(b': ') for x in headers])
+ return header_dict
+
+ def stop(self):
+ with self.mutex:
+ self.stopped = True
+
+ def read_num_bytes(self, n):
+ """Subclasses should override this method"""
+ return NotImplementedError("Not implemented")
diff --git a/spyder/plugins/editor/lsp/transport/common/producer.py b/spyder/plugins/editor/lsp/transport/common/producer.py
new file mode 100644
index 00000000000..9341a2a562d
--- /dev/null
+++ b/spyder/plugins/editor/lsp/transport/common/producer.py
@@ -0,0 +1,114 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+
+"""
+Spyder MS Language Server Protocol v3.0 transport proxy base implementation.
+
+This module provides the base class from which each transport-specific client
+should inherit from. LanguageServerClient implements functions to handle
+incoming requests from the actual Spyder LSP client ZMQ queue and to
+encapsulate them into valid JSONRPC messages before sending them to the
+LSP server, using the specific transport mode.
+"""
+
+# Standard library imports
+import json
+import logging
+
+# Third party imports
+import zmq
+
+TIMEOUT = 5000
+
+logger = logging.getLogger(__name__)
+
+
+class LanguageServerClient(object):
+ """Base implementation of a v3.0 compilant language server client."""
+ CONTENT_LENGTH = 'Content-Length: {0}\r\n\r\n'
+
+ def __init__(self, zmq_in_port=7000, zmq_out_port=7001):
+ self.zmq_in_port = zmq_in_port
+ self.zmq_out_port = zmq_out_port
+ self.context = None
+ self.zmq_in_socket = None
+ self.zmq_out_socket = None
+
+ def finalize_initialization(self):
+ connected, connection_error = self.is_server_alive()
+
+ if not connected:
+ logger.error("The client was unable to establish a connection "
+ "with the Language Server. The error was: "
+ "{}".format(connection_error))
+ raise Exception("An error occurred while trying to create a "
+ "client to connect to the Language Server! The "
+ "error was\n\n{}".format(connection_error))
+
+ logger.info('Starting ZMQ connection...')
+ self.context = zmq.Context()
+ self.zmq_in_socket = self.context.socket(zmq.PAIR)
+ self.zmq_in_socket.connect("tcp://localhost:{0}".format(
+ self.zmq_in_port))
+ self.zmq_out_socket = self.context.socket(zmq.PAIR)
+ self.zmq_out_socket.connect("tcp://localhost:{0}".format(
+ self.zmq_out_port))
+ logger.info('Sending server_ready...')
+ self.zmq_out_socket.send_pyobj({'id': -1, 'method': 'server_ready',
+ 'params': {}})
+
+ def listen(self):
+ events = self.zmq_in_socket.poll(TIMEOUT)
+ # requests = []
+ while events > 0:
+ client_request = self.zmq_in_socket.recv_pyobj()
+ logger.debug("Client Event: {0}".format(client_request))
+ server_request = self.__compose_request(client_request['id'],
+ client_request['method'],
+ client_request['params'])
+ self.__send_request(server_request)
+ # self.zmq_socket.send_pyobj({'a': 'b'})
+ events -= 1
+
+ def __compose_request(self, id, method, params):
+ request = {
+ "jsonrpc": "2.0",
+ "id": id,
+ "method": method,
+ "params": params
+ }
+ return request
+
+ def __send_request(self, request):
+ json_req = json.dumps(request)
+ content = bytes(json_req.encode('utf-8'))
+ content_length = len(content)
+
+ logger.debug('Sending request of type: {0}'.format(request['method']))
+ logger.debug(json_req)
+
+ content_length = self.CONTENT_LENGTH.format(
+ content_length).encode('utf-8')
+ self.transport_send(bytes(content_length), content)
+
+ def transport_send(self, content_length, body):
+ """Subclasses should override this method"""
+ raise NotImplementedError("Not implemented")
+
+ def is_server_alive(self):
+ """Subclasses should override this method"""
+ raise NotImplementedError("Not implemented")
+
+ def start(self):
+ """Subclasses should override this method."""
+ raise NotImplementedError("Not implemented")
+
+ def stop(self):
+ """Subclasses should override this method."""
+ raise NotImplementedError("Not implemented")
diff --git a/spyder/plugins/editor/lsp/transport/main.py b/spyder/plugins/editor/lsp/transport/main.py
new file mode 100644
index 00000000000..854b3e39e0a
--- /dev/null
+++ b/spyder/plugins/editor/lsp/transport/main.py
@@ -0,0 +1,143 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+
+"""
+Spyder MS Language Server v3.0 transport proxy implementation.
+
+Main point-of-entry to start an LSP ZMQ/TCP transport proxy.
+"""
+
+# Standard library imports
+import argparse
+import logging
+import os
+import psutil
+import signal
+from functools import partial
+
+# Local imports
+from spyder.plugins.editor.lsp.transport.tcp.producer import (
+ TCPLanguageServerClient)
+from spyder.plugins.editor.lsp.transport.stdio.producer import (
+ StdioLanguageServerClient)
+from spyder.py3compat import getcwd
+
+
+logger = logging.getLogger(__name__)
+
+
+parser = argparse.ArgumentParser(
+ description='ZMQ Python-based MS Language-Server v3.0 client for Spyder')
+parser.add_argument('--zmq-in-port',
+ default=7000,
+ help="ZMQ (in) port to be contacted")
+parser.add_argument('--zmq-out-port',
+ default=7001,
+ help="ZMQ (out) port to be contacted")
+parser.add_argument('--server-host',
+ default='127.0.0.1',
+ help='Host that serves the ls-server')
+parser.add_argument('--server-port',
+ default=2087,
+ help="Deployment port of the ls-server")
+parser.add_argument('--server-log-file',
+ default=None,
+ help="Log file to register ls-server activity")
+parser.add_argument('--folder',
+ default=getcwd(),
+ help="Initial current working directory used to "
+ "initialize ls-server")
+parser.add_argument('--external-server',
+ action="store_true",
+ help="Do not start a local server")
+parser.add_argument('--stdio-server',
+ action="store_true",
+ help='Server communication should use stdio pipes')
+parser.add_argument('--transport-debug',
+ default=0,
+ type=int,
+ help='Verbosity level for log messages')
+args, extra_args = parser.parse_known_args()
+
+
+def logger_init(level):
+ """
+ Initialize the logger for this thread.
+
+ Sets the log level to ERROR (0), WARNING (1), INFO (2), or DEBUG (3),
+ depending on the argument `level`.
+ """
+ levellist = [logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG]
+ handler = logging.StreamHandler()
+ fmt = ('%(levelname) -10s %(asctime)s %(name) -30s %(funcName) '
+ '-35s %(lineno) -5d: %(message)s')
+ handler.setFormatter(logging.Formatter(fmt))
+ logger = logging.root
+ logger.addHandler(handler)
+ logger.setLevel(levellist[level])
+
+
+class TerminateSignal(Exception):
+ """Terminal exception descriptor."""
+ pass
+
+
+class SignalManager:
+ """Manage and intercept SIGTERM and SIGKILL signals."""
+
+ def __init__(self):
+ self.original_sigint = signal.getsignal(signal.SIGINT)
+ self.original_sigterm = signal.getsignal(signal.SIGTERM)
+ signal.signal(signal.SIGINT, self.exit_gracefully)
+ signal.signal(signal.SIGTERM, self.exit_gracefully)
+ if os.name == 'nt':
+ self.original_sigbreak = signal.getsignal(signal.SIGBREAK)
+ signal.signal(signal.SIGBREAK, self.exit_gracefully)
+
+ def exit_gracefully(self, signum, frame):
+ """Capture exit/kill signal and throw and exception."""
+ logger.info('Termination signal ({}) captured, '
+ 'initiating exit sequence'.format(signum))
+ raise TerminateSignal("Exit process!")
+
+ def restore(self):
+ """Restore signal handlers to their original settings."""
+ signal.signal(signal.SIGINT, self.original_sigint)
+ signal.signal(signal.SIGTERM, self.original_sigterm)
+ if os.name == 'nt':
+ signal.signal(signal.SIGBREAK, self.original_sigbreak)
+
+
+if __name__ == '__main__':
+ logger_init(args.transport_debug)
+ extra_args = [x for x in extra_args if len(x) > 0]
+ extra_args = ' '.join(extra_args)
+ logger.debug(extra_args)
+ process = psutil.Process()
+ sig_manager = SignalManager()
+ if args.stdio_server:
+ LanguageServerClient = partial(StdioLanguageServerClient,
+ server_args=extra_args,
+ log_file=args.server_log_file)
+ else:
+ LanguageServerClient = partial(TCPLanguageServerClient,
+ host=args.server_host,
+ port=args.server_port)
+ client = LanguageServerClient(zmq_in_port=args.zmq_in_port,
+ zmq_out_port=args.zmq_out_port)
+ client.start()
+ try:
+ while True:
+ client.listen()
+ except TerminateSignal:
+ pass
+ client.stop()
+ # sig_manager.restore()
+ process.terminate()
+ process.wait()
diff --git a/spyder_pylint/widgets/__init__.py b/spyder/plugins/editor/lsp/transport/stdio/__init__.py
similarity index 100%
rename from spyder_pylint/widgets/__init__.py
rename to spyder/plugins/editor/lsp/transport/stdio/__init__.py
diff --git a/spyder/plugins/editor/lsp/transport/stdio/consumer.py b/spyder/plugins/editor/lsp/transport/stdio/consumer.py
new file mode 100644
index 00000000000..5a54fe7db69
--- /dev/null
+++ b/spyder/plugins/editor/lsp/transport/stdio/consumer.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+"""
+Spyder MS Language Server Protocol v3.0 transport proxy implementation.
+
+This module handles and processes incoming stdin messages sent by an
+LSP server, then it relays the information to the actual Spyder LSP
+client via ZMQ.
+"""
+
+import logging
+from spyder.plugins.editor.lsp.transport.common.consumer import (
+ IncomingMessageThread)
+
+logger = logging.getLogger(__name__)
+
+
+class StdioIncomingMessageThread(IncomingMessageThread):
+ """Stdio socket consumer."""
+
+ def read_num_bytes(self, n):
+ return self.fd.read(n).encode('utf-8')
diff --git a/spyder/plugins/editor/lsp/transport/stdio/producer.py b/spyder/plugins/editor/lsp/transport/stdio/producer.py
new file mode 100644
index 00000000000..a30f337802f
--- /dev/null
+++ b/spyder/plugins/editor/lsp/transport/stdio/producer.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+
+"""
+Spyder MS Language Server Protocol v3.0 transport proxy implementation.
+
+This module handles incoming requests from the actual Spyder LSP client ZMQ
+queue, encapsulates them into valid JSONRPC messages and sends them to a
+LSP server via stdio pipes.
+"""
+
+# Standard library imports
+import os
+import time
+import logging
+
+# Local imports
+from spyder.plugins.editor.lsp.transport.stdio.consumer import (
+ StdioIncomingMessageThread)
+from spyder.plugins.editor.lsp.transport.common.producer import (
+ LanguageServerClient)
+
+from pexpect import popen_spawn
+
+logger = logging.getLogger(__name__)
+
+
+class StdioLanguageServerClient(LanguageServerClient):
+ """Implementation of a v3.0 compilant language server stdio client."""
+ MAX_TIMEOUT_TIME = 20000
+
+ def __init__(self, server_args='', log_file='',
+ zmq_in_port=7000, zmq_out_port=7001):
+ super(StdioLanguageServerClient, self).__init__(
+ zmq_in_port, zmq_out_port)
+ self.req_status = {}
+ self.process = None
+ logger.debug(server_args)
+ logger.debug('Redirect stderr to {0}'.format(log_file))
+ self.process = popen_spawn.PopenSpawn(server_args)
+ logger.info('Connecting to language server on stdio')
+ super(StdioLanguageServerClient, self).finalize_initialization()
+ self.reading_thread = StdioIncomingMessageThread()
+ self.reading_thread.initialize(self.process, self.zmq_out_socket,
+ self.req_status, expectable=True)
+
+ def start(self):
+ self.reading_thread.start()
+ logger.info('Ready to receive/attend requests and responses!')
+
+ def stop(self):
+ logger.info('Closing consumer thread...')
+ self.reading_thread.stop()
+ logger.debug('Joining thread...')
+ self.reading_thread.join()
+ logger.debug('Exit routine should be complete')
+
+ def transport_send(self, content_length, body):
+ if os.name == 'nt':
+ content_length = content_length.decode('utf-8')
+ body = body.decode('utf-8')
+ self.process.write(content_length)
+ self.process.write(body)
+
+ def is_server_alive(self):
+ """This method verifies if stdout is broken."""
+ connected = False
+ connection_error = None
+ initial_time = time.time()
+ try:
+ while not connected:
+ connected = not self.process.proc.poll()
+ if time.time() - initial_time > self.MAX_TIMEOUT_TIME:
+ connection_error = 'Timeout communication period exceeded'
+ break
+ except Exception as e:
+ connection_error = e
+ return connected, connection_error
diff --git a/spyder/plugins/editor/lsp/transport/tcp/__init__.py b/spyder/plugins/editor/lsp/transport/tcp/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/spyder/plugins/editor/lsp/transport/tcp/consumer.py b/spyder/plugins/editor/lsp/transport/tcp/consumer.py
new file mode 100644
index 00000000000..1dec21b507c
--- /dev/null
+++ b/spyder/plugins/editor/lsp/transport/tcp/consumer.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+"""
+Spyder MS Language Server Protocol v3.0 transport proxy implementation.
+
+This module handles and processes incoming TCP messages sent by an LSP server,
+then it relays the information to the actual Spyder LSP client via ZMQ.
+"""
+
+import logging
+from spyder.plugins.editor.lsp.transport.common.consumer import (
+ IncomingMessageThread)
+
+logger = logging.getLogger(__name__)
+
+
+class TCPIncomingMessageThread(IncomingMessageThread):
+ """TCP socket consumer."""
+
+ def read_num_bytes(self, n):
+ return self.fd.recv(n)
diff --git a/spyder/plugins/editor/lsp/transport/tcp/producer.py b/spyder/plugins/editor/lsp/transport/tcp/producer.py
new file mode 100644
index 00000000000..5014fecb2d0
--- /dev/null
+++ b/spyder/plugins/editor/lsp/transport/tcp/producer.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+
+"""
+Spyder MS Language Server Protocol v3.0 transport proxy implementation.
+
+This module handles incoming requests from the actual Spyder LSP client ZMQ
+queue, encapsulates them into valid JSONRPC messages and sends them to a
+LSP server via TCP.
+"""
+
+# Standard library imports
+import logging
+import socket
+import time
+
+# Local imports
+from spyder.plugins.editor.lsp.transport.tcp.consumer import (
+ TCPIncomingMessageThread)
+from spyder.plugins.editor.lsp.transport.common.producer import (
+ LanguageServerClient)
+
+logger = logging.getLogger(__name__)
+
+
+class TCPLanguageServerClient(LanguageServerClient):
+ """Implementation of a v3.0 compilant language server TCP client."""
+ MAX_TIMEOUT_TIME = 20000
+
+ def __init__(self, host='127.0.0.1', port=2087, zmq_in_port=7000,
+ zmq_out_port=7001):
+ LanguageServerClient.__init__(self, zmq_in_port, zmq_out_port)
+ self.req_status = {}
+ self.host = host
+ self.port = port
+ self.socket = None
+ # self.request_seq = 1
+ logger.info('Connecting to language server at {0}:{1}'.format(
+ self.host, self.port))
+ super(TCPLanguageServerClient, self).finalize_initialization()
+ self.socket.setblocking(True)
+ self.reading_thread = TCPIncomingMessageThread()
+ self.reading_thread.initialize(self.socket, self.zmq_out_socket,
+ self.req_status)
+
+ def start(self):
+ self.reading_thread.start()
+ logger.info('Ready to receive/attend requests and responses!')
+
+ def stop(self):
+ logger.info('Closing TCP socket...')
+ self.socket.close()
+ logger.info('Closing consumer thread...')
+ self.reading_thread.stop()
+ logger.debug('Joining thread...')
+ self.reading_thread.join()
+ logger.debug('Exit routine should be complete')
+
+ def transport_send(self, content_length, body):
+ logger.debug('Sending message via TCP')
+ self.socket.send(content_length)
+ self.socket.send(body)
+
+ def is_server_alive(self):
+ connected = False
+ initial_time = time.time()
+ connection_error = None
+ while not connected:
+ try:
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.socket.connect((self.host, int(self.port)))
+ connected = True
+ except Exception as e:
+ connection_error = e
+
+ if time.time() - initial_time > self.MAX_TIMEOUT_TIME:
+ break
+ return connected, connection_error
diff --git a/spyder/plugins/editor/panels/__init__.py b/spyder/plugins/editor/panels/__init__.py
new file mode 100644
index 00000000000..3808ae59e62
--- /dev/null
+++ b/spyder/plugins/editor/panels/__init__.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+"""
+This module contains the editor panels.
+
+Panels are widgets used to extend editor functionalities.
+"""
+
+from .classfunctiondropdown import ClassFunctionDropdown
+from .codefolding import FoldingPanel
+from .debugger import DebuggerPanel
+from .edgeline import EdgeLine
+from .indentationguides import IndentationGuide
+from .linenumber import LineNumberArea
+from .manager import PanelsManager
+from .scrollflag import ScrollFlagArea
diff --git a/spyder/widgets/panels/classfunctiondropdown.py b/spyder/plugins/editor/panels/classfunctiondropdown.py
similarity index 92%
rename from spyder/widgets/panels/classfunctiondropdown.py
rename to spyder/plugins/editor/panels/classfunctiondropdown.py
index 8f1129f7ed0..45e78ce29e7 100644
--- a/spyder/widgets/panels/classfunctiondropdown.py
+++ b/spyder/plugins/editor/panels/classfunctiondropdown.py
@@ -18,17 +18,12 @@
from qtpy.QtCore import QSize
from spyder.api.panel import Panel
-from spyder.widgets.sourcecode.folding import FoldScope
-from spyder.utils.editor import TextBlockHelper
-from spyder.utils.syntaxhighlighters import OutlineExplorerData as OED
+from spyder.plugins.editor.utils.folding import FoldScope
+from spyder.plugins.editor.utils.editor import TextBlockHelper
+from spyder.plugins.outlineexplorer.api import OutlineExplorerData as OED
from spyder.utils import icon_manager as ima
-DUMMY_OED = OED()
-DUMMY_OED.fold_level = 0
-DUMMY_OED.text = ""
-
-
def populate(combobox, data):
"""
Populate the given ``combobox`` with the class or function names.
@@ -83,27 +78,24 @@ def _get_fold_levels(editor):
Parameters
----------
- editor : :class:`spyder.widgets.sourcecode.codeeditor.CodeEditor`
+ editor : :class:`spyder.plugins.editor.widgets.codeeditor.CodeEditor`
Returns
-------
folds : list of :class:`FoldScopeHelper`
A list of all the class or function defintion fold points.
"""
- block = editor.document().firstBlock()
- oed = editor.get_outlineexplorer_data()
+
folds = []
parents = []
prev = None
- while block.isValid():
- if TextBlockHelper.is_fold_trigger(block):
+ for oedata in editor.outlineexplorer_data_list():
+ if TextBlockHelper.is_fold_trigger(oedata.block):
try:
- data = oed[block.firstLineNumber()]
-
- if data.def_type in (OED.CLASS, OED.FUNCTION):
- fsh = FoldScopeHelper(FoldScope(block), data)
+ if oedata.def_type in (OED.CLASS, OED.FUNCTION):
+ fsh = FoldScopeHelper(FoldScope(oedata.block), oedata)
# Determine the parents of the item using a stack.
_adjust_parent_stack(fsh, prev, parents)
@@ -114,9 +106,6 @@ def _get_fold_levels(editor):
prev = fsh
except KeyError:
pass
-
- block = block.next()
-
return folds
@@ -247,8 +236,8 @@ class FoldScopeHelper(object):
Parameters
----------
- fold_scope : :class:`spyder.widgets.sourcecode.folding.FoldScope`
- oed : :class:`spyder.utils.syntaxhighlighters.OutlineExplorerData`
+ fold_scope : :class:`spyder.plugins.editor.utils.folding.FoldScope`
+ oed : :class:`spyder.plugins.outlineexplorer.api.OutlineExplorerData`
Properties
----------
@@ -331,7 +320,7 @@ class ClassFunctionDropdown(Panel):
Parameters
----------
- editor : :class:`spyder.widgets.sourcecode.codeeditor.CodeEditor`
+ editor : :class:`spyder.plugins.editor.widgets.codeeditor.CodeEditor`
The editor to act on.
"""
diff --git a/spyder/widgets/panels/codefolding.py b/spyder/plugins/editor/panels/codefolding.py
similarity index 96%
rename from spyder/widgets/panels/codefolding.py
rename to spyder/plugins/editor/panels/codefolding.py
index d26be11ca5b..6fe88c8f021 100644
--- a/spyder/widgets/panels/codefolding.py
+++ b/spyder/plugins/editor/panels/codefolding.py
@@ -1,27 +1,37 @@
# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2013-2016 Colin Duquesnoy and others (see pyqode/AUTHORS.rst)
+# Copyright (c) 2016- Spyder Project Contributors (see AUTHORS.txt)
#
-# Copyright © Spyder Project Contributors
-# Copyright © <2013-2016>
-# Licensed under the terms of the MIT License
-# (see spyder/__init__.py for details)
+# Distributed under the terms of the MIT License
+# (see NOTICE.txt in the Spyder root directory for details)
+# -----------------------------------------------------------------------------
+
"""
This module contains the marker panel.
-Adapted from https://github.com/pyQode/pyqode.core/blob/master/pyqode/core/panels/folding.py
+
+Adapted from pyqode/core/panels/folding.py of the
+`PyQode project `_.
+Original file:
+
"""
+
+# Standard library imports
import sys
+# Third party imports
from qtpy.QtCore import Signal, QSize, QPointF, QRectF, QRect, Qt
from qtpy.QtWidgets import QApplication, QStyleOptionViewItem, QStyle
from qtpy.QtGui import (QTextBlock, QColor, QFontMetricsF, QPainter,
QLinearGradient, QPen, QPalette, QResizeEvent,
QCursor)
-from spyder.widgets.sourcecode.api.decoration import (TextDecoration,
- DRAW_ORDERS)
-from spyder.widgets.sourcecode.folding import FoldScope
+# Local imports
+from spyder.plugins.editor.api.decoration import TextDecoration, DRAW_ORDERS
+from spyder.plugins.editor.utils.folding import FoldScope
from spyder.api.panel import Panel
-from spyder.utils.editor import (TextBlockHelper, TextHelper, DelayJobRunner,
- drift_color)
+from spyder.plugins.editor.utils.editor import (TextBlockHelper, TextHelper,
+ DelayJobRunner, drift_color)
import spyder.utils.icon_manager as ima
@@ -338,7 +348,7 @@ def _get_scope_highlight_color(self):
Gets the base scope highlight color (derivated from the editor
background)
- For lighter themes will be a darker color,
+ For lighter themes will be a darker color,
and for darker ones will be a lighter color
"""
color = self.editor.sideareas_color
diff --git a/spyder/plugins/editor/panels/debugger.py b/spyder/plugins/editor/panels/debugger.py
new file mode 100644
index 00000000000..6348d54400c
--- /dev/null
+++ b/spyder/plugins/editor/panels/debugger.py
@@ -0,0 +1,153 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+"""
+This module contains the DebuggerPanel panel
+"""
+from qtpy.QtCore import QSize, Qt, QRect, Slot
+from qtpy.QtGui import QPainter, QFontMetrics
+
+from spyder.utils import icon_manager as ima
+from spyder.api.panel import Panel
+from spyder.config.base import debug_print
+
+
+class DebuggerPanel(Panel):
+ """Debugger panel for show information about the debugging in process."""
+
+ def __init__(self):
+ """Initialize panel."""
+ Panel.__init__(self)
+
+ self.setMouseTracking(True)
+ self.scrollable = True
+
+ self.line_number_hint = None
+ self._current_line_arrow = None
+ self.stop = False
+
+ # Diccionary of QIcons to draw in the panel
+ self.icons = {'breakpoint': ima.icon('breakpoint_big'),
+ 'transparent': ima.icon('breakpoint_transparent'),
+ 'condition': ima.icon('breakpoint_cond_big'),
+ 'arrow': ima.icon('arrow_debugger')}
+
+ def set_current_line_arrow(self, n):
+ self._current_line_arrow = n
+
+ def sizeHint(self):
+ """Override Qt method.
+
+ Returns the widget size hint (based on the editor font size).
+ """
+ fm = QFontMetrics(self.editor.font())
+ size_hint = QSize(fm.height(), fm.height())
+ if size_hint.width() > 16:
+ size_hint.setWidth(16)
+ return size_hint
+
+ def _draw_breakpoint_icon(self, top, painter, icon_name):
+ """Draw the given breakpoint pixmap.
+
+ Args:
+ top (int): top of the line to draw the breakpoint icon.
+ painter (QPainter)
+ icon_name (srt): key of icon to draw (see: self.icons)
+ """
+ rect = QRect(0, top, self.sizeHint().width(),
+ self.sizeHint().height())
+ try:
+ icon = self.icons[icon_name]
+ except KeyError as e:
+ debug_print("Breakpoint icon doen't exist, {}".format(e))
+ else:
+ icon.paint(painter, rect)
+
+ @Slot()
+ def stop_clean(self):
+ """Handle debugging state. The debugging is not running."""
+ self.stop = True
+ self.update()
+
+ @Slot()
+ def start_clean(self):
+ """Handle debugging state. The debugging is running."""
+ self.stop = False
+ self.update()
+
+ def paintEvent(self, event):
+ """Override Qt method.
+
+ Paint breakpoints icons.
+ """
+ super(DebuggerPanel, self).paintEvent(event)
+ painter = QPainter(self)
+ painter.fillRect(event.rect(), self.editor.sideareas_color)
+
+ for top, line_number, block in self.editor.visible_blocks:
+ if self.line_number_hint == line_number:
+ self._draw_breakpoint_icon(top, painter, 'transparent')
+ if self._current_line_arrow == line_number and not self.stop:
+ self._draw_breakpoint_icon(top, painter, 'arrow')
+
+ data = block.userData()
+ if data is None or not data.breakpoint:
+ continue
+
+ if data.breakpoint_condition is None:
+ self._draw_breakpoint_icon(top, painter, 'breakpoint')
+ else:
+ self._draw_breakpoint_icon(top, painter, 'condition')
+
+ def mousePressEvent(self, event):
+ """Override Qt method
+
+ Add/remove breakpoints by single click.
+ """
+ line_number = self.editor.get_linenumber_from_mouse_event(event)
+ shift = event.modifiers() & Qt.ShiftModifier
+ self.editor.debugger.toogle_breakpoint(line_number,
+ edit_condition=shift)
+
+ def mouseMoveEvent(self, event):
+ """Override Qt method.
+
+ Draw semitransparent breakpoint hint.
+ """
+ self.line_number_hint = self.editor.get_linenumber_from_mouse_event(
+ event)
+ self.update()
+
+ def leaveEvent(self, event):
+ """Override Qt method.
+
+ Remove semitransparent breakpoint hint
+ """
+ self.line_number_hint = None
+ self.update()
+
+ def wheelEvent(self, event):
+ """Override Qt method.
+
+ Needed for scroll down the editor when scrolling over the panel.
+ """
+ self.editor.wheelEvent(event)
+
+ def on_state_changed(self, state):
+ """Change visibility and connect/disconnect signal.
+
+ Args:
+ state (bool): Activate/deactivate.
+ """
+ if state:
+ self.editor.sig_breakpoints_changed.connect(self.repaint)
+ self.editor.sig_debug_stop.connect(self.set_current_line_arrow)
+ self.editor.sig_debug_stop[()].connect(self.stop_clean)
+ self.editor.sig_debug_start.connect(self.start_clean)
+ else:
+ self.editor.sig_breakpoints_changed.disconnect(self.repaint)
+ self.editor.sig_debug_stop.disconnect(self.set_current_line_arrow)
+ self.editor.sig_debug_stop[()].disconnect(self.stop_clean)
+ self.editor.sig_debug_start.disconnect(self.start_clean)
diff --git a/spyder/widgets/panels/edgeline.py b/spyder/plugins/editor/panels/edgeline.py
similarity index 100%
rename from spyder/widgets/panels/edgeline.py
rename to spyder/plugins/editor/panels/edgeline.py
diff --git a/spyder/plugins/editor/panels/indentationguides.py b/spyder/plugins/editor/panels/indentationguides.py
new file mode 100644
index 00000000000..6a983f82638
--- /dev/null
+++ b/spyder/plugins/editor/panels/indentationguides.py
@@ -0,0 +1,96 @@
+
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+This module contains the indentation guide panel.
+"""
+
+from qtpy.QtCore import Qt, QRect, QPoint
+from qtpy.QtGui import QPainter, QColor
+
+from spyder.plugins.editor.utils.editor import TextBlockHelper
+from spyder.api.panel import Panel
+
+
+class IndentationGuide(Panel):
+ """Indentation guides to easy identify nested blocks."""
+
+ # --- Qt Overrides
+ # -----------------------------------------------------------------
+ def __init__(self, editor):
+ """Initialize IndentationGuide panel.
+ i_width(int): identation width in characters.
+ """
+ Panel.__init__(self, editor)
+ self.color = Qt.darkGray
+ self.i_width = 4
+
+ def paintEvent(self, event):
+ """Override Qt method."""
+ painter = QPainter(self)
+
+ color = QColor(self.color)
+ color.setAlphaF(.5)
+ painter.setPen(color)
+ offset = self.editor.document().documentMargin() + \
+ self.editor.contentOffset().x()
+
+ for _, line_number, block in self.editor.visible_blocks:
+
+ indentation = TextBlockHelper.get_fold_lvl(block)
+ ref_lvl = indentation
+ block = block.next()
+ last_line = block.blockNumber()
+ lvl = TextBlockHelper.get_fold_lvl(block)
+ if ref_lvl == lvl: # for zone set programmatically such as imports
+ # in pyqode.python
+ ref_lvl -= 1
+
+ while (block.isValid() and
+ TextBlockHelper.get_fold_lvl(block) > ref_lvl):
+ last_line = block.blockNumber()
+ block = block.next()
+
+ end_of_sub_fold = block
+ if last_line:
+ block = block.document().findBlockByNumber(last_line)
+ while ((block.blockNumber()) and (block.text().strip() == ''
+ or block.text().strip().startswith('#'))):
+ block = block.previous()
+ last_line = block.blockNumber()
+
+ block = self.editor.document().findBlockByNumber(line_number)
+ top = int(self.editor.blockBoundingGeometry(block).translated(
+ self.editor.contentOffset()).top())
+ bottom = top + int(self.editor.blockBoundingRect(block).height())
+
+ indentation = TextBlockHelper.get_fold_lvl(block)
+
+ for i in range(1, indentation):
+ if (line_number > last_line and
+ TextBlockHelper.get_fold_lvl(end_of_sub_fold) <= i):
+ continue
+ else:
+ x = self.editor.fontMetrics().width(i * self.i_width *
+ '9') + offset
+ painter.drawLine(x, top, x, bottom)
+
+ # --- Other methods
+ # -----------------------------------------------------------------
+
+ def set_enabled(self, state):
+ """Toggle edge line visibility."""
+ self._enabled = state
+ self.setVisible(state)
+
+ def update_color(self):
+ """Set color using syntax highlighter color for comments."""
+ self.color = self.editor.highlighter.get_color_name('comment')
+
+ def set_indentation_width(self, indentation_width):
+ """Set indentation width to be used to draw indent guides."""
+ self.i_width = indentation_width
diff --git a/spyder/widgets/panels/linenumber.py b/spyder/plugins/editor/panels/linenumber.py
similarity index 75%
rename from spyder/widgets/panels/linenumber.py
rename to spyder/plugins/editor/panels/linenumber.py
index 91a550bc98f..96b5ffb98e5 100644
--- a/spyder/widgets/panels/linenumber.py
+++ b/spyder/plugins/editor/panels/linenumber.py
@@ -3,6 +3,7 @@
# Copyright © Spyder Project Contributors
# Licensed under the terms of the MIT License
# (see spyder/__init__.py for details)
+
"""
This module contains the Line Number panel
"""
@@ -16,6 +17,7 @@
from spyder.utils import icon_manager as ima
from spyder.utils.programs import check_version
from spyder.api.panel import Panel
+from spyder.plugins.editor.lsp import DiagnosticSeverity
QT55_VERSION = check_version(QT_VERSION, "5.5", ">=")
@@ -36,12 +38,13 @@ def __init__(self, editor):
# Markers
self._markers_margin = True
- self._markers_margin_width = 15
- self.error_pixmap = ima.icon('error').pixmap(QSize(14, 14))
- self.warning_pixmap = ima.icon('warning').pixmap(QSize(14, 14))
- self.todo_pixmap = ima.icon('todo').pixmap(QSize(14, 14))
- self.bp_pixmap = ima.icon('breakpoint_big').pixmap(QSize(14, 14))
- self.bpc_pixmap = ima.icon('breakpoint_cond_big').pixmap(QSize(14, 14))
+
+ # Icons
+ self.error_icon = ima.icon('error')
+ self.warning_icon = ima.icon('warning')
+ self.info_icon = ima.icon('information')
+ self.hint_icon = ima.icon('hint')
+ self.todo_icon = ima.icon('todo')
# Line number area management
self._margin = True
@@ -57,7 +60,6 @@ def paintEvent(self, event):
Painting line number area
"""
-
painter = QPainter(self)
painter.fillRect(event.rect(), self.editor.sideareas_color)
# This is needed to make that the font size of line numbers
@@ -69,13 +71,13 @@ def paintEvent(self, event):
active_block = self.editor.textCursor().block()
active_line_number = active_block.blockNumber() + 1
- def draw_pixmap(ytop, pixmap):
+ def draw_pixmap(xleft, ytop, pixmap):
if not QT55_VERSION:
pixmap_height = pixmap.height()
else:
# scale pixmap height to device independent pixels
pixmap_height = pixmap.height() / pixmap.devicePixelRatio()
- painter.drawPixmap(0, ytop + (font_height-pixmap_height) / 2,
+ painter.drawPixmap(xleft, ytop + (font_height-pixmap_height) / 2,
pixmap)
for top, line_number, block in self.editor.visible_blocks:
@@ -94,23 +96,37 @@ def draw_pixmap(ytop, pixmap):
Qt.AlignRight | Qt.AlignBottom,
to_text_string(line_number))
+ size = self.get_markers_margin() - 2
+ icon_size = QSize(size, size)
+
data = block.userData()
if self._markers_margin and data:
if data.code_analysis:
- for _message, error in data.code_analysis:
- if error:
- break
- if error:
- draw_pixmap(top, self.error_pixmap)
- else:
- draw_pixmap(top, self.warning_pixmap)
+ errors = 0
+ warnings = 0
+ infos = 0
+ hints = 0
+ for _, _, sev, _ in data.code_analysis:
+ errors += sev == DiagnosticSeverity.ERROR
+ warnings += sev == DiagnosticSeverity.WARNING
+ infos += sev == DiagnosticSeverity.INFORMATION
+ hints += sev == DiagnosticSeverity.HINT
+
+ if errors:
+ draw_pixmap(1, top, self.error_icon.pixmap(icon_size))
+ elif warnings:
+ draw_pixmap(1, top, self.warning_icon.pixmap(icon_size))
+ elif infos:
+ draw_pixmap(1, top, self.info_icon.pixmap(icon_size))
+ elif hints:
+ draw_pixmap(1, top, self.hint_icon.pixmap(icon_size))
+
if data.todo:
- draw_pixmap(top, self.todo_pixmap)
- if data.breakpoint:
- if data.breakpoint_condition is None:
- draw_pixmap(top, self.bp_pixmap)
- else:
- draw_pixmap(top, self.bpc_pixmap)
+ draw_pixmap(1, top, self.todo_icon.pixmap(icon_size))
+
+ def leaveEvent(self, event):
+ """Override Qt method."""
+ self.editor.hide_tooltip()
def mouseMoveEvent(self, event):
"""Override Qt method.
@@ -126,21 +142,14 @@ def mouseMoveEvent(self, event):
check = self._released == -1
if data and data.code_analysis and check:
self.editor.show_code_analysis_results(line_number,
- data.code_analysis)
+ data)
+ else:
+ self.editor.hide_tooltip()
if event.buttons() == Qt.LeftButton:
self._released = line_number
self.editor.select_lines(self._pressed, self._released)
- def mouseDoubleClickEvent(self, event):
- """Override Qt method.
-
- Add or remove breakpoints.
- """
- line_number = self.editor.get_linenumber_from_mouse_event(event)
- shift = event.modifiers() & Qt.ShiftModifier
- self.editor.add_remove_breakpoint(line_number, edit_condition=shift)
-
def mousePressEvent(self, event):
"""Override Qt method
@@ -181,11 +190,11 @@ def compute_width(self):
def get_markers_margin(self):
if self._markers_margin:
- return self._markers_margin_width
+ font_height = self.editor.fontMetrics().height() + 2
+ return font_height
else:
return 0
-
def setup_margins(self, linenumbers=True, markers=True):
"""
Setup margin settings
diff --git a/spyder/plugins/editor/panels/manager.py b/spyder/plugins/editor/panels/manager.py
new file mode 100644
index 00000000000..62fdf30222f
--- /dev/null
+++ b/spyder/plugins/editor/panels/manager.py
@@ -0,0 +1,323 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2013-2016 Colin Duquesnoy and others (see pyqode/AUTHORS.rst)
+# Copyright (c) 2016- Spyder Project Contributors (see AUTHORS.txt)
+#
+# Distributed under the terms of the MIT License
+# (see NOTICE.txt in the Spyder root directory for details)
+# -----------------------------------------------------------------------------
+
+"""
+Contains the panels controller, drawing the panel inside CodeEditor's margins.
+
+Not all panels are using PanelsManager, but future panels should use it.
+
+Adapted from pyqode/core/managers/panels.py of the
+`PyQode project `_.
+Original file:
+
+"""
+
+import logging
+
+
+# Local imports
+from spyder.api.manager import Manager
+from spyder.api.panel import Panel
+from spyder.py3compat import is_text_string
+
+
+logger = logging.getLogger(__name__)
+
+
+class PanelsManager(Manager):
+ """
+ Manage the list of panels and draw them inside the margins of
+ CodeEditor widgets.
+ """
+ def __init__(self, editor):
+ super(PanelsManager, self).__init__(editor)
+ self._cached_cursor_pos = (-1, -1)
+ self._margin_sizes = (0, 0, 0, 0)
+ self._top = self._left = self._right = self._bottom = -1
+ self._panels = {
+ Panel.Position.TOP: {},
+ Panel.Position.LEFT: {},
+ Panel.Position.RIGHT: {},
+ Panel.Position.BOTTOM: {},
+ Panel.Position.FLOATING: {}
+ }
+ try:
+ editor.blockCountChanged.connect(self._update_viewport_margins)
+ editor.updateRequest.connect(self._update)
+ except AttributeError:
+ # QTextEdit
+ editor.document().blockCountChanged.connect(
+ self._update_viewport_margins)
+
+ def register(self, panel, position=Panel.Position.LEFT):
+ """
+ Installs a panel on the editor.
+
+ :param panel: Panel to install
+ :param position: Position where the panel must be installed.
+ :return: The installed panel
+ """
+ assert panel is not None
+ pos_to_string = {
+ Panel.Position.BOTTOM: 'bottom',
+ Panel.Position.LEFT: 'left',
+ Panel.Position.RIGHT: 'right',
+ Panel.Position.TOP: 'top',
+ Panel.Position.FLOATING: 'floating'
+ }
+ logger.debug('adding panel %s at %s' % (panel.name,
+ pos_to_string[position]))
+ panel.order_in_zone = len(self._panels[position])
+ self._panels[position][panel.name] = panel
+ panel.position = position
+ panel.on_install(self.editor)
+ logger.debug('panel %s installed' % panel.name)
+ return panel
+
+ def remove(self, name_or_klass):
+ """
+ Removes the specified panel.
+
+ :param name_or_klass: Name or class of the panel to remove.
+ :return: The removed panel
+ """
+ logger.debug('removing panel %s' % name_or_klass)
+ panel = self.get(name_or_klass)
+ panel.on_uninstall()
+ panel.hide()
+ panel.setParent(None)
+ return self._panels[panel.position].pop(panel.name, None)
+
+ def clear(self):
+ """Removes all panel from the CodeEditor."""
+ for i in range(4):
+ while len(self._panels[i]):
+ key = sorted(list(self._panels[i].keys()))[0]
+ panel = self.remove(key)
+ panel.setParent(None)
+ panel.deleteLater()
+
+ def get(self, name_or_klass):
+ """
+ Gets a specific panel instance.
+
+ :param name_or_klass: Name or class of the panel to retrieve.
+ :return: The specified panel instance.
+ """
+ if not is_text_string(name_or_klass):
+ name_or_klass = name_or_klass.__name__
+ for zone in range(4):
+ try:
+ panel = self._panels[zone][name_or_klass]
+ except KeyError:
+ pass
+ else:
+ return panel
+ raise KeyError(name_or_klass)
+
+ def keys(self):
+ """Returns the list of installed panel names."""
+ return self._modes.keys()
+
+ def values(self):
+ """Returns the list of installed panels."""
+ return self._modes.values()
+
+ def __iter__(self):
+ lst = []
+ for zone, zone_dict in self._panels.items():
+ for name, panel in zone_dict.items():
+ lst.append(panel)
+ return iter(lst)
+
+ def __len__(self):
+ lst = []
+ for zone, zone_dict in self._panels.items():
+ for name, panel in zone_dict.items():
+ lst.append(panel)
+ return len(lst)
+
+ def panels_for_zone(self, zone):
+ """
+ Gets the list of panels attached to the specified zone.
+
+ :param zone: Panel position.
+
+ :return: List of panels instances.
+ """
+ return list(self._panels[zone].values())
+
+ def refresh(self):
+ """Refreshes the editor panels (resize and update margins)."""
+ logger.debug('Refresh panels')
+ self.resize()
+ self._update(self.editor.contentsRect(), 0,
+ force_update_margins=True)
+
+ def resize(self):
+ """Resizes panels."""
+ crect = self.editor.contentsRect()
+ view_crect = self.editor.viewport().contentsRect()
+ s_bottom, s_left, s_right, s_top = self._compute_zones_sizes()
+ tw = s_left + s_right
+ th = s_bottom + s_top
+ w_offset = crect.width() - (view_crect.width() + tw)
+ h_offset = crect.height() - (view_crect.height() + th)
+ left = 0
+ panels = self.panels_for_zone(Panel.Position.LEFT)
+ panels.sort(key=lambda panel: panel.order_in_zone, reverse=True)
+ for panel in panels:
+ if not panel.isVisible():
+ continue
+ panel.adjustSize()
+ size_hint = panel.sizeHint()
+ panel.setGeometry(crect.left() + left,
+ crect.top() + s_top,
+ size_hint.width(),
+ crect.height() - s_bottom - s_top - h_offset)
+ left += size_hint.width()
+ right = 0
+ panels = self.panels_for_zone(Panel.Position.RIGHT)
+ panels.sort(key=lambda panel: panel.order_in_zone, reverse=True)
+ for panel in panels:
+ if not panel.isVisible():
+ continue
+ size_hint = panel.sizeHint()
+ panel.setGeometry(
+ crect.right() - right - size_hint.width() - w_offset,
+ crect.top() + s_top,
+ size_hint.width(),
+ crect.height() - s_bottom - s_top - h_offset)
+ right += size_hint.width()
+ top = 0
+ panels = self.panels_for_zone(Panel.Position.TOP)
+ panels.sort(key=lambda panel: panel.order_in_zone)
+ for panel in panels:
+ if not panel.isVisible():
+ continue
+ size_hint = panel.sizeHint()
+ panel.setGeometry(crect.left(),
+ crect.top() + top,
+ crect.width() - w_offset,
+ size_hint.height())
+ top += size_hint.height()
+ bottom = 0
+ panels = self.panels_for_zone(Panel.Position.BOTTOM)
+ panels.sort(key=lambda panel: panel.order_in_zone)
+ for panel in panels:
+ if not panel.isVisible():
+ continue
+ size_hint = panel.sizeHint()
+ panel.setGeometry(
+ crect.left(),
+ crect.bottom() - bottom - size_hint.height() - h_offset,
+ crect.width() - w_offset,
+ size_hint.height())
+ bottom += size_hint.height()
+
+ def update_floating_panels(self):
+ """Update foating panels."""
+ crect = self.editor.contentsRect()
+ panels = self.panels_for_zone(Panel.Position.FLOATING)
+ for panel in panels:
+ if not panel.isVisible():
+ continue
+ panel.set_geometry(crect)
+
+ def _update(self, rect, delta_y, force_update_margins=False):
+ """Updates panels."""
+ if not self:
+ return
+ for zones_id, zone in self._panels.items():
+ if zones_id == Panel.Position.TOP or \
+ zones_id == Panel.Position.BOTTOM:
+ continue
+ panels = list(zone.values())
+ for panel in panels:
+ if panel.scrollable and delta_y:
+ panel.scroll(0, delta_y)
+ line, col = self.editor.get_cursor_line_column()
+ oline, ocol = self._cached_cursor_pos
+ if line != oline or col != ocol or panel.scrollable:
+ panel.update(0, rect.y(), panel.width(), rect.height())
+ self._cached_cursor_pos = self.editor.get_cursor_line_column()
+ if (rect.contains(self.editor.viewport().rect()) or
+ force_update_margins):
+ self._update_viewport_margins()
+ self.update_floating_panels()
+
+ def _update_viewport_margins(self):
+ """Update viewport margins."""
+ top = 0
+ left = 0
+ right = 0
+ bottom = 0
+ for panel in self.panels_for_zone(Panel.Position.LEFT):
+ if panel.isVisible():
+ width = panel.sizeHint().width()
+ left += width
+ for panel in self.panels_for_zone(Panel.Position.RIGHT):
+ if panel.isVisible():
+ width = panel.sizeHint().width()
+ right += width
+ for panel in self.panels_for_zone(Panel.Position.TOP):
+ if panel.isVisible():
+ height = panel.sizeHint().height()
+ top += height
+ for panel in self.panels_for_zone(Panel.Position.BOTTOM):
+ if panel.isVisible():
+ height = panel.sizeHint().height()
+ bottom += height
+ self._margin_sizes = (top, left, right, bottom)
+ self.editor.setViewportMargins(left, top, right, bottom)
+
+ def margin_size(self, position=Panel.Position.LEFT):
+ """
+ Gets the size of a specific margin.
+
+ :param position: Margin position. See
+ :class:`spyder.api.Panel.Position`
+ :return: The size of the specified margin
+ :rtype: float
+ """
+ return self._margin_sizes[position]
+
+ def _compute_zones_sizes(self):
+ """Compute panel zone sizes."""
+ # Left panels
+ left = 0
+ for panel in self.panels_for_zone(Panel.Position.LEFT):
+ if not panel.isVisible():
+ continue
+ size_hint = panel.sizeHint()
+ left += size_hint.width()
+ # Right panels
+ right = 0
+ for panel in self.panels_for_zone(Panel.Position.RIGHT):
+ if not panel.isVisible():
+ continue
+ size_hint = panel.sizeHint()
+ right += size_hint.width()
+ # Top panels
+ top = 0
+ for panel in self.panels_for_zone(Panel.Position.TOP):
+ if not panel.isVisible():
+ continue
+ size_hint = panel.sizeHint()
+ top += size_hint.height()
+ # Bottom panels
+ bottom = 0
+ for panel in self.panels_for_zone(Panel.Position.BOTTOM):
+ if not panel.isVisible():
+ continue
+ size_hint = panel.sizeHint()
+ bottom += size_hint.height()
+ self._top, self._left, self._right, self._bottom = (
+ top, left, right, bottom)
+ return bottom, left, right, top
diff --git a/spyder/widgets/panels/scrollflag.py b/spyder/plugins/editor/panels/scrollflag.py
similarity index 97%
rename from spyder/widgets/panels/scrollflag.py
rename to spyder/plugins/editor/panels/scrollflag.py
index ffed6a41070..b3f46c63874 100644
--- a/spyder/widgets/panels/scrollflag.py
+++ b/spyder/plugins/editor/panels/scrollflag.py
@@ -12,6 +12,7 @@
from qtpy.QtWidgets import (QStyle, QStyleOptionSlider, QApplication)
from spyder.api.panel import Panel
+from spyder.plugins.editor.lsp import DiagnosticSeverity
class ScrollFlagArea(Panel):
@@ -49,7 +50,7 @@ def offset(self):
"""This property holds the vertical offset of the scroll flag area
relative to the top of the text editor."""
vsb = self.editor.verticalScrollBar()
- style = vsb.style()
+ style = QApplication.instance().style()
opt = QStyleOptionSlider()
vsb.initStyleOption(opt)
@@ -82,7 +83,8 @@ def paintEvent(self, event):
if data.code_analysis:
# Paint the warnings
color = self.editor.warning_color
- for _message, error in data.code_analysis:
+ for source, code, severity, message in data.code_analysis:
+ error = severity == DiagnosticSeverity.ERROR
if error:
color = self.editor.error_color
break
@@ -170,7 +172,7 @@ def get_scrollbar_position_height(self):
"""Return the pixel span height of the scrollbar area in which
the slider handle may move"""
vsb = self.editor.verticalScrollBar()
- style = vsb.style()
+ style = QApplication.instance().style()
opt = QStyleOptionSlider()
vsb.initStyleOption(opt)
diff --git a/spyder/widgets/panels/tests/test_classfunctiondropdown.py b/spyder/plugins/editor/panels/tests/test_classfunctiondropdown.py
similarity index 92%
rename from spyder/widgets/panels/tests/test_classfunctiondropdown.py
rename to spyder/plugins/editor/panels/tests/test_classfunctiondropdown.py
index aff12d9f50d..678aa30b835 100644
--- a/spyder/widgets/panels/tests/test_classfunctiondropdown.py
+++ b/spyder/plugins/editor/panels/tests/test_classfunctiondropdown.py
@@ -17,12 +17,12 @@
from pytestqt import qtbot
# Local imports
-from spyder.widgets.panels import classfunctiondropdown as cfd
-from spyder.utils.syntaxhighlighters import OutlineExplorerData as OED
+from spyder.plugins.editor.panels import classfunctiondropdown as cfd
+from spyder.plugins.outlineexplorer.api import OutlineExplorerData as OED
from spyder.utils.syntaxhighlighters import PythonSH
-from spyder.widgets.sourcecode.folding import FoldScope
-from spyder.utils.editor import TextBlockHelper
-from spyder.widgets.sourcecode.folding import IndentFoldDetector
+from spyder.plugins.editor.utils.folding import FoldScope
+from spyder.plugins.editor.utils.editor import TextBlockHelper
+from spyder.plugins.editor.utils.folding import IndentFoldDetector
# ---------------------------------------------------------------------------
@@ -45,7 +45,7 @@ def qcombobox_bot(qtbot):
@pytest.fixture
def editor_bot(qtbot):
- from spyder.widgets.editor import codeeditor
+ from spyder.plugins.editor.widgets.editor import codeeditor
widget = codeeditor.CodeEditor(None)
widget.setup_editor(linenumbers=True,
markers=True,
@@ -156,7 +156,7 @@ def my_add():
block = block.next()
TextBlockHelper.set_fold_trigger(block, True)
fold_scope = FoldScope(block)
- oed = sh.get_outlineexplorer_data()[1]
+ oed = block.userData().oedata
def test_fold_scope_helper(self):
fsh = cfd.FoldScopeHelper(None, None)
diff --git a/spyder/widgets/panels/tests/test_scrollflag.py b/spyder/plugins/editor/panels/tests/test_scrollflag.py
similarity index 83%
rename from spyder/widgets/panels/tests/test_scrollflag.py
rename to spyder/plugins/editor/panels/tests/test_scrollflag.py
index f4ef8766286..6d909df119c 100644
--- a/spyder/widgets/panels/tests/test_scrollflag.py
+++ b/spyder/plugins/editor/panels/tests/test_scrollflag.py
@@ -14,8 +14,7 @@
import pytest
# Local imports
-from spyder.widgets.sourcecode.codeeditor import CodeEditor
-from qtpy import PYQT4
+from spyder.plugins.editor.widgets.codeeditor import CodeEditor
# ---------------------------------------------------------------------------
@@ -32,8 +31,8 @@ def editor_bot(qtbot):
font=QFont("Courier New", 10),
color_scheme='Zenburn',
language='Python')
- # qtbot.addWidget(widget)
- return qtbot, widget
+ qtbot.addWidget(widget)
+ return widget
# ---------------------------------------------------------------------------
@@ -77,7 +76,7 @@ def editor_bot(qtbot):
def test_enabled(editor_bot):
""""Test that enabling and disabling the srollflagarea panel make
it visible or invisible depending on the case."""
- qtbot, editor = editor_bot
+ editor = editor_bot
sfa = editor.scrollflagarea
editor.show()
editor.set_text(short_code)
@@ -88,12 +87,12 @@ def test_enabled(editor_bot):
@pytest.mark.skipif(not os.name == 'nt', reason="It fails on Travis")
-def test_flag_painting(editor_bot):
+def test_flag_painting(editor_bot, qtbot):
""""Test that there is no error when painting all flag types on the
scrollbar area when the editor vertical scrollbar is visible and not
visible. There is seven different flags: breakpoints, todos, warnings,
errors, found_results, and occurences"""
- qtbot, editor = editor_bot
+ editor = editor_bot
sfa = editor.scrollflagarea
editor.resize(450, 300)
@@ -104,9 +103,18 @@ def test_flag_painting(editor_bot):
qtbot.waitUntil(lambda: not sfa.slider)
# Trigger the painting of all flag types.
- editor.add_remove_breakpoint(line_number=2)
+ editor.debugger.toogle_breakpoint(line_number=2)
editor.process_todo([[True, 3]])
- editor.process_code_analysis([['E227 warning', 4], ['syntax error', 5]])
+ analysis = [{'source': 'pycodestyle', 'range':{
+ 'start': {'line': 4, 'character': 0},
+ 'end': {'line': 4, 'character': 1}},
+ 'line': 4, 'code': 'E227','message': 'E227 warning',
+ 'severity': 2},
+ {'source': 'pyflakes', 'range':{
+ 'start': {'line': 5, 'character': 0},
+ 'end': {'line': 5, 'character': 1}},
+ 'message': 'syntax error', 'severity': 1}]
+ editor.process_code_analysis(analysis)
editor.highlight_found_results('line6')
with qtbot.waitSignal(editor.sig_flags_changed, raising=True,
timeout=5000):
@@ -119,9 +127,18 @@ def test_flag_painting(editor_bot):
qtbot.waitUntil(lambda: sfa.slider)
# Trigger the painting of all flag types.
- editor.add_remove_breakpoint(line_number=2)
+ editor.debugger.toogle_breakpoint(line_number=2)
editor.process_todo([[True, 3]])
- editor.process_code_analysis([['E227 warning', 4], ['syntax error', 5]])
+ analysis = [{'source': 'pycodestyle', 'range':{
+ 'start': {'line': 4, 'character': 0},
+ 'end': {'line': 4, 'character': 1}},
+ 'line': 4, 'code': 'E227','message': 'E227 warning',
+ 'severity': 2},
+ {'source': 'pyflakes', 'range':{
+ 'start': {'line': 5, 'character': 0},
+ 'end': {'line': 5, 'character': 1}},
+ 'message': 'syntax error', 'severity': 1}]
+ editor.process_code_analysis(analysis)
editor.highlight_found_results('line6')
with qtbot.waitSignal(editor.sig_flags_changed, raising=True,
timeout=5000):
@@ -131,12 +148,12 @@ def test_flag_painting(editor_bot):
@pytest.mark.skipif(not os.name == 'nt', reason="It fails on Travis")
-def test_range_indicator_visible_on_hover_only(editor_bot):
+def test_range_indicator_visible_on_hover_only(editor_bot, qtbot):
"""Test that the slider range indicator is visible only when hovering
over the scrollflag area when the editor vertical scrollbar is visible.
The scrollflag area should remain hidden at all times when the editor
vertical scrollbar is not visible."""
- qtbot, editor = editor_bot
+ editor = editor_bot
sfa = editor.scrollflagarea
editor.resize(450, 300)
@@ -179,13 +196,13 @@ def test_range_indicator_visible_on_hover_only(editor_bot):
@pytest.mark.skipif(not os.name == 'nt', reason="It fails on Travis")
-def test_range_indicator_alt_modifier_response(editor_bot):
+def test_range_indicator_alt_modifier_response(editor_bot, qtbot):
"""Test that the slider range indicator is visible while the alt key is
held down while the cursor is over the editor, but outside of the
scrollflag area. In addition, while the alt key is held down, mouse
click events in the editor should be forwarded to the scrollfag area and
should set the value of the editor vertical scrollbar."""
- qtbot, editor = editor_bot
+ editor = editor_bot
sfa = editor.scrollflagarea
sfa._unit_testing = True
vsb = editor.verticalScrollBar()
diff --git a/spyder/plugins/editor/plugin.py b/spyder/plugins/editor/plugin.py
new file mode 100644
index 00000000000..82b89b851cb
--- /dev/null
+++ b/spyder/plugins/editor/plugin.py
@@ -0,0 +1,2780 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Editor Plugin"""
+
+# pylint: disable=C0103
+# pylint: disable=R0903
+# pylint: disable=R0911
+# pylint: disable=R0201
+
+# Standard library imports
+import logging
+import os
+import os.path as osp
+import re
+import sys
+import time
+
+# Third party imports
+from qtpy.compat import from_qvariant, getopenfilenames, to_qvariant
+from qtpy.QtCore import QByteArray, Qt, Signal, Slot
+from qtpy.QtGui import QKeySequence
+from qtpy.QtPrintSupport import QAbstractPrintDialog, QPrintDialog, QPrinter
+from qtpy.QtWidgets import (QAction, QActionGroup, QApplication, QDialog,
+ QFileDialog, QInputDialog, QMenu, QSplitter,
+ QToolBar, QVBoxLayout, QWidget)
+
+# Local imports
+from spyder import dependencies
+from spyder.config.base import _, get_conf_path, running_under_pytest
+from spyder.config.gui import get_shortcut
+from spyder.config.main import CONF
+from spyder.config.utils import (get_edit_filetypes, get_edit_filters,
+ get_filter)
+from spyder.py3compat import PY2, qbytearray_to_str, to_text_string
+from spyder.utils import encoding, programs, sourcecode
+from spyder.utils import icon_manager as ima
+from spyder.utils.qthelpers import create_action, add_actions, MENU_SEPARATOR
+from spyder.utils.misc import getcwd_or_home
+from spyder.widgets.findreplace import FindReplace
+from spyder.plugins.editor.confpage import EditorConfigPage
+from spyder.plugins.editor.utils.autosave import AutosaveForPlugin
+from spyder.plugins.editor.widgets.editor import (EditorMainWindow, Printer,
+ EditorSplitter, EditorStack,)
+from spyder.plugins.editor.widgets.codeeditor import CodeEditor
+from spyder.plugins.editor.utils.bookmarks import (load_bookmarks,
+ save_bookmarks)
+from spyder.plugins.editor.utils.debugger import (clear_all_breakpoints,
+ clear_breakpoint)
+from spyder.plugins.editor.widgets.status import (CursorPositionStatus,
+ EncodingStatus, EOLStatus,
+ ReadWriteStatus, VCSStatus)
+from spyder.api.plugins import SpyderPluginWidget
+from spyder.preferences.runconfig import (ALWAYS_OPEN_FIRST_RUN_OPTION,
+ get_run_configuration,
+ RunConfigDialog, RunConfigOneDialog)
+
+
+logger = logging.getLogger(__name__)
+
+
+# Dependencies
+PYLS_REQVER = '>=0.19.0;<0.25'
+dependencies.add('pyls',
+ _("Editor's code completion, go-to-definition, help and "
+ "real-time code analysis"),
+ required_version=PYLS_REQVER)
+
+NBCONVERT_REQVER = ">=4.0"
+dependencies.add("nbconvert", _("Manipulate Jupyter notebooks on the Editor"),
+ required_version=NBCONVERT_REQVER)
+
+WINPDB_PATH = programs.find_program('winpdb')
+
+
+class Editor(SpyderPluginWidget):
+ """
+ Multi-file Editor widget
+ """
+ CONF_SECTION = 'editor'
+ CONFIGWIDGET_CLASS = EditorConfigPage
+ TEMPFILE_PATH = get_conf_path('temp.py')
+ TEMPLATE_PATH = get_conf_path('template.py')
+ DISABLE_ACTIONS_WHEN_HIDDEN = False # SpyderPluginWidget class attribute
+
+ # Signals
+ run_in_current_ipyclient = Signal(str, str, str, bool, bool, bool, bool)
+ run_cell_in_ipyclient = Signal(str, str, str, bool)
+ exec_in_extconsole = Signal(str, bool)
+ redirect_stdio = Signal(bool)
+ open_dir = Signal(str)
+ breakpoints_saved = Signal()
+ run_in_current_extconsole = Signal(str, str, str, bool, bool)
+ open_file_update = Signal(str)
+
+ # This signal is fired for any focus change among all editor stacks
+ sig_editor_focus_changed = Signal()
+
+ def __init__(self, parent, ignore_last_opened_files=False):
+ SpyderPluginWidget.__init__(self, parent)
+
+ self.__set_eol_chars = True
+
+ # Creating template if it doesn't already exist
+ if not osp.isfile(self.TEMPLATE_PATH):
+ if os.name == "nt":
+ shebang = []
+ else:
+ shebang = ['#!/usr/bin/env python' + ('2' if PY2 else '3')]
+ header = shebang + [
+ '# -*- coding: utf-8 -*-',
+ '"""', 'Created on %(date)s', '',
+ '@author: %(username)s', '"""', '', '']
+ try:
+ encoding.write(os.linesep.join(header), self.TEMPLATE_PATH,
+ 'utf-8')
+ except EnvironmentError:
+ pass
+
+ self.projects = None
+ self.outlineexplorer = None
+ self.help = None
+
+ self.file_dependent_actions = []
+ self.pythonfile_dependent_actions = []
+ self.dock_toolbar_actions = None
+ self.edit_menu_actions = None #XXX: find another way to notify Spyder
+ self.stack_menu_actions = None
+ self.checkable_actions = {}
+
+ self.__first_open_files_setup = True
+ self.editorstacks = []
+ self.last_focus_editorstack = {}
+ self.editorwindows = []
+ self.editorwindows_to_be_created = []
+ self.toolbar_list = None
+ self.menu_list = None
+
+ # Initialize plugin
+ self.initialize_plugin()
+ self.options_button.hide()
+
+ # Configuration dialog size
+ self.dialog_size = None
+
+ statusbar = parent.statusBar() # Create a status bar
+ self.vcs_status = VCSStatus(self, statusbar)
+ self.cursorpos_status = CursorPositionStatus(self, statusbar)
+ self.encoding_status = EncodingStatus(self, statusbar)
+ self.eol_status = EOLStatus(self, statusbar)
+ self.readwrite_status = ReadWriteStatus(self, statusbar)
+
+ layout = QVBoxLayout()
+ self.dock_toolbar = QToolBar(self)
+ add_actions(self.dock_toolbar, self.dock_toolbar_actions)
+ layout.addWidget(self.dock_toolbar)
+
+ self.last_edit_cursor_pos = None
+ self.cursor_pos_history = []
+ self.cursor_pos_index = None
+ self.__ignore_cursor_position = True
+
+ # LSP setup
+ self.lsp_editor_settings = {}
+
+ # Setup new windows:
+ self.main.all_actions_defined.connect(self.setup_other_windows)
+
+ # Change module completions when PYTHONPATH changes
+ self.main.sig_pythonpath_changed.connect(self.set_path)
+
+ # Find widget
+ self.find_widget = FindReplace(self, enable_replace=True)
+ self.find_widget.hide()
+ self.find_widget.visibility_changed.connect(
+ lambda vs: self.rehighlight_cells())
+ self.register_widget_shortcuts(self.find_widget)
+
+ # Tabbed editor widget + Find/Replace widget
+ editor_widgets = QWidget(self)
+ editor_layout = QVBoxLayout()
+ editor_layout.setContentsMargins(0, 0, 0, 0)
+ editor_widgets.setLayout(editor_layout)
+ self.editorsplitter = EditorSplitter(self, self,
+ self.stack_menu_actions, first=True)
+ editor_layout.addWidget(self.editorsplitter)
+ editor_layout.addWidget(self.find_widget)
+
+ # Start autosave component
+ self.autosave = AutosaveForPlugin(self)
+ self.autosave.try_recover_from_autosave()
+ # Multiply by 1000 to convert seconds to milliseconds
+ self.autosave.interval = self.get_option('autosave_interval') * 1000
+ self.autosave.enabled = self.get_option('autosave_enabled')
+
+ # Splitter: editor widgets (see above) + outline explorer
+ self.splitter = QSplitter(self)
+ self.splitter.setContentsMargins(0, 0, 0, 0)
+ self.splitter.addWidget(editor_widgets)
+ self.splitter.setStretchFactor(0, 5)
+ self.splitter.setStretchFactor(1, 1)
+ layout.addWidget(self.splitter)
+ self.setLayout(layout)
+ self.setFocusPolicy(Qt.ClickFocus)
+
+ # Editor's splitter state
+ state = self.get_option('splitter_state', None)
+ if state is not None:
+ self.splitter.restoreState( QByteArray().fromHex(
+ str(state).encode('utf-8')) )
+
+ self.recent_files = self.get_option('recent_files', [])
+ self.untitled_num = 0
+
+ # Parameters of last file execution:
+ self.__last_ic_exec = None # internal console
+ self.__last_ec_exec = None # external console
+
+ # File types and filters used by the Open dialog
+ self.edit_filetypes = None
+ self.edit_filters = None
+
+ self.__ignore_cursor_position = False
+ current_editor = self.get_current_editor()
+ if current_editor is not None:
+ filename = self.get_current_filename()
+ position = current_editor.get_position('cursor')
+ self.add_cursor_position_to_history(filename, position)
+ self.update_cursorpos_actions()
+ self.set_path()
+
+ def set_projects(self, projects):
+ self.projects = projects
+
+ @Slot()
+ def show_hide_projects(self):
+ if self.projects is not None:
+ dw = self.projects.dockwidget
+ if dw.isVisible():
+ dw.hide()
+ else:
+ dw.show()
+ dw.raise_()
+ self.switch_to_plugin()
+
+ def set_outlineexplorer(self, outlineexplorer):
+ self.outlineexplorer = outlineexplorer
+ for editorstack in self.editorstacks:
+ # Pass the OutlineExplorer widget to the stacks because they
+ # don't need the plugin
+ editorstack.set_outlineexplorer(self.outlineexplorer.explorer)
+ self.editorstacks[0].initialize_outlineexplorer()
+ self.outlineexplorer.explorer.edit_goto.connect(
+ lambda filenames, goto, word:
+ self.load(filenames=filenames, goto=goto, word=word,
+ editorwindow=self))
+ self.outlineexplorer.explorer.edit.connect(
+ lambda filenames:
+ self.load(filenames=filenames, editorwindow=self))
+
+ def set_help(self, help_plugin):
+ self.help = help_plugin
+ for editorstack in self.editorstacks:
+ editorstack.set_help(self.help)
+
+ #------ Private API --------------------------------------------------------
+ def restore_scrollbar_position(self):
+ """Restoring scrollbar position after main window is visible"""
+ # Widget is now visible, we may center cursor on top level editor:
+ try:
+ self.get_current_editor().centerCursor()
+ except AttributeError:
+ pass
+
+ @Slot(dict)
+ def report_open_file(self, options):
+ """Request to start a LSP server to attend a language."""
+ filename = options['filename']
+ logger.debug('Call LSP for %s' % filename)
+ language = options['language']
+ callback = options['codeeditor']
+ stat = self.main.lspmanager.start_client(language.lower())
+ self.main.lspmanager.register_file(
+ language.lower(), filename, callback)
+ if stat:
+ if language.lower() in self.lsp_editor_settings:
+ self.lsp_server_ready(
+ language.lower(), self.lsp_editor_settings[
+ language.lower()])
+ else:
+ editor = self.get_current_editor()
+ editor.lsp_ready = False
+
+ @Slot(dict, str)
+ def register_lsp_server_settings(self, settings, language):
+ """Register LSP server settings."""
+ self.lsp_editor_settings[language] = settings
+ logger.debug('LSP server settings for {!s} are: {!r}'.format(
+ language, settings))
+ self.lsp_server_ready(language, self.lsp_editor_settings[language])
+
+ def stop_lsp_services(self, language):
+ """Notify all editorstacks about LSP server unavailability."""
+ for editorstack in self.editorstacks:
+ editorstack.notify_server_down(language)
+
+ def lsp_server_ready(self, language, configuration):
+ """Notify all stackeditors about LSP server availability."""
+ for editorstack in self.editorstacks:
+ editorstack.notify_server_ready(language, configuration)
+
+ def send_lsp_request(self, language, request, params):
+ logger.debug("LSP request: %r" %request)
+ self.main.lspmanager.send_request(language, request, params)
+
+
+ #------ SpyderPluginWidget API ---------------------------------------------
+ def get_plugin_title(self):
+ """Return widget title"""
+ title = _('Editor')
+ return title
+
+ def get_plugin_icon(self):
+ """Return widget icon."""
+ return ima.icon('edit')
+
+ def get_focus_widget(self):
+ """
+ Return the widget to give focus to.
+
+ This happens when plugin's dockwidget is raised on top-level.
+ """
+ return self.get_current_editor()
+
+ def visibility_changed(self, enable):
+ """DockWidget visibility has changed"""
+ SpyderPluginWidget.visibility_changed(self, enable)
+ if self.dockwidget is None:
+ return
+ if self.dockwidget.isWindow():
+ self.dock_toolbar.show()
+ else:
+ self.dock_toolbar.hide()
+ if enable:
+ self.refresh_plugin()
+ self.sig_update_plugin_title.emit()
+
+ def refresh_plugin(self):
+ """Refresh editor plugin"""
+ editorstack = self.get_current_editorstack()
+ editorstack.refresh()
+ self.refresh_save_all_action()
+
+ def closing_plugin(self, cancelable=False):
+ """Perform actions before parent main window is closed"""
+ state = self.splitter.saveState()
+ self.set_option('splitter_state', qbytearray_to_str(state))
+ filenames = []
+ editorstack = self.editorstacks[0]
+
+ active_project_path = None
+ if self.projects is not None:
+ active_project_path = self.projects.get_active_project_path()
+ if not active_project_path:
+ self.set_open_filenames()
+ else:
+ self.projects.set_project_filenames(
+ [finfo.filename for finfo in editorstack.data])
+
+ self.set_option('layout_settings',
+ self.editorsplitter.get_layout_settings())
+ self.set_option('windows_layout_settings',
+ [win.get_layout_settings() for win in self.editorwindows])
+# self.set_option('filenames', filenames)
+ self.set_option('recent_files', self.recent_files)
+
+ # Stop autosave timer before closing windows
+ self.autosave.stop_autosave_timer()
+
+ try:
+ if not editorstack.save_if_changed(cancelable) and cancelable:
+ return False
+ else:
+ for win in self.editorwindows[:]:
+ win.close()
+ # Remove autosave on successful close to avoid issue #9265.
+ # Probably a good idea anyway to mitigate autosave issues.
+ # Ignore errors resulting from file being open in > 2
+ # editorstacks or another Spyder being closed first and
+ # removing the spurious files.
+ for editorstack_split in self.editorstacks:
+ editorstack_split.autosave.remove_all_autosave_files(
+ errors="ignore")
+ return True
+ except IndexError:
+ return True
+
+ def get_plugin_actions(self):
+ """Return a list of actions related to plugin"""
+ # ---- File menu and toolbar ----
+ self.new_action = create_action(
+ self,
+ _("&New file..."),
+ icon=ima.icon('filenew'), tip=_("New file"),
+ triggered=self.new,
+ context=Qt.WidgetShortcut
+ )
+ self.register_shortcut(self.new_action, context="Editor",
+ name="New file", add_sc_to_tip=True)
+
+ self.open_last_closed_action = create_action(
+ self,
+ _("O&pen last closed"),
+ tip=_("Open last closed"),
+ triggered=self.open_last_closed
+ )
+ self.register_shortcut(self.open_last_closed_action, context="Editor",
+ name="Open last closed")
+
+ self.open_action = create_action(self, _("&Open..."),
+ icon=ima.icon('fileopen'), tip=_("Open file"),
+ triggered=self.load,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(self.open_action, context="Editor",
+ name="Open file", add_sc_to_tip=True)
+
+ self.revert_action = create_action(self, _("&Revert"),
+ icon=ima.icon('revert'), tip=_("Revert file from disk"),
+ triggered=self.revert)
+
+ self.save_action = create_action(self, _("&Save"),
+ icon=ima.icon('filesave'), tip=_("Save file"),
+ triggered=self.save,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(self.save_action, context="Editor",
+ name="Save file", add_sc_to_tip=True)
+
+ self.save_all_action = create_action(self, _("Sav&e all"),
+ icon=ima.icon('save_all'), tip=_("Save all files"),
+ triggered=self.save_all,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(self.save_all_action, context="Editor",
+ name="Save all", add_sc_to_tip=True)
+
+ save_as_action = create_action(self, _("Save &as..."), None,
+ ima.icon('filesaveas'), tip=_("Save current file as..."),
+ triggered=self.save_as,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(save_as_action, "Editor", "Save As")
+
+ save_copy_as_action = create_action(self, _("Save copy as..."), None,
+ ima.icon('filesaveas'), _("Save copy of current file as..."),
+ triggered=self.save_copy_as)
+
+ print_preview_action = create_action(self, _("Print preview..."),
+ tip=_("Print preview..."), triggered=self.print_preview)
+ self.print_action = create_action(self, _("&Print..."),
+ icon=ima.icon('print'), tip=_("Print current file..."),
+ triggered=self.print_file)
+ # Shortcut for close_action is defined in widgets/editor.py
+ self.close_action = create_action(self, _("&Close"),
+ icon=ima.icon('fileclose'), tip=_("Close current file"),
+ triggered=self.close_file)
+
+ self.close_all_action = create_action(self, _("C&lose all"),
+ icon=ima.icon('filecloseall'), tip=_("Close all opened files"),
+ triggered=self.close_all_files,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(self.close_all_action, context="Editor",
+ name="Close all")
+
+ # ---- Find menu and toolbar ----
+ _text = _("&Find text")
+ find_action = create_action(self, _text, icon=ima.icon('find'),
+ tip=_text, triggered=self.find,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(find_action, context="_",
+ name="Find text", add_sc_to_tip=True)
+ find_next_action = create_action(self, _("Find &next"),
+ icon=ima.icon('findnext'),
+ triggered=self.find_next,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(find_next_action, context="_",
+ name="Find next")
+ find_previous_action = create_action(self, _("Find &previous"),
+ icon=ima.icon('findprevious'),
+ triggered=self.find_previous,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(find_previous_action, context="_",
+ name="Find previous")
+ _text = _("&Replace text")
+ replace_action = create_action(self, _text, icon=ima.icon('replace'),
+ tip=_text, triggered=self.replace,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(replace_action, context="_",
+ name="Replace text")
+
+ # ---- Debug menu and toolbar ----
+ set_clear_breakpoint_action = create_action(self,
+ _("Set/Clear breakpoint"),
+ icon=ima.icon('breakpoint_big'),
+ triggered=self.set_or_clear_breakpoint,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(set_clear_breakpoint_action, context="Editor",
+ name="Breakpoint")
+ set_cond_breakpoint_action = create_action(self,
+ _("Set/Edit conditional breakpoint"),
+ icon=ima.icon('breakpoint_cond_big'),
+ triggered=self.set_or_edit_conditional_breakpoint,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(set_cond_breakpoint_action, context="Editor",
+ name="Conditional breakpoint")
+ clear_all_breakpoints_action = create_action(self,
+ _('Clear breakpoints in all files'),
+ triggered=self.clear_all_breakpoints)
+ self.winpdb_action = create_action(self, _("Debug with winpdb"),
+ triggered=self.run_winpdb)
+ self.winpdb_action.setEnabled(WINPDB_PATH is not None and PY2)
+
+ # --- Debug toolbar ---
+ debug_action = create_action(self, _("&Debug"),
+ icon=ima.icon('debug'),
+ tip=_("Debug file"),
+ triggered=self.debug_file)
+ self.register_shortcut(debug_action, context="_", name="Debug",
+ add_sc_to_tip=True)
+
+ debug_next_action = create_action(self, _("Step"),
+ icon=ima.icon('arrow-step-over'), tip=_("Run current line"),
+ triggered=lambda: self.debug_command("next"))
+ self.register_shortcut(debug_next_action, "_", "Debug Step Over",
+ add_sc_to_tip=True)
+
+ debug_continue_action = create_action(self, _("Continue"),
+ icon=ima.icon('arrow-continue'),
+ tip=_("Continue execution until next breakpoint"),
+ triggered=lambda: self.debug_command("continue"))
+ self.register_shortcut(debug_continue_action, "_", "Debug Continue",
+ add_sc_to_tip=True)
+
+ debug_step_action = create_action(self, _("Step Into"),
+ icon=ima.icon('arrow-step-in'),
+ tip=_("Step into function or method of current line"),
+ triggered=lambda: self.debug_command("step"))
+ self.register_shortcut(debug_step_action, "_", "Debug Step Into",
+ add_sc_to_tip=True)
+
+ debug_return_action = create_action(self, _("Step Return"),
+ icon=ima.icon('arrow-step-out'),
+ tip=_("Run until current function or method returns"),
+ triggered=lambda: self.debug_command("return"))
+ self.register_shortcut(debug_return_action, "_", "Debug Step Return",
+ add_sc_to_tip=True)
+
+ debug_exit_action = create_action(self, _("Stop"),
+ icon=ima.icon('stop_debug'), tip=_("Stop debugging"),
+ triggered=lambda: self.debug_command("exit"))
+ self.register_shortcut(debug_exit_action, "_", "Debug Exit",
+ add_sc_to_tip=True)
+
+ # --- Run toolbar ---
+ run_action = create_action(self, _("&Run"), icon=ima.icon('run'),
+ tip=_("Run file"),
+ triggered=self.run_file)
+ self.register_shortcut(run_action, context="_", name="Run",
+ add_sc_to_tip=True)
+
+ configure_action = create_action(self, _("&Configuration per file..."),
+ icon=ima.icon('run_settings'),
+ tip=_("Run settings"),
+ menurole=QAction.NoRole,
+ triggered=self.edit_run_configurations)
+ self.register_shortcut(configure_action, context="_",
+ name="Configure", add_sc_to_tip=True)
+
+ re_run_action = create_action(self, _("Re-run &last script"),
+ icon=ima.icon('run_again'),
+ tip=_("Run again last file"),
+ triggered=self.re_run_file)
+ self.register_shortcut(re_run_action, context="_",
+ name="Re-run last script",
+ add_sc_to_tip=True)
+
+ run_selected_action = create_action(self, _("Run &selection or "
+ "current line"),
+ icon=ima.icon('run_selection'),
+ tip=_("Run selection or "
+ "current line"),
+ triggered=self.run_selection,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(run_selected_action, context="Editor",
+ name="Run selection", add_sc_to_tip=True)
+
+ run_cell_action = create_action(self,
+ _("Run cell"),
+ icon=ima.icon('run_cell'),
+ shortcut=get_shortcut('editor', 'run cell'),
+ tip=_("Run current cell \n"
+ "[Use #%% to create cells]"),
+ triggered=self.run_cell,
+ context=Qt.WidgetShortcut)
+
+ run_cell_advance_action = create_action(self,
+ _("Run cell and advance"),
+ icon=ima.icon('run_cell_advance'),
+ shortcut=get_shortcut('editor', 'run cell and advance'),
+ tip=_("Run current cell and go to the next one "),
+ triggered=self.run_cell_and_advance,
+ context=Qt.WidgetShortcut)
+
+ re_run_last_cell_action = create_action(self,
+ _("Re-run last cell"),
+ tip=_("Re run last cell "),
+ triggered=self.re_run_last_cell,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(re_run_last_cell_action,
+ context="Editor",
+ name='re-run last cell',
+ add_sc_to_tip=True)
+
+ # --- Source code Toolbar ---
+ self.todo_list_action = create_action(self,
+ _("Show todo list"), icon=ima.icon('todo_list'),
+ tip=_("Show comments list (TODO/FIXME/XXX/HINT/TIP/@todo/"
+ "HACK/BUG/OPTIMIZE/!!!/???)"),
+ triggered=self.go_to_next_todo)
+ self.todo_menu = QMenu(self)
+ self.todo_menu.setStyleSheet("QMenu {menu-scrollable: 1;}")
+ self.todo_list_action.setMenu(self.todo_menu)
+ self.todo_menu.aboutToShow.connect(self.update_todo_menu)
+
+ self.warning_list_action = create_action(self,
+ _("Show warning/error list"), icon=ima.icon('wng_list'),
+ tip=_("Show code analysis warnings/errors"),
+ triggered=self.go_to_next_warning)
+ self.warning_menu = QMenu(self)
+ self.warning_menu.setStyleSheet("QMenu {menu-scrollable: 1;}")
+ self.warning_list_action.setMenu(self.warning_menu)
+ self.warning_menu.aboutToShow.connect(self.update_warning_menu)
+ self.previous_warning_action = create_action(self,
+ _("Previous warning/error"), icon=ima.icon('prev_wng'),
+ tip=_("Go to previous code analysis warning/error"),
+ triggered=self.go_to_previous_warning,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(self.previous_warning_action,
+ context="Editor",
+ name="Previous warning",
+ add_sc_to_tip=True)
+ self.next_warning_action = create_action(self,
+ _("Next warning/error"), icon=ima.icon('next_wng'),
+ tip=_("Go to next code analysis warning/error"),
+ triggered=self.go_to_next_warning,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(self.next_warning_action,
+ context="Editor",
+ name="Next warning",
+ add_sc_to_tip=True)
+
+ self.previous_edit_cursor_action = create_action(self,
+ _("Last edit location"), icon=ima.icon('last_edit_location'),
+ tip=_("Go to last edit location"),
+ triggered=self.go_to_last_edit_location,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(self.previous_edit_cursor_action,
+ context="Editor",
+ name="Last edit location",
+ add_sc_to_tip=True)
+ self.previous_cursor_action = create_action(self,
+ _("Previous cursor position"), icon=ima.icon('prev_cursor'),
+ tip=_("Go to previous cursor position"),
+ triggered=self.go_to_previous_cursor_position,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(self.previous_cursor_action,
+ context="Editor",
+ name="Previous cursor position",
+ add_sc_to_tip=True)
+ self.next_cursor_action = create_action(self,
+ _("Next cursor position"), icon=ima.icon('next_cursor'),
+ tip=_("Go to next cursor position"),
+ triggered=self.go_to_next_cursor_position,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(self.next_cursor_action,
+ context="Editor",
+ name="Next cursor position",
+ add_sc_to_tip=True)
+
+ # --- Edit Toolbar ---
+ self.toggle_comment_action = create_action(self,
+ _("Comment")+"/"+_("Uncomment"), icon=ima.icon('comment'),
+ tip=_("Comment current line or selection"),
+ triggered=self.toggle_comment, context=Qt.WidgetShortcut)
+ self.register_shortcut(self.toggle_comment_action, context="Editor",
+ name="Toggle comment")
+ blockcomment_action = create_action(self, _("Add &block comment"),
+ tip=_("Add block comment around "
+ "current line or selection"),
+ triggered=self.blockcomment, context=Qt.WidgetShortcut)
+ self.register_shortcut(blockcomment_action, context="Editor",
+ name="Blockcomment")
+ unblockcomment_action = create_action(self,
+ _("R&emove block comment"),
+ tip = _("Remove comment block around "
+ "current line or selection"),
+ triggered=self.unblockcomment, context=Qt.WidgetShortcut)
+ self.register_shortcut(unblockcomment_action, context="Editor",
+ name="Unblockcomment")
+
+ # ----------------------------------------------------------------------
+ # The following action shortcuts are hard-coded in CodeEditor
+ # keyPressEvent handler (the shortcut is here only to inform user):
+ # (context=Qt.WidgetShortcut -> disable shortcut for other widgets)
+ self.indent_action = create_action(self,
+ _("Indent"), "Tab", icon=ima.icon('indent'),
+ tip=_("Indent current line or selection"),
+ triggered=self.indent, context=Qt.WidgetShortcut)
+ self.unindent_action = create_action(self,
+ _("Unindent"), "Shift+Tab", icon=ima.icon('unindent'),
+ tip=_("Unindent current line or selection"),
+ triggered=self.unindent, context=Qt.WidgetShortcut)
+
+ self.text_uppercase_action = create_action(self,
+ _("Toggle Uppercase"),
+ tip=_("Change to uppercase current line or selection"),
+ triggered=self.text_uppercase, context=Qt.WidgetShortcut)
+ self.register_shortcut(self.text_uppercase_action, context="Editor",
+ name="transform to uppercase")
+
+ self.text_lowercase_action = create_action(self,
+ _("Toggle Lowercase"),
+ tip=_("Change to lowercase current line or selection"),
+ triggered=self.text_lowercase, context=Qt.WidgetShortcut)
+ self.register_shortcut(self.text_lowercase_action, context="Editor",
+ name="transform to lowercase")
+ # ----------------------------------------------------------------------
+
+ self.win_eol_action = create_action(self,
+ _("Carriage return and line feed (Windows)"),
+ toggled=lambda checked: self.toggle_eol_chars('nt', checked))
+ self.linux_eol_action = create_action(self,
+ _("Line feed (UNIX)"),
+ toggled=lambda checked: self.toggle_eol_chars('posix', checked))
+ self.mac_eol_action = create_action(self,
+ _("Carriage return (Mac)"),
+ toggled=lambda checked: self.toggle_eol_chars('mac', checked))
+ eol_action_group = QActionGroup(self)
+ eol_actions = (self.win_eol_action, self.linux_eol_action,
+ self.mac_eol_action)
+ add_actions(eol_action_group, eol_actions)
+ eol_menu = QMenu(_("Convert end-of-line characters"), self)
+ add_actions(eol_menu, eol_actions)
+
+ trailingspaces_action = create_action(
+ self,
+ _("Remove trailing spaces"),
+ triggered=self.remove_trailing_spaces)
+
+ # Checkable actions
+ showblanks_action = self._create_checkable_action(
+ _("Show blank spaces"), 'blank_spaces', 'set_blanks_enabled')
+
+ scrollpastend_action = self._create_checkable_action(
+ _("Scroll past the end"), 'scroll_past_end',
+ 'set_scrollpastend_enabled')
+
+ showindentguides_action = self._create_checkable_action(
+ _("Show indent guides"), 'indent_guides', 'set_indent_guides')
+
+ show_classfunc_dropdown_action = self._create_checkable_action(
+ _("Show selector for classes and functions"),
+ 'show_class_func_dropdown', 'set_classfunc_dropdown_visible')
+
+ show_codestyle_warnings_action = self._create_checkable_action(
+ _("Show code style warnings"), 'pycodestyle',)
+
+ show_docstring_warnings_action = self._create_checkable_action(
+ _("Show docstring style warnings"), 'pydocstyle')
+
+ self.checkable_actions = {
+ 'blank_spaces': showblanks_action,
+ 'scroll_past_end': scrollpastend_action,
+ 'indent_guides': showindentguides_action,
+ 'show_class_func_dropdown': show_classfunc_dropdown_action,
+ 'pycodestyle': show_codestyle_warnings_action,
+ 'pydocstyle': show_docstring_warnings_action}
+
+ fixindentation_action = create_action(self, _("Fix indentation"),
+ tip=_("Replace tab characters by space characters"),
+ triggered=self.fix_indentation)
+
+ gotoline_action = create_action(self, _("Go to line..."),
+ icon=ima.icon('gotoline'),
+ triggered=self.go_to_line,
+ context=Qt.WidgetShortcut)
+ self.register_shortcut(gotoline_action, context="Editor",
+ name="Go to line")
+
+ workdir_action = create_action(self,
+ _("Set console working directory"),
+ icon=ima.icon('DirOpenIcon'),
+ tip=_("Set current console (and file explorer) working "
+ "directory to current script directory"),
+ triggered=self.__set_workdir)
+
+ self.max_recent_action = create_action(self,
+ _("Maximum number of recent files..."),
+ triggered=self.change_max_recent_files)
+ self.clear_recent_action = create_action(self,
+ _("Clear this list"), tip=_("Clear recent files list"),
+ triggered=self.clear_recent_files)
+
+ # Fixes issue 6055
+ # See: https://bugreports.qt.io/browse/QTBUG-8596
+ self.tab_navigation_actions = []
+ if sys.platform == 'darwin':
+ self.go_to_next_file_action = create_action(
+ self,
+ _("Go to next file"),
+ shortcut=get_shortcut('editor', 'go to previous file'),
+ triggered=self.go_to_next_file,
+ )
+ self.go_to_previous_file_action = create_action(
+ self,
+ _("Go to previous file"),
+ shortcut=get_shortcut('editor', 'go to next file'),
+ triggered=self.go_to_previous_file,
+ )
+ self.register_shortcut(
+ self.go_to_next_file_action,
+ context="Editor",
+ name="Go to next file",
+ )
+ self.register_shortcut(
+ self.go_to_previous_file_action,
+ context="Editor",
+ name="Go to previous file",
+ )
+ self.tab_navigation_actions = [
+ MENU_SEPARATOR,
+ self.go_to_previous_file_action,
+ self.go_to_next_file_action,
+ ]
+
+ # ---- File menu/toolbar construction ----
+ self.recent_file_menu = QMenu(_("Open &recent"), self)
+ self.recent_file_menu.aboutToShow.connect(self.update_recent_file_menu)
+
+ file_menu_actions = [
+ self.new_action,
+ MENU_SEPARATOR,
+ self.open_action,
+ self.open_last_closed_action,
+ self.recent_file_menu,
+ MENU_SEPARATOR,
+ MENU_SEPARATOR,
+ self.save_action,
+ self.save_all_action,
+ save_as_action,
+ save_copy_as_action,
+ self.revert_action,
+ MENU_SEPARATOR,
+ print_preview_action,
+ self.print_action,
+ MENU_SEPARATOR,
+ self.close_action,
+ self.close_all_action,
+ MENU_SEPARATOR,
+ ]
+
+ self.main.file_menu_actions += file_menu_actions
+ file_toolbar_actions = ([self.new_action, self.open_action,
+ self.save_action, self.save_all_action] +
+ self.main.file_toolbar_actions)
+
+ self.main.file_toolbar_actions = file_toolbar_actions
+
+ # ---- Find menu/toolbar construction ----
+ self.main.search_menu_actions = [find_action,
+ find_next_action,
+ find_previous_action,
+ replace_action]
+ self.main.search_toolbar_actions = [find_action,
+ find_next_action,
+ replace_action]
+
+ # ---- Edit menu/toolbar construction ----
+ self.edit_menu_actions = [self.toggle_comment_action,
+ blockcomment_action, unblockcomment_action,
+ self.indent_action, self.unindent_action,
+ self.text_uppercase_action,
+ self.text_lowercase_action]
+ self.main.edit_menu_actions += [MENU_SEPARATOR] + self.edit_menu_actions
+ edit_toolbar_actions = [self.toggle_comment_action,
+ self.unindent_action, self.indent_action]
+ self.main.edit_toolbar_actions += edit_toolbar_actions
+
+ # ---- Search menu/toolbar construction ----
+ self.main.search_menu_actions += [gotoline_action]
+ self.main.search_toolbar_actions += [gotoline_action]
+
+ # ---- Run menu/toolbar construction ----
+ run_menu_actions = [run_action, run_cell_action,
+ run_cell_advance_action,
+ re_run_last_cell_action, MENU_SEPARATOR,
+ run_selected_action, re_run_action,
+ configure_action, MENU_SEPARATOR]
+ self.main.run_menu_actions += run_menu_actions
+ run_toolbar_actions = [run_action, run_cell_action,
+ run_cell_advance_action, run_selected_action,
+ re_run_action]
+ self.main.run_toolbar_actions += run_toolbar_actions
+
+ # ---- Debug menu/toolbar construction ----
+ # NOTE: 'list_breakpoints' is used by the breakpoints
+ # plugin to add its "List breakpoints" action to this
+ # menu
+ debug_menu_actions = [
+ debug_action,
+ debug_next_action,
+ debug_step_action,
+ debug_return_action,
+ debug_continue_action,
+ debug_exit_action,
+ MENU_SEPARATOR,
+ set_clear_breakpoint_action,
+ set_cond_breakpoint_action,
+ clear_all_breakpoints_action,
+ 'list_breakpoints',
+ MENU_SEPARATOR,
+ self.winpdb_action
+ ]
+ self.main.debug_menu_actions += debug_menu_actions
+ debug_toolbar_actions = [
+ debug_action,
+ debug_next_action,
+ debug_step_action,
+ debug_return_action,
+ debug_continue_action,
+ debug_exit_action
+ ]
+ self.main.debug_toolbar_actions += debug_toolbar_actions
+
+ # ---- Source menu/toolbar construction ----
+ source_menu_actions = [
+ showblanks_action,
+ scrollpastend_action,
+ showindentguides_action,
+ show_classfunc_dropdown_action,
+ show_codestyle_warnings_action,
+ show_docstring_warnings_action,
+ MENU_SEPARATOR,
+ self.todo_list_action,
+ self.warning_list_action,
+ self.previous_warning_action,
+ self.next_warning_action,
+ MENU_SEPARATOR,
+ self.previous_edit_cursor_action,
+ self.previous_cursor_action,
+ self.next_cursor_action,
+ MENU_SEPARATOR,
+ eol_menu,
+ trailingspaces_action,
+ fixindentation_action
+ ]
+ self.main.source_menu_actions += source_menu_actions
+
+ source_toolbar_actions = [
+ self.todo_list_action,
+ self.warning_list_action,
+ self.previous_warning_action,
+ self.next_warning_action,
+ MENU_SEPARATOR,
+ self.previous_edit_cursor_action,
+ self.previous_cursor_action,
+ self.next_cursor_action
+ ]
+ self.main.source_toolbar_actions += source_toolbar_actions
+
+ # ---- Dock widget and file dependent actions ----
+ self.dock_toolbar_actions = (
+ file_toolbar_actions +
+ [MENU_SEPARATOR] +
+ source_toolbar_actions +
+ [MENU_SEPARATOR] +
+ run_toolbar_actions +
+ [MENU_SEPARATOR] +
+ debug_toolbar_actions +
+ [MENU_SEPARATOR] +
+ edit_toolbar_actions
+ )
+ self.pythonfile_dependent_actions = [
+ run_action,
+ configure_action,
+ set_clear_breakpoint_action,
+ set_cond_breakpoint_action,
+ debug_action,
+ run_selected_action,
+ run_cell_action,
+ run_cell_advance_action,
+ re_run_last_cell_action,
+ blockcomment_action,
+ unblockcomment_action,
+ self.winpdb_action
+ ]
+ self.cythonfile_compatible_actions = [run_action, configure_action]
+ self.file_dependent_actions = (
+ self.pythonfile_dependent_actions +
+ [
+ self.save_action,
+ save_as_action,
+ save_copy_as_action,
+ print_preview_action,
+ self.print_action,
+ self.save_all_action,
+ gotoline_action,
+ workdir_action,
+ self.close_action,
+ self.close_all_action,
+ self.toggle_comment_action,
+ self.revert_action,
+ self.indent_action,
+ self.unindent_action
+ ]
+ )
+ self.stack_menu_actions = [gotoline_action, workdir_action]
+
+ return self.file_dependent_actions
+
+ def register_plugin(self):
+ """Register plugin in Spyder's main window"""
+ self.main.restore_scrollbar_position.connect(
+ self.restore_scrollbar_position)
+ self.main.console.edit_goto.connect(self.load)
+ self.exec_in_extconsole.connect(self.main.execute_in_external_console)
+ self.redirect_stdio.connect(self.main.redirect_internalshell_stdio)
+ self.open_dir.connect(self.main.workingdirectory.chdir)
+ self.set_help(self.main.help)
+ if self.main.outlineexplorer is not None:
+ self.set_outlineexplorer(self.main.outlineexplorer)
+ editorstack = self.get_current_editorstack()
+ if not editorstack.data:
+ self.__load_temp_file()
+ self.main.add_dockwidget(self)
+ self.main.add_to_fileswitcher(self, editorstack.tabs, editorstack.data,
+ ima.icon('TextFileIcon'))
+
+ def update_font(self):
+ """Update font from Preferences"""
+ font = self.get_plugin_font()
+ color_scheme = self.get_color_scheme()
+ for editorstack in self.editorstacks:
+ editorstack.set_default_font(font, color_scheme)
+ completion_size = CONF.get('main', 'completion/size')
+ for finfo in editorstack.data:
+ comp_widget = finfo.editor.completion_widget
+ comp_widget.setup_appearance(completion_size, font)
+
+ def _create_checkable_action(self, text, conf_name, method=''):
+ """Helper function to create a checkable action.
+
+ Args:
+ text (str): Text to be displayed in the action.
+ conf_name (str): configuration setting associated with the
+ action
+ method (str): name of EditorStack class that will be used
+ to update the changes in each editorstack.
+ """
+ def toogle(checked):
+ self.switch_to_plugin()
+ self._toggle_checkable_action(checked, method, conf_name)
+ action = create_action(self, text, toggled=toogle)
+
+ if conf_name not in ['pycodestyle', 'pydocstyle']:
+ action.setChecked(self.get_option(conf_name))
+ else:
+ action.setChecked(CONF.get('lsp-server', conf_name))
+
+ return action
+
+ @Slot(bool, str, str)
+ def _toggle_checkable_action(self, checked, method_name, conf_name):
+ """
+ Handle the toogle of a checkable action.
+
+ Update editorstacks, PyLS and CONF.
+
+ Args:
+ checked (bool): State of the action.
+ method_name (str): name of EditorStack class that will be used
+ to update the changes in each editorstack.
+ conf_name (str): configuration setting associated with the
+ action.
+ """
+ if method_name:
+ if self.editorstacks:
+ for editorstack in self.editorstacks:
+ try:
+ method = getattr(editorstack, method_name)
+ method(checked)
+ except AttributeError as e:
+ logger.error(e, exc_info=True)
+ self.set_option(conf_name, checked)
+ else:
+ if conf_name == 'pycodestyle':
+ CONF.set('lsp-server', 'pycodestyle', checked)
+ elif conf_name == 'pydocstyle':
+ CONF.set('lsp-server', 'pydocstyle', checked)
+ self.main.lspmanager.update_server_list()
+
+ def received_sig_option_changed(self, option, value):
+ """
+ Called when sig_option_changed is received.
+
+ If option being changed is autosave_mapping, then synchronize new
+ mapping with all editor stacks except the sender.
+ """
+ if option == 'autosave_mapping':
+ for editorstack in self.editorstacks:
+ if editorstack != self.sender():
+ editorstack.autosave_mapping = value
+ self.sig_option_changed.emit(option, value)
+
+ #------ Focus tabwidget
+ def __get_focus_editorstack(self):
+ fwidget = QApplication.focusWidget()
+ if isinstance(fwidget, EditorStack):
+ return fwidget
+ else:
+ for editorstack in self.editorstacks:
+ if editorstack.isAncestorOf(fwidget):
+ return editorstack
+
+ def set_last_focus_editorstack(self, editorwindow, editorstack):
+ self.last_focus_editorstack[editorwindow] = editorstack
+ self.last_focus_editorstack[None] = editorstack # very last editorstack
+
+ def get_last_focus_editorstack(self, editorwindow=None):
+ return self.last_focus_editorstack[editorwindow]
+
+ def remove_last_focus_editorstack(self, editorstack):
+ for editorwindow, widget in list(self.last_focus_editorstack.items()):
+ if widget is editorstack:
+ self.last_focus_editorstack[editorwindow] = None
+
+ def save_focus_editorstack(self):
+ editorstack = self.__get_focus_editorstack()
+ if editorstack is not None:
+ for win in [self]+self.editorwindows:
+ if win.isAncestorOf(editorstack):
+ self.set_last_focus_editorstack(win, editorstack)
+
+ # ------ Handling editorstacks
+ def register_editorstack(self, editorstack):
+ self.editorstacks.append(editorstack)
+ self.register_widget_shortcuts(editorstack)
+ if len(self.editorstacks) > 1 and self.main is not None:
+ # The first editostack is registered automatically with Spyder's
+ # main window through the `register_plugin` method. Only additional
+ # editors added by splitting need to be registered.
+ # See Issue #5057.
+ self.main.fileswitcher.sig_goto_file.connect(
+ editorstack.set_stack_index)
+
+ if self.isAncestorOf(editorstack):
+ # editorstack is a child of the Editor plugin
+ self.set_last_focus_editorstack(self, editorstack)
+ editorstack.set_closable( len(self.editorstacks) > 1 )
+ if self.outlineexplorer is not None:
+ editorstack.set_outlineexplorer(self.outlineexplorer.explorer)
+ editorstack.set_find_widget(self.find_widget)
+ editorstack.reset_statusbar.connect(self.readwrite_status.hide)
+ editorstack.reset_statusbar.connect(self.encoding_status.hide)
+ editorstack.reset_statusbar.connect(self.cursorpos_status.hide)
+ editorstack.readonly_changed.connect(
+ self.readwrite_status.update_readonly)
+ editorstack.encoding_changed.connect(
+ self.encoding_status.update_encoding)
+ editorstack.sig_editor_cursor_position_changed.connect(
+ self.cursorpos_status.update_cursor_position)
+ editorstack.sig_refresh_eol_chars.connect(
+ self.eol_status.update_eol)
+ editorstack.current_file_changed.connect(
+ self.vcs_status.update_vcs)
+ editorstack.file_saved.connect(
+ self.vcs_status.update_vcs_state)
+
+ editorstack.autosave_mapping \
+ = CONF.get('editor', 'autosave_mapping', {})
+ editorstack.set_help(self.help)
+ editorstack.set_io_actions(self.new_action, self.open_action,
+ self.save_action, self.revert_action)
+ editorstack.set_tempfile_path(self.TEMPFILE_PATH)
+
+ settings = (
+ ('set_todolist_enabled', 'todo_list'),
+ ('set_blanks_enabled', 'blank_spaces'),
+ ('set_scrollpastend_enabled', 'scroll_past_end'),
+ ('set_linenumbers_enabled', 'line_numbers'),
+ ('set_edgeline_enabled', 'edge_line'),
+ ('set_edgeline_columns', 'edge_line_columns'),
+ ('set_indent_guides', 'indent_guides'),
+ ('set_focus_to_editor', 'focus_to_editor'),
+ ('set_run_cell_copy', 'run_cell_copy'),
+ ('set_close_parentheses_enabled', 'close_parentheses'),
+ ('set_close_quotes_enabled', 'close_quotes'),
+ ('set_add_colons_enabled', 'add_colons'),
+ ('set_auto_unindent_enabled', 'auto_unindent'),
+ ('set_indent_chars', 'indent_chars'),
+ ('set_tab_stop_width_spaces', 'tab_stop_width_spaces'),
+ ('set_wrap_enabled', 'wrap'),
+ ('set_tabmode_enabled', 'tab_always_indent'),
+ ('set_stripmode_enabled', 'strip_trailing_spaces_on_modify'),
+ ('set_intelligent_backspace_enabled', 'intelligent_backspace'),
+ ('set_highlight_current_line_enabled', 'highlight_current_line'),
+ ('set_highlight_current_cell_enabled', 'highlight_current_cell'),
+ ('set_occurrence_highlighting_enabled', 'occurrence_highlighting'),
+ ('set_occurrence_highlighting_timeout', 'occurrence_highlighting/timeout'),
+ ('set_checkeolchars_enabled', 'check_eol_chars'),
+ ('set_tabbar_visible', 'show_tab_bar'),
+ ('set_classfunc_dropdown_visible', 'show_class_func_dropdown'),
+ ('set_always_remove_trailing_spaces', 'always_remove_trailing_spaces'),
+ ('set_convert_eol_on_save', 'convert_eol_on_save'),
+ ('set_convert_eol_on_save_to', 'convert_eol_on_save_to'),
+ )
+ for method, setting in settings:
+ getattr(editorstack, method)(self.get_option(setting))
+ editorstack.set_help_enabled(CONF.get('help', 'connect/editor'))
+ color_scheme = self.get_color_scheme()
+ editorstack.set_default_font(self.get_plugin_font(), color_scheme)
+
+ editorstack.starting_long_process.connect(self.starting_long_process)
+ editorstack.ending_long_process.connect(self.ending_long_process)
+
+ # Redirect signals
+ editorstack.sig_option_changed.connect(
+ self.received_sig_option_changed)
+ editorstack.redirect_stdio.connect(
+ lambda state: self.redirect_stdio.emit(state))
+ editorstack.exec_in_extconsole.connect(
+ lambda text, option:
+ self.exec_in_extconsole.emit(text, option))
+ editorstack.run_cell_in_ipyclient.connect(
+ lambda code, cell_name, filename, run_cell_copy:
+ self.run_cell_in_ipyclient.emit(code, cell_name, filename,
+ run_cell_copy))
+ editorstack.update_plugin_title.connect(
+ lambda: self.sig_update_plugin_title.emit())
+ editorstack.editor_focus_changed.connect(self.save_focus_editorstack)
+ editorstack.editor_focus_changed.connect(self.main.plugin_focus_changed)
+ editorstack.editor_focus_changed.connect(self.sig_editor_focus_changed)
+ editorstack.zoom_in.connect(lambda: self.zoom(1))
+ editorstack.zoom_out.connect(lambda: self.zoom(-1))
+ editorstack.zoom_reset.connect(lambda: self.zoom(0))
+ editorstack.sig_open_file.connect(self.report_open_file)
+ editorstack.sig_new_file.connect(lambda s: self.new(text=s))
+ editorstack.sig_new_file[()].connect(self.new)
+ editorstack.sig_close_file.connect(self.close_file_in_all_editorstacks)
+ editorstack.file_saved.connect(self.file_saved_in_editorstack)
+ editorstack.file_renamed_in_data.connect(
+ self.file_renamed_in_data_in_editorstack)
+ editorstack.opened_files_list_changed.connect(
+ self.opened_files_list_changed)
+ editorstack.active_languages_stats.connect(
+ self.update_active_languages)
+ editorstack.sig_go_to_definition.connect(
+ lambda fname, line, col: self.load(
+ fname, line, start_column=col))
+ editorstack.perform_lsp_request.connect(self.send_lsp_request)
+ editorstack.todo_results_changed.connect(self.todo_results_changed)
+ editorstack.update_code_analysis_actions.connect(
+ self.update_code_analysis_actions)
+ editorstack.update_code_analysis_actions.connect(
+ self.update_todo_actions)
+ editorstack.refresh_file_dependent_actions.connect(
+ self.refresh_file_dependent_actions)
+ editorstack.refresh_save_all_action.connect(self.refresh_save_all_action)
+ editorstack.sig_refresh_eol_chars.connect(self.refresh_eol_chars)
+ editorstack.sig_breakpoints_saved.connect(self.breakpoints_saved)
+ editorstack.text_changed_at.connect(self.text_changed_at)
+ editorstack.current_file_changed.connect(self.current_file_changed)
+ editorstack.plugin_load.connect(self.load)
+ editorstack.plugin_load[()].connect(self.load)
+ editorstack.edit_goto.connect(self.load)
+ editorstack.sig_save_as.connect(self.save_as)
+ editorstack.sig_prev_edit_pos.connect(self.go_to_last_edit_location)
+ editorstack.sig_prev_cursor.connect(self.go_to_previous_cursor_position)
+ editorstack.sig_next_cursor.connect(self.go_to_next_cursor_position)
+ editorstack.sig_prev_warning.connect(self.go_to_previous_warning)
+ editorstack.sig_next_warning.connect(self.go_to_next_warning)
+ editorstack.sig_save_bookmark.connect(self.save_bookmark)
+ editorstack.sig_load_bookmark.connect(self.load_bookmark)
+ editorstack.sig_save_bookmarks.connect(self.save_bookmarks)
+
+ def unregister_editorstack(self, editorstack):
+ """Removing editorstack only if it's not the last remaining"""
+ self.remove_last_focus_editorstack(editorstack)
+ if len(self.editorstacks) > 1:
+ index = self.editorstacks.index(editorstack)
+ self.editorstacks.pop(index)
+ return True
+ else:
+ # editorstack was not removed!
+ return False
+
+ def clone_editorstack(self, editorstack):
+ editorstack.clone_from(self.editorstacks[0])
+ for finfo in editorstack.data:
+ self.register_widget_shortcuts(finfo.editor)
+
+ @Slot(str, str)
+ def close_file_in_all_editorstacks(self, editorstack_id_str, filename):
+ for editorstack in self.editorstacks:
+ if str(id(editorstack)) != editorstack_id_str:
+ editorstack.blockSignals(True)
+ index = editorstack.get_index_from_filename(filename)
+ editorstack.close_file(index, force=True)
+ editorstack.blockSignals(False)
+
+ @Slot(str, str, str)
+ def file_saved_in_editorstack(self, editorstack_id_str,
+ original_filename, filename):
+ """A file was saved in editorstack, this notifies others"""
+ for editorstack in self.editorstacks:
+ if str(id(editorstack)) != editorstack_id_str:
+ editorstack.file_saved_in_other_editorstack(original_filename,
+ filename)
+
+ @Slot(str, str, str)
+ def file_renamed_in_data_in_editorstack(self, editorstack_id_str,
+ original_filename, filename):
+ """A file was renamed in data in editorstack, this notifies others"""
+ for editorstack in self.editorstacks:
+ if str(id(editorstack)) != editorstack_id_str:
+ editorstack.rename_in_data(original_filename, filename)
+
+ #------ Handling editor windows
+ def setup_other_windows(self):
+ """Setup toolbars and menus for 'New window' instances"""
+
+ self.toolbar_list = ((_("File toolbar"), "file_toolbar",
+ self.main.file_toolbar_actions),
+ (_("Search toolbar"), "search_toolbar",
+ self.main.search_menu_actions),
+ (_("Source toolbar"), "source_toolbar",
+ self.main.source_toolbar_actions),
+ (_("Run toolbar"), "run_toolbar",
+ self.main.run_toolbar_actions),
+ (_("Debug toolbar"), "debug_toolbar",
+ self.main.debug_toolbar_actions),
+ (_("Edit toolbar"), "edit_toolbar",
+ self.main.edit_toolbar_actions))
+ self.menu_list = ((_("&File"), self.main.file_menu_actions),
+ (_("&Edit"), self.main.edit_menu_actions),
+ (_("&Search"), self.main.search_menu_actions),
+ (_("Sour&ce"), self.main.source_menu_actions),
+ (_("&Run"), self.main.run_menu_actions),
+ (_("&Tools"), self.main.tools_menu_actions),
+ (_("&View"), []),
+ (_("&Help"), self.main.help_menu_actions))
+ # Create pending new windows:
+ for layout_settings in self.editorwindows_to_be_created:
+ win = self.create_new_window()
+ win.set_layout_settings(layout_settings)
+
+ def switch_to_plugin(self):
+ """
+ Reimplemented method to deactivate shortcut when
+ opening a new window.
+ """
+ if not self.editorwindows:
+ super(Editor, self).switch_to_plugin()
+
+ def create_new_window(self):
+ oe_options = self.outlineexplorer.explorer.get_options()
+ window = EditorMainWindow(
+ self, self.stack_menu_actions, self.toolbar_list, self.menu_list,
+ outline_explorer_options=oe_options)
+ window.add_toolbars_to_menu("&View", window.get_toolbars())
+ window.load_toolbars()
+ window.resize(self.size())
+ window.show()
+ window.editorwidget.editorsplitter.editorstack.new_window = True
+ self.register_editorwindow(window)
+ window.destroyed.connect(lambda: self.unregister_editorwindow(window))
+ return window
+
+ def register_editorwindow(self, window):
+ self.editorwindows.append(window)
+
+ def unregister_editorwindow(self, window):
+ self.editorwindows.pop(self.editorwindows.index(window))
+
+
+ #------ Accessors
+ def get_filenames(self):
+ return [finfo.filename for finfo in self.editorstacks[0].data]
+
+ def get_filename_index(self, filename):
+ return self.editorstacks[0].has_filename(filename)
+
+ def get_current_editorstack(self, editorwindow=None):
+ if self.editorstacks is not None:
+ if len(self.editorstacks) == 1:
+ editorstack = self.editorstacks[0]
+ else:
+ editorstack = self.__get_focus_editorstack()
+ if editorstack is None or editorwindow is not None:
+ editorstack = self.get_last_focus_editorstack(editorwindow)
+ if editorstack is None:
+ editorstack = self.editorstacks[0]
+ return editorstack
+
+ def get_current_editor(self):
+ editorstack = self.get_current_editorstack()
+ if editorstack is not None:
+ return editorstack.get_current_editor()
+
+ def get_current_finfo(self):
+ editorstack = self.get_current_editorstack()
+ if editorstack is not None:
+ return editorstack.get_current_finfo()
+
+ def get_current_filename(self):
+ editorstack = self.get_current_editorstack()
+ if editorstack is not None:
+ return editorstack.get_current_filename()
+
+ def is_file_opened(self, filename=None):
+ return self.editorstacks[0].is_file_opened(filename)
+
+ def set_current_filename(self, filename, editorwindow=None, focus=True):
+ """Set focus to *filename* if this file has been opened.
+
+ Return the editor instance associated to *filename*.
+ """
+ editorstack = self.get_current_editorstack(editorwindow)
+ return editorstack.set_current_filename(filename, focus)
+
+ def set_path(self):
+ # TODO: Fix this
+ for finfo in self.editorstacks[0].data:
+ finfo.path = self.main.get_spyder_pythonpath()
+ #if self.introspector:
+ # self.introspector.change_extra_path(
+ # self.main.get_spyder_pythonpath())
+
+ #------ FileSwitcher API
+ def get_current_tab_manager(self):
+ """Get the widget with the TabWidget attribute."""
+ return self.get_current_editorstack()
+
+ #------ Refresh methods
+ def refresh_file_dependent_actions(self):
+ """Enable/disable file dependent actions
+ (only if dockwidget is visible)"""
+ if self.dockwidget and self.dockwidget.isVisible():
+ enable = self.get_current_editor() is not None
+ for action in self.file_dependent_actions:
+ action.setEnabled(enable)
+
+ def refresh_save_all_action(self):
+ """Enable 'Save All' if there are files to be saved"""
+ editorstack = self.get_current_editorstack()
+ if editorstack:
+ state = any(finfo.editor.document().isModified() or finfo.newly_created
+ for finfo in editorstack.data)
+ self.save_all_action.setEnabled(state)
+
+ def update_warning_menu(self):
+ """Update warning list menu"""
+ editor = self.get_current_editor()
+ check_results = editor.get_current_warnings()
+ self.warning_menu.clear()
+ filename = self.get_current_filename()
+ for message, line_number in check_results:
+ error = 'syntax' in message
+ text = message[:1].upper() + message[1:]
+ icon = ima.icon('error') if error else ima.icon('warning')
+ slot = lambda _checked, _l=line_number: self.load(filename, goto=_l)
+ action = create_action(self, text=text, icon=icon, triggered=slot)
+ self.warning_menu.addAction(action)
+
+ def update_todo_menu(self):
+ """Update todo list menu"""
+ editorstack = self.get_current_editorstack()
+ results = editorstack.get_todo_results()
+ self.todo_menu.clear()
+ filename = self.get_current_filename()
+ for text, line0 in results:
+ icon = ima.icon('todo')
+ slot = lambda _checked, _l=line0: self.load(filename, goto=_l)
+ action = create_action(self, text=text, icon=icon, triggered=slot)
+ self.todo_menu.addAction(action)
+ self.update_todo_actions()
+
+ def todo_results_changed(self):
+ """
+ Synchronize todo results between editorstacks
+ Refresh todo list navigation buttons
+ """
+ editorstack = self.get_current_editorstack()
+ results = editorstack.get_todo_results()
+ index = editorstack.get_stack_index()
+ if index != -1:
+ filename = editorstack.data[index].filename
+ for other_editorstack in self.editorstacks:
+ if other_editorstack is not editorstack:
+ other_editorstack.set_todo_results(filename, results)
+ self.update_todo_actions()
+
+ def refresh_eol_chars(self, os_name):
+ os_name = to_text_string(os_name)
+ self.__set_eol_chars = False
+ if os_name == 'nt':
+ self.win_eol_action.setChecked(True)
+ elif os_name == 'posix':
+ self.linux_eol_action.setChecked(True)
+ else:
+ self.mac_eol_action.setChecked(True)
+ self.__set_eol_chars = True
+
+ #------ Slots
+ def opened_files_list_changed(self):
+ """
+ Opened files list has changed:
+ --> open/close file action
+ --> modification ('*' added to title)
+ --> current edited file has changed
+ """
+ # Refresh Python file dependent actions:
+ editor = self.get_current_editor()
+ if editor:
+ python_enable = editor.is_python()
+ cython_enable = python_enable or (
+ programs.is_module_installed('Cython') and editor.is_cython())
+ for action in self.pythonfile_dependent_actions:
+ if action in self.cythonfile_compatible_actions:
+ enable = cython_enable
+ else:
+ enable = python_enable
+ if action is self.winpdb_action:
+ action.setEnabled(enable and WINPDB_PATH is not None)
+ else:
+ action.setEnabled(enable)
+ self.open_file_update.emit(self.get_current_filename())
+
+ def update_code_analysis_actions(self):
+ """Update actions in the warnings menu."""
+ editor = self.get_current_editor()
+ # To fix an error at startup
+ if editor is None:
+ return
+ results = editor.get_current_warnings()
+ # Update code analysis actions
+ state = results is not None and len(results)
+ for action in (self.warning_list_action, self.previous_warning_action,
+ self.next_warning_action):
+ if state is not None:
+ action.setEnabled(state)
+
+ def update_todo_actions(self):
+ editorstack = self.get_current_editorstack()
+ results = editorstack.get_todo_results()
+ state = (self.get_option('todo_list') and
+ results is not None and len(results))
+ if state is not None:
+ self.todo_list_action.setEnabled(state)
+
+ def rehighlight_cells(self):
+ """Rehighlight cells of current editor"""
+ editor = self.get_current_editor()
+ editor.rehighlight_cells()
+ QApplication.processEvents()
+
+ @Slot(set)
+ def update_active_languages(self, languages):
+ self.main.lspmanager.update_client_status(languages)
+
+
+ #------ Breakpoints
+ def save_breakpoints(self, filename, breakpoints):
+ filename = to_text_string(filename)
+ breakpoints = to_text_string(breakpoints)
+ filename = osp.normpath(osp.abspath(filename))
+ if breakpoints:
+ breakpoints = eval(breakpoints)
+ else:
+ breakpoints = []
+ save_breakpoints(filename, breakpoints)
+ self.breakpoints_saved.emit()
+
+ # ------ Bookmarks
+ def save_bookmarks(self, filename, bookmarks):
+ """Receive bookmark changes and save them."""
+ filename = to_text_string(filename)
+ bookmarks = to_text_string(bookmarks)
+ filename = osp.normpath(osp.abspath(filename))
+ bookmarks = eval(bookmarks)
+ save_bookmarks(filename, bookmarks)
+
+ #------ File I/O
+ def __load_temp_file(self):
+ """Load temporary file from a text file in user home directory"""
+ if not osp.isfile(self.TEMPFILE_PATH):
+ # Creating temporary file
+ default = ['# -*- coding: utf-8 -*-',
+ '"""', _("Spyder Editor"), '',
+ _("This is a temporary script file."),
+ '"""', '', '']
+ text = os.linesep.join([encoding.to_unicode(qstr)
+ for qstr in default])
+ try:
+ encoding.write(to_text_string(text), self.TEMPFILE_PATH,
+ 'utf-8')
+ except EnvironmentError:
+ self.new()
+ return
+
+ self.load(self.TEMPFILE_PATH)
+
+ @Slot()
+ def __set_workdir(self):
+ """Set current script directory as working directory"""
+ fname = self.get_current_filename()
+ if fname is not None:
+ directory = osp.dirname(osp.abspath(fname))
+ self.open_dir.emit(directory)
+
+ def __add_recent_file(self, fname):
+ """Add to recent file list"""
+ if fname is None:
+ return
+ if fname in self.recent_files:
+ self.recent_files.remove(fname)
+ self.recent_files.insert(0, fname)
+ if len(self.recent_files) > self.get_option('max_recent_files'):
+ self.recent_files.pop(-1)
+
+ def _clone_file_everywhere(self, finfo):
+ """Clone file (*src_editor* widget) in all editorstacks
+ Cloning from the first editorstack in which every single new editor
+ is created (when loading or creating a new file)"""
+ for editorstack in self.editorstacks[1:]:
+ editor = editorstack.clone_editor_from(finfo, set_current=False)
+ self.register_widget_shortcuts(editor)
+
+
+ @Slot()
+ @Slot(str)
+ def new(self, fname=None, editorstack=None, text=None):
+ """
+ Create a new file - Untitled
+
+ fname=None --> fname will be 'untitledXX.py' but do not create file
+ fname= --> create file
+ """
+ # If no text is provided, create default content
+ empty = False
+ try:
+ if text is None:
+ default_content = True
+ text, enc = encoding.read(self.TEMPLATE_PATH)
+ enc_match = re.search(r'-*- coding: ?([a-z0-9A-Z\-]*) -*-',
+ text)
+ if enc_match:
+ enc = enc_match.group(1)
+ # Initialize template variables
+ # Windows
+ username = encoding.to_unicode_from_fs(
+ os.environ.get('USERNAME', ''))
+ # Linux, Mac OS X
+ if not username:
+ username = encoding.to_unicode_from_fs(
+ os.environ.get('USER', '-'))
+ VARS = {
+ 'date': time.ctime(),
+ 'username': username,
+ }
+ try:
+ text = text % VARS
+ except Exception:
+ pass
+ else:
+ default_content = False
+ enc = encoding.read(self.TEMPLATE_PATH)[1]
+ except (IOError, OSError):
+ text = ''
+ enc = 'utf-8'
+ default_content = True
+ empty = True
+
+ create_fname = lambda n: to_text_string(_("untitled")) + ("%d.py" % n)
+ # Creating editor widget
+ if editorstack is None:
+ current_es = self.get_current_editorstack()
+ else:
+ current_es = editorstack
+ created_from_here = fname is None
+ if created_from_here:
+ while True:
+ fname = create_fname(self.untitled_num)
+ self.untitled_num += 1
+ if not osp.isfile(fname):
+ break
+ basedir = getcwd_or_home()
+
+ if self.main.projects.get_active_project() is not None:
+ basedir = self.main.projects.get_active_project_path()
+ else:
+ c_fname = self.get_current_filename()
+ if c_fname is not None and c_fname != self.TEMPFILE_PATH:
+ basedir = osp.dirname(c_fname)
+ fname = osp.abspath(osp.join(basedir, fname))
+ else:
+ # QString when triggered by a Qt signal
+ fname = osp.abspath(to_text_string(fname))
+ index = current_es.has_filename(fname)
+ if index is not None and not current_es.close_file(index):
+ return
+
+ # Creating the editor widget in the first editorstack (the one that
+ # can't be destroyed), then cloning this editor widget in all other
+ # editorstacks:
+ finfo = self.editorstacks[0].new(fname, enc, text, default_content,
+ empty)
+ finfo.path = self.main.get_spyder_pythonpath()
+ self._clone_file_everywhere(finfo)
+ current_editor = current_es.set_current_filename(finfo.filename)
+ self.register_widget_shortcuts(current_editor)
+ if not created_from_here:
+ self.save(force=True)
+
+ def edit_template(self):
+ """Edit new file template"""
+ self.load(self.TEMPLATE_PATH)
+
+ def update_recent_file_menu(self):
+ """Update recent file menu"""
+ recent_files = []
+ for fname in self.recent_files:
+ if osp.isfile(fname):
+ recent_files.append(fname)
+ self.recent_file_menu.clear()
+ if recent_files:
+ for fname in recent_files:
+ action = create_action(
+ self, fname,
+ icon=ima.get_icon_by_extension(fname, scale_factor=1.0),
+ triggered=self.load)
+ action.setData(to_qvariant(fname))
+ self.recent_file_menu.addAction(action)
+ self.clear_recent_action.setEnabled(len(recent_files) > 0)
+ add_actions(self.recent_file_menu, (None, self.max_recent_action,
+ self.clear_recent_action))
+
+ @Slot()
+ def clear_recent_files(self):
+ """Clear recent files list"""
+ self.recent_files = []
+
+ @Slot()
+ def change_max_recent_files(self):
+ "Change max recent files entries"""
+ editorstack = self.get_current_editorstack()
+ mrf, valid = QInputDialog.getInt(editorstack, _('Editor'),
+ _('Maximum number of recent files'),
+ self.get_option('max_recent_files'), 1, 35)
+ if valid:
+ self.set_option('max_recent_files', mrf)
+
+ @Slot()
+ @Slot(str)
+ @Slot(str, int, str)
+ @Slot(str, int, str, object)
+ def load(self, filenames=None, goto=None, word='',
+ editorwindow=None, processevents=True, start_column=None,
+ set_focus=True, add_where='end'):
+ """
+ Load a text file
+ editorwindow: load in this editorwindow (useful when clicking on
+ outline explorer with multiple editor windows)
+ processevents: determines if processEvents() should be called at the
+ end of this method (set to False to prevent keyboard events from
+ creeping through to the editor during debugging)
+ """
+ # Switch to editor before trying to load a file
+ try:
+ self.switch_to_plugin()
+ except AttributeError:
+ pass
+
+ editor0 = self.get_current_editor()
+ if editor0 is not None:
+ position0 = editor0.get_position('cursor')
+ filename0 = self.get_current_filename()
+ else:
+ position0, filename0 = None, None
+ if not filenames:
+ # Recent files action
+ action = self.sender()
+ if isinstance(action, QAction):
+ filenames = from_qvariant(action.data(), to_text_string)
+ if not filenames:
+ basedir = getcwd_or_home()
+ if self.edit_filetypes is None:
+ self.edit_filetypes = get_edit_filetypes()
+ if self.edit_filters is None:
+ self.edit_filters = get_edit_filters()
+
+ c_fname = self.get_current_filename()
+ if c_fname is not None and c_fname != self.TEMPFILE_PATH:
+ basedir = osp.dirname(c_fname)
+ self.redirect_stdio.emit(False)
+ parent_widget = self.get_current_editorstack()
+ if filename0 is not None:
+ selectedfilter = get_filter(self.edit_filetypes,
+ osp.splitext(filename0)[1])
+ else:
+ selectedfilter = ''
+ if not running_under_pytest():
+ filenames, _sf = getopenfilenames(
+ parent_widget,
+ _("Open file"), basedir,
+ self.edit_filters,
+ selectedfilter=selectedfilter,
+ options=QFileDialog.HideNameFilterDetails)
+ else:
+ # Use a Qt (i.e. scriptable) dialog for pytest
+ dialog = QFileDialog(parent_widget, _("Open file"),
+ options=QFileDialog.DontUseNativeDialog)
+ if dialog.exec_():
+ filenames = dialog.selectedFiles()
+ self.redirect_stdio.emit(True)
+ if filenames:
+ filenames = [osp.normpath(fname) for fname in filenames]
+ else:
+ return
+
+ focus_widget = QApplication.focusWidget()
+ if self.editorwindows and not self.dockwidget.isVisible():
+ # We override the editorwindow variable to force a focus on
+ # the editor window instead of the hidden editor dockwidget.
+ # See PR #5742.
+ if editorwindow not in self.editorwindows:
+ editorwindow = self.editorwindows[0]
+ editorwindow.setFocus()
+ editorwindow.raise_()
+ elif (self.dockwidget and not self.ismaximized
+ and not self.dockwidget.isAncestorOf(focus_widget)
+ and not isinstance(focus_widget, CodeEditor)):
+ self.dockwidget.setVisible(True)
+ self.dockwidget.setFocus()
+ self.dockwidget.raise_()
+
+ def _convert(fname):
+ fname = osp.abspath(encoding.to_unicode_from_fs(fname))
+ if os.name == 'nt' and len(fname) >= 2 and fname[1] == ':':
+ fname = fname[0].upper()+fname[1:]
+ return fname
+
+ if hasattr(filenames, 'replaceInStrings'):
+ # This is a QStringList instance (PyQt API #1), converting to list:
+ filenames = list(filenames)
+ if not isinstance(filenames, list):
+ filenames = [_convert(filenames)]
+ else:
+ filenames = [_convert(fname) for fname in list(filenames)]
+ if isinstance(goto, int):
+ goto = [goto]
+ elif goto is not None and len(goto) != len(filenames):
+ goto = None
+
+ for index, filename in enumerate(filenames):
+ # -- Do not open an already opened file
+ focus = set_focus and index == 0
+ current_editor = self.set_current_filename(filename,
+ editorwindow,
+ focus=focus)
+ if current_editor is None:
+ # -- Not a valid filename:
+ if not osp.isfile(filename):
+ continue
+ # --
+ current_es = self.get_current_editorstack(editorwindow)
+ # Creating the editor widget in the first editorstack
+ # (the one that can't be destroyed), then cloning this
+ # editor widget in all other editorstacks:
+ finfo = self.editorstacks[0].load(
+ filename, set_current=False, add_where=add_where)
+ finfo.path = self.main.get_spyder_pythonpath()
+ self._clone_file_everywhere(finfo)
+ current_editor = current_es.set_current_filename(filename,
+ focus=focus)
+ current_editor.debugger.load_breakpoints()
+ current_editor.set_bookmarks(load_bookmarks(filename))
+ self.register_widget_shortcuts(current_editor)
+ current_es.analyze_script()
+ self.__add_recent_file(filename)
+ if goto is not None: # 'word' is assumed to be None as well
+ current_editor.go_to_line(goto[index], word=word,
+ start_column=start_column)
+ position = current_editor.get_position('cursor')
+ self.cursor_moved(filename0, position0, filename, position)
+ current_editor.clearFocus()
+ current_editor.setFocus()
+ current_editor.window().raise_()
+ if processevents:
+ QApplication.processEvents()
+ else:
+ # processevents is false only when calling from debugging
+ current_editor.sig_debug_stop.emit(goto[index])
+ current_sw = self.main.ipyconsole.get_current_shellwidget()
+ current_sw.sig_prompt_ready.connect(
+ current_editor.sig_debug_stop[()].emit)
+
+ @Slot()
+ def print_file(self):
+ """Print current file"""
+ editor = self.get_current_editor()
+ filename = self.get_current_filename()
+ printer = Printer(mode=QPrinter.HighResolution,
+ header_font=self.get_plugin_font('printer_header'))
+ printDialog = QPrintDialog(printer, editor)
+ if editor.has_selected_text():
+ printDialog.setOption(QAbstractPrintDialog.PrintSelection, True)
+ self.redirect_stdio.emit(False)
+ answer = printDialog.exec_()
+ self.redirect_stdio.emit(True)
+ if answer == QDialog.Accepted:
+ self.starting_long_process(_("Printing..."))
+ printer.setDocName(filename)
+ editor.print_(printer)
+ self.ending_long_process()
+
+ @Slot()
+ def print_preview(self):
+ """Print preview for current file"""
+ from qtpy.QtPrintSupport import QPrintPreviewDialog
+
+ editor = self.get_current_editor()
+ printer = Printer(mode=QPrinter.HighResolution,
+ header_font=self.get_plugin_font('printer_header'))
+ preview = QPrintPreviewDialog(printer, self)
+ preview.setWindowFlags(Qt.Window)
+ preview.paintRequested.connect(lambda printer: editor.print_(printer))
+ self.redirect_stdio.emit(False)
+ preview.exec_()
+ self.redirect_stdio.emit(True)
+
+ @Slot()
+ def close_file(self):
+ """Close current file"""
+ editorstack = self.get_current_editorstack()
+ editorstack.close_file()
+ @Slot()
+ def close_all_files(self):
+ """Close all opened scripts"""
+ self.editorstacks[0].close_all_files()
+
+ @Slot()
+ def save(self, index=None, force=False):
+ """Save file"""
+ editorstack = self.get_current_editorstack()
+ return editorstack.save(index=index, force=force)
+
+ @Slot()
+ def save_as(self):
+ """Save *as* the currently edited file"""
+ editorstack = self.get_current_editorstack()
+ if editorstack.save_as():
+ fname = editorstack.get_current_filename()
+ self.__add_recent_file(fname)
+
+ @Slot()
+ def save_copy_as(self):
+ """Save *copy as* the currently edited file"""
+ editorstack = self.get_current_editorstack()
+ editorstack.save_copy_as()
+
+ @Slot()
+ def save_all(self):
+ """Save all opened files"""
+ self.get_current_editorstack().save_all()
+
+ @Slot()
+ def revert(self):
+ """Revert the currently edited file from disk"""
+ editorstack = self.get_current_editorstack()
+ editorstack.revert()
+
+ @Slot()
+ def find(self):
+ """Find slot"""
+ editorstack = self.get_current_editorstack()
+ editorstack.find_widget.show()
+ editorstack.find_widget.search_text.setFocus()
+
+ @Slot()
+ def find_next(self):
+ """Fnd next slot"""
+ editorstack = self.get_current_editorstack()
+ editorstack.find_widget.find_next()
+
+ @Slot()
+ def find_previous(self):
+ """Find previous slot"""
+ editorstack = self.get_current_editorstack()
+ editorstack.find_widget.find_previous()
+
+ @Slot()
+ def replace(self):
+ """Replace slot"""
+ editorstack = self.get_current_editorstack()
+ editorstack.find_widget.show_replace()
+
+ def open_last_closed(self):
+ """ Reopens the last closed tab."""
+ editorstack = self.get_current_editorstack()
+ last_closed_files = editorstack.get_last_closed_files()
+ if (len(last_closed_files) > 0):
+ file_to_open = last_closed_files[0]
+ last_closed_files.remove(file_to_open)
+ editorstack.set_last_closed_files(last_closed_files)
+ self.load(file_to_open)
+
+ #------ Explorer widget
+ def close_file_from_name(self, filename):
+ """Close file from its name"""
+ filename = osp.abspath(to_text_string(filename))
+ index = self.editorstacks[0].has_filename(filename)
+ if index is not None:
+ self.editorstacks[0].close_file(index)
+
+ def removed(self, filename):
+ """File was removed in file explorer widget or in project explorer"""
+ self.close_file_from_name(filename)
+
+ def removed_tree(self, dirname):
+ """Directory was removed in project explorer widget"""
+ dirname = osp.abspath(to_text_string(dirname))
+ for fname in self.get_filenames():
+ if osp.abspath(fname).startswith(dirname):
+ self.close_file_from_name(fname)
+
+ def renamed(self, source, dest):
+ """File was renamed in file explorer widget or in project explorer"""
+ filename = osp.abspath(to_text_string(source))
+ index = self.editorstacks[0].has_filename(filename)
+ if index is not None:
+ for editorstack in self.editorstacks:
+ editorstack.rename_in_data(filename,
+ new_filename=to_text_string(dest))
+
+ def renamed_tree(self, source, dest):
+ """Directory was renamed in file explorer or in project explorer."""
+ dirname = osp.abspath(to_text_string(source))
+ tofile = to_text_string(dest)
+ for fname in self.get_filenames():
+ if osp.abspath(fname).startswith(dirname):
+ new_filename = fname.replace(dirname, tofile)
+ self.renamed(source=fname, dest=new_filename)
+
+ #------ Source code
+ @Slot()
+ def indent(self):
+ """Indent current line or selection"""
+ editor = self.get_current_editor()
+ if editor is not None:
+ editor.indent()
+
+ @Slot()
+ def unindent(self):
+ """Unindent current line or selection"""
+ editor = self.get_current_editor()
+ if editor is not None:
+ editor.unindent()
+
+ @Slot()
+ def text_uppercase (self):
+ """Change current line or selection to uppercase."""
+ editor = self.get_current_editor()
+ if editor is not None:
+ editor.transform_to_uppercase()
+
+ @Slot()
+ def text_lowercase(self):
+ """Change current line or selection to lowercase."""
+ editor = self.get_current_editor()
+ if editor is not None:
+ editor.transform_to_lowercase()
+
+ @Slot()
+ def toggle_comment(self):
+ """Comment current line or selection"""
+ editor = self.get_current_editor()
+ if editor is not None:
+ editor.toggle_comment()
+
+ @Slot()
+ def blockcomment(self):
+ """Block comment current line or selection"""
+ editor = self.get_current_editor()
+ if editor is not None:
+ editor.blockcomment()
+
+ @Slot()
+ def unblockcomment(self):
+ """Un-block comment current line or selection"""
+ editor = self.get_current_editor()
+ if editor is not None:
+ editor.unblockcomment()
+ @Slot()
+ def go_to_next_todo(self):
+ self.switch_to_plugin()
+ editor = self.get_current_editor()
+ position = editor.go_to_next_todo()
+ filename = self.get_current_filename()
+ self.add_cursor_position_to_history(filename, position)
+
+ @Slot()
+ def go_to_next_warning(self):
+ self.switch_to_plugin()
+ editor = self.get_current_editor()
+ position = editor.go_to_next_warning()
+ filename = self.get_current_filename()
+ self.add_cursor_position_to_history(filename, position)
+
+ @Slot()
+ def go_to_previous_warning(self):
+ self.switch_to_plugin()
+ editor = self.get_current_editor()
+ position = editor.go_to_previous_warning()
+ filename = self.get_current_filename()
+ self.add_cursor_position_to_history(filename, position)
+
+ @Slot()
+ def run_winpdb(self):
+ """Run winpdb to debug current file"""
+ if self.save():
+ fname = self.get_current_filename()
+ runconf = get_run_configuration(fname)
+ if runconf is None:
+ args = []
+ wdir = None
+ else:
+ args = runconf.get_arguments().split()
+ wdir = runconf.get_working_directory()
+ # Handle the case where wdir comes back as an empty string
+ # when the working directory dialog checkbox is unchecked.
+ # (subprocess "cwd" default is None, so empty str
+ # must be changed to None in this case.)
+ programs.run_program(WINPDB_PATH, [fname] + args, cwd=wdir or None)
+
+ def toggle_eol_chars(self, os_name, checked):
+ if checked:
+ editor = self.get_current_editor()
+ if self.__set_eol_chars:
+ self.switch_to_plugin()
+ editor.set_eol_chars(sourcecode.get_eol_chars_from_os_name(os_name))
+
+ @Slot()
+ def remove_trailing_spaces(self):
+ self.switch_to_plugin()
+ editorstack = self.get_current_editorstack()
+ editorstack.remove_trailing_spaces()
+
+ @Slot()
+ def fix_indentation(self):
+ self.switch_to_plugin()
+ editorstack = self.get_current_editorstack()
+ editorstack.fix_indentation()
+
+ #------ Cursor position history management
+ def update_cursorpos_actions(self):
+ self.previous_edit_cursor_action.setEnabled(
+ self.last_edit_cursor_pos is not None)
+ self.previous_cursor_action.setEnabled(
+ self.cursor_pos_index is not None and self.cursor_pos_index > 0)
+ self.next_cursor_action.setEnabled(self.cursor_pos_index is not None \
+ and self.cursor_pos_index < len(self.cursor_pos_history)-1)
+
+ def add_cursor_position_to_history(self, filename, position, fc=False):
+ if self.__ignore_cursor_position:
+ return
+ for index, (fname, pos) in enumerate(self.cursor_pos_history[:]):
+ if fname == filename:
+ if pos == position or pos == 0:
+ if fc:
+ self.cursor_pos_history[index] = (filename, position)
+ self.cursor_pos_index = index
+ self.update_cursorpos_actions()
+ return
+ else:
+ if self.cursor_pos_index >= index:
+ self.cursor_pos_index -= 1
+ self.cursor_pos_history.pop(index)
+ break
+ if self.cursor_pos_index is not None:
+ self.cursor_pos_history = \
+ self.cursor_pos_history[:self.cursor_pos_index+1]
+ self.cursor_pos_history.append((filename, position))
+ self.cursor_pos_index = len(self.cursor_pos_history)-1
+ self.update_cursorpos_actions()
+
+ def cursor_moved(self, filename0, position0, filename1, position1):
+ """Cursor was just moved: 'go to'"""
+ if position0 is not None:
+ self.add_cursor_position_to_history(filename0, position0)
+ self.add_cursor_position_to_history(filename1, position1)
+
+ def text_changed_at(self, filename, position):
+ self.last_edit_cursor_pos = (to_text_string(filename), position)
+
+ def current_file_changed(self, filename, position):
+ self.add_cursor_position_to_history(to_text_string(filename), position,
+ fc=True)
+
+ @Slot()
+ def go_to_last_edit_location(self):
+ if self.last_edit_cursor_pos is not None:
+ filename, position = self.last_edit_cursor_pos
+ if not osp.isfile(filename):
+ self.last_edit_cursor_pos = None
+ return
+ else:
+ self.load(filename)
+ editor = self.get_current_editor()
+ if position < editor.document().characterCount():
+ editor.set_cursor_position(position)
+
+ def __move_cursor_position(self, index_move):
+ if self.cursor_pos_index is None:
+ return
+ filename, _position = self.cursor_pos_history[self.cursor_pos_index]
+ self.cursor_pos_history[self.cursor_pos_index] = ( filename,
+ self.get_current_editor().get_position('cursor') )
+ self.__ignore_cursor_position = True
+ old_index = self.cursor_pos_index
+ self.cursor_pos_index = min([
+ len(self.cursor_pos_history)-1,
+ max([0, self.cursor_pos_index+index_move])
+ ])
+ filename, position = self.cursor_pos_history[self.cursor_pos_index]
+ if not osp.isfile(filename):
+ self.cursor_pos_history.pop(self.cursor_pos_index)
+ if self.cursor_pos_index < old_index:
+ old_index -= 1
+ self.cursor_pos_index = old_index
+ else:
+ self.load(filename)
+ editor = self.get_current_editor()
+ if position < editor.document().characterCount():
+ editor.set_cursor_position(position)
+ self.__ignore_cursor_position = False
+ self.update_cursorpos_actions()
+
+ @Slot()
+ def go_to_previous_cursor_position(self):
+ self.switch_to_plugin()
+ self.__move_cursor_position(-1)
+
+ @Slot()
+ def go_to_next_cursor_position(self):
+ self.switch_to_plugin()
+ self.__move_cursor_position(1)
+
+ @Slot()
+ def go_to_line(self, line=None):
+ """Open 'go to line' dialog"""
+ editorstack = self.get_current_editorstack()
+ if editorstack is not None:
+ editorstack.go_to_line(line)
+
+ @Slot()
+ def set_or_clear_breakpoint(self):
+ """Set/Clear breakpoint"""
+ editorstack = self.get_current_editorstack()
+ if editorstack is not None:
+ self.switch_to_plugin()
+ editorstack.set_or_clear_breakpoint()
+
+ @Slot()
+ def set_or_edit_conditional_breakpoint(self):
+ """Set/Edit conditional breakpoint"""
+ editorstack = self.get_current_editorstack()
+ if editorstack is not None:
+ self.switch_to_plugin()
+ editorstack.set_or_edit_conditional_breakpoint()
+
+ @Slot()
+ def clear_all_breakpoints(self):
+ """Clear breakpoints in all files"""
+ self.switch_to_plugin()
+ clear_all_breakpoints()
+ self.breakpoints_saved.emit()
+ editorstack = self.get_current_editorstack()
+ if editorstack is not None:
+ for data in editorstack.data:
+ data.editor.debugger.clear_breakpoints()
+ self.refresh_plugin()
+
+ def clear_breakpoint(self, filename, lineno):
+ """Remove a single breakpoint"""
+ clear_breakpoint(filename, lineno)
+ self.breakpoints_saved.emit()
+ editorstack = self.get_current_editorstack()
+ if editorstack is not None:
+ index = self.is_file_opened(filename)
+ if index is not None:
+ editorstack.data[index].editor.debugger.toogle_breakpoint(
+ lineno)
+
+ def debug_command(self, command):
+ """Debug actions"""
+ self.switch_to_plugin()
+ self.main.ipyconsole.write_to_stdin(command)
+ focus_widget = self.main.ipyconsole.get_focus_widget()
+ if focus_widget:
+ focus_widget.setFocus()
+
+ #------ Run Python script
+ @Slot()
+ def edit_run_configurations(self):
+ dialog = RunConfigDialog(self)
+ dialog.size_change.connect(lambda s: self.set_dialog_size(s))
+ if self.dialog_size is not None:
+ dialog.resize(self.dialog_size)
+ fname = osp.abspath(self.get_current_filename())
+ dialog.setup(fname)
+ if dialog.exec_():
+ fname = dialog.file_to_run
+ if fname is not None:
+ self.load(fname)
+ self.run_file()
+
+ @Slot()
+ def run_file(self, debug=False):
+ """Run script inside current interpreter or in a new one"""
+ editorstack = self.get_current_editorstack()
+ if editorstack.save():
+ editor = self.get_current_editor()
+ fname = osp.abspath(self.get_current_filename())
+
+ # Get fname's dirname before we escape the single and double
+ # quotes (Fixes Issue #6771)
+ dirname = osp.dirname(fname)
+
+ # Escape single and double quotes in fname and dirname
+ # (Fixes Issue #2158)
+ fname = fname.replace("'", r"\'").replace('"', r'\"')
+ dirname = dirname.replace("'", r"\'").replace('"', r'\"')
+
+ runconf = get_run_configuration(fname)
+ if runconf is None:
+ dialog = RunConfigOneDialog(self)
+ dialog.size_change.connect(lambda s: self.set_dialog_size(s))
+ if self.dialog_size is not None:
+ dialog.resize(self.dialog_size)
+ dialog.setup(fname)
+ if CONF.get('run', 'open_at_least_once',
+ not running_under_pytest()):
+ # Open Run Config dialog at least once: the first time
+ # a script is ever run in Spyder, so that the user may
+ # see it at least once and be conscious that it exists
+ show_dlg = True
+ CONF.set('run', 'open_at_least_once', False)
+ else:
+ # Open Run Config dialog only
+ # if ALWAYS_OPEN_FIRST_RUN_OPTION option is enabled
+ show_dlg = CONF.get('run', ALWAYS_OPEN_FIRST_RUN_OPTION)
+ if show_dlg and not dialog.exec_():
+ return
+ runconf = dialog.get_configuration()
+
+ args = runconf.get_arguments()
+ python_args = runconf.get_python_arguments()
+ interact = runconf.interact
+ post_mortem = runconf.post_mortem
+ current = runconf.current
+ systerm = runconf.systerm
+ clear_namespace = runconf.clear_namespace
+
+ if runconf.file_dir:
+ wdir = dirname
+ elif runconf.cw_dir:
+ wdir = ''
+ elif osp.isdir(runconf.dir):
+ wdir = runconf.dir
+ else:
+ wdir = ''
+
+ python = True # Note: in the future, it may be useful to run
+ # something in a terminal instead of a Python interp.
+ self.__last_ec_exec = (fname, wdir, args, interact, debug,
+ python, python_args, current, systerm,
+ post_mortem, clear_namespace)
+ self.re_run_file()
+ if not interact and not debug:
+ # If external console dockwidget is hidden, it will be
+ # raised in top-level and so focus will be given to the
+ # current external shell automatically
+ # (see SpyderPluginWidget.visibility_changed method)
+ editor.setFocus()
+
+ def set_dialog_size(self, size):
+ self.dialog_size = size
+
+ @Slot()
+ def debug_file(self):
+ """Debug current script"""
+ self.switch_to_plugin()
+ current_editor = self.get_current_editor()
+ if current_editor is not None:
+ current_editor.sig_debug_start.emit()
+ self.run_file(debug=True)
+
+ @Slot()
+ def re_run_file(self):
+ """Re-run last script"""
+ if self.get_option('save_all_before_run'):
+ self.save_all()
+ if self.__last_ec_exec is None:
+ return
+ (fname, wdir, args, interact, debug,
+ python, python_args, current, systerm,
+ post_mortem, clear_namespace) = self.__last_ec_exec
+ if not systerm:
+ self.run_in_current_ipyclient.emit(fname, wdir, args,
+ debug, post_mortem,
+ current, clear_namespace)
+ else:
+ self.main.open_external_console(fname, wdir, args, interact,
+ debug, python, python_args,
+ systerm, post_mortem)
+
+ @Slot()
+ def run_selection(self):
+ """Run selection or current line in external console"""
+ editorstack = self.get_current_editorstack()
+ editorstack.run_selection()
+
+ @Slot()
+ def run_cell(self):
+ """Run current cell"""
+ editorstack = self.get_current_editorstack()
+ editorstack.run_cell()
+
+ @Slot()
+ def run_cell_and_advance(self):
+ """Run current cell and advance to the next one"""
+ editorstack = self.get_current_editorstack()
+ editorstack.run_cell_and_advance()
+
+ @Slot()
+ def re_run_last_cell(self):
+ """Run last executed cell."""
+ editorstack = self.get_current_editorstack()
+ editorstack.re_run_last_cell()
+
+ # ------ Code bookmarks
+ @Slot(int)
+ def save_bookmark(self, slot_num):
+ """Save current line and position as bookmark."""
+ bookmarks = CONF.get('editor', 'bookmarks')
+ editorstack = self.get_current_editorstack()
+ if slot_num in bookmarks:
+ filename, line_num, column = bookmarks[slot_num]
+ if osp.isfile(filename):
+ index = editorstack.has_filename(filename)
+ if index is not None:
+ block = (editorstack.tabs.widget(index).document()
+ .findBlockByNumber(line_num))
+ block.userData().bookmarks.remove((slot_num, column))
+ if editorstack is not None:
+ self.switch_to_plugin()
+ editorstack.set_bookmark(slot_num)
+
+ @Slot(int)
+ def load_bookmark(self, slot_num):
+ """Set cursor to bookmarked file and position."""
+ bookmarks = CONF.get('editor', 'bookmarks')
+ if slot_num in bookmarks:
+ filename, line_num, column = bookmarks[slot_num]
+ else:
+ return
+ if not osp.isfile(filename):
+ self.last_edit_cursor_pos = None
+ return
+ self.load(filename)
+ editor = self.get_current_editor()
+ if line_num < editor.document().lineCount():
+ linelength = len(editor.document()
+ .findBlockByNumber(line_num).text())
+ if column <= linelength:
+ editor.go_to_line(line_num + 1, column)
+ else:
+ # Last column
+ editor.go_to_line(line_num + 1, linelength)
+
+ #------ Zoom in/out/reset
+ def zoom(self, factor):
+ """Zoom in/out/reset"""
+ editor = self.get_current_editorstack().get_current_editor()
+ if factor == 0:
+ font = self.get_plugin_font()
+ editor.set_font(font)
+ else:
+ font = editor.font()
+ size = font.pointSize() + factor
+ if size > 0:
+ font.setPointSize(size)
+ editor.set_font(font)
+ editor.update_tab_stop_width_spaces()
+
+ #------ Options
+ def apply_plugin_settings(self, options):
+ """Apply configuration file's plugin settings"""
+ if self.editorstacks is not None:
+ # --- syntax highlight and text rendering settings
+ color_scheme_n = 'color_scheme_name'
+ color_scheme_o = self.get_color_scheme()
+ currentline_n = 'highlight_current_line'
+ currentline_o = self.get_option(currentline_n)
+ currentcell_n = 'highlight_current_cell'
+ currentcell_o = self.get_option(currentcell_n)
+ occurrence_n = 'occurrence_highlighting'
+ occurrence_o = self.get_option(occurrence_n)
+ occurrence_timeout_n = 'occurrence_highlighting/timeout'
+ occurrence_timeout_o = self.get_option(occurrence_timeout_n)
+ focus_to_editor_n = 'focus_to_editor'
+ focus_to_editor_o = self.get_option(focus_to_editor_n)
+
+ for editorstack in self.editorstacks:
+ if color_scheme_n in options:
+ editorstack.set_color_scheme(color_scheme_o)
+ if currentline_n in options:
+ editorstack.set_highlight_current_line_enabled(
+ currentline_o)
+ if currentcell_n in options:
+ editorstack.set_highlight_current_cell_enabled(
+ currentcell_o)
+ if occurrence_n in options:
+ editorstack.set_occurrence_highlighting_enabled(occurrence_o)
+ if occurrence_timeout_n in options:
+ editorstack.set_occurrence_highlighting_timeout(
+ occurrence_timeout_o)
+ if focus_to_editor_n in options:
+ editorstack.set_focus_to_editor(focus_to_editor_o)
+
+ # --- everything else
+ tabbar_n = 'show_tab_bar'
+ tabbar_o = self.get_option(tabbar_n)
+ classfuncdropdown_n = 'show_class_func_dropdown'
+ classfuncdropdown_o = self.get_option(classfuncdropdown_n)
+ linenb_n = 'line_numbers'
+ linenb_o = self.get_option(linenb_n)
+ blanks_n = 'blank_spaces'
+ blanks_o = self.get_option(blanks_n)
+ scrollpastend_n = 'scroll_past_end'
+ scrollpastend_o = self.get_option(scrollpastend_n)
+ edgeline_n = 'edge_line'
+ edgeline_o = self.get_option(edgeline_n)
+ edgelinecols_n = 'edge_line_columns'
+ edgelinecols_o = self.get_option(edgelinecols_n)
+ wrap_n = 'wrap'
+ wrap_o = self.get_option(wrap_n)
+ indentguides_n = 'indent_guides'
+ indentguides_o = self.get_option(indentguides_n)
+ tabindent_n = 'tab_always_indent'
+ tabindent_o = self.get_option(tabindent_n)
+ stripindent_n = 'strip_trailing_spaces_on_modify'
+ stripindent_o = self.get_option(stripindent_n)
+ ibackspace_n = 'intelligent_backspace'
+ ibackspace_o = self.get_option(ibackspace_n)
+ removetrail_n = 'always_remove_trailing_spaces'
+ removetrail_o = self.get_option(removetrail_n)
+ converteol_n = 'convert_eol_on_save'
+ converteol_o = self.get_option(converteol_n)
+ converteolto_n = 'convert_eol_on_save_to'
+ converteolto_o = self.get_option(converteolto_n)
+ runcellcopy_n = 'run_cell_copy'
+ runcellcopy_o = self.get_option(runcellcopy_n)
+ closepar_n = 'close_parentheses'
+ closepar_o = self.get_option(closepar_n)
+ close_quotes_n = 'close_quotes'
+ close_quotes_o = self.get_option(close_quotes_n)
+ add_colons_n = 'add_colons'
+ add_colons_o = self.get_option(add_colons_n)
+ autounindent_n = 'auto_unindent'
+ autounindent_o = self.get_option(autounindent_n)
+ indent_chars_n = 'indent_chars'
+ indent_chars_o = self.get_option(indent_chars_n)
+ tab_stop_width_spaces_n = 'tab_stop_width_spaces'
+ tab_stop_width_spaces_o = self.get_option(tab_stop_width_spaces_n)
+ help_n = 'connect_to_oi'
+ help_o = CONF.get('help', 'connect/editor')
+ todo_n = 'todo_list'
+ todo_o = self.get_option(todo_n)
+
+ finfo = self.get_current_finfo()
+
+
+ for editorstack in self.editorstacks:
+ if tabbar_n in options:
+ editorstack.set_tabbar_visible(tabbar_o)
+ if linenb_n in options:
+ editorstack.set_linenumbers_enabled(linenb_o,
+ current_finfo=finfo)
+ if edgeline_n in options:
+ editorstack.set_edgeline_enabled(edgeline_o)
+ if edgelinecols_n in options:
+ editorstack.set_edgeline_columns(edgelinecols_o)
+ if wrap_n in options:
+ editorstack.set_wrap_enabled(wrap_o)
+ if tabindent_n in options:
+ editorstack.set_tabmode_enabled(tabindent_o)
+ if stripindent_n in options:
+ editorstack.set_stripmode_enabled(stripindent_o)
+ if ibackspace_n in options:
+ editorstack.set_intelligent_backspace_enabled(ibackspace_o)
+ if removetrail_n in options:
+ editorstack.set_always_remove_trailing_spaces(removetrail_o)
+ if converteol_n in options:
+ editorstack.set_convert_eol_on_save(converteol_o)
+ if converteolto_n in options:
+ editorstack.set_convert_eol_on_save_to(converteolto_o)
+ if runcellcopy_n in options:
+ editorstack.set_run_cell_copy(runcellcopy_o)
+ if closepar_n in options:
+ editorstack.set_close_parentheses_enabled(closepar_o)
+ if close_quotes_n in options:
+ editorstack.set_close_quotes_enabled(close_quotes_o)
+ if add_colons_n in options:
+ editorstack.set_add_colons_enabled(add_colons_o)
+ if autounindent_n in options:
+ editorstack.set_auto_unindent_enabled(autounindent_o)
+ if indent_chars_n in options:
+ editorstack.set_indent_chars(indent_chars_o)
+ if tab_stop_width_spaces_n in options:
+ editorstack.set_tab_stop_width_spaces(tab_stop_width_spaces_o)
+ if help_n in options:
+ editorstack.set_help_enabled(help_o)
+ if todo_n in options:
+ editorstack.set_todolist_enabled(todo_o,
+ current_finfo=finfo)
+
+ for name, action in self.checkable_actions.items():
+ if name in options:
+ state = self.get_option(name)
+ action.setChecked(state)
+ action.trigger()
+
+ # Multiply by 1000 to convert seconds to milliseconds
+ self.autosave.interval = (
+ self.get_option('autosave_interval') * 1000)
+ self.autosave.enabled = self.get_option('autosave_enabled')
+
+ # We must update the current editor after the others:
+ # (otherwise, code analysis buttons state would correspond to the
+ # last editor instead of showing the one of the current editor)
+ if finfo is not None:
+ # TODO: Connect this to the LSP
+ if todo_n in options and todo_o:
+ finfo.run_todo_finder()
+
+ # --- Open files
+ def get_open_filenames(self):
+ """Get the list of open files in the current stack"""
+ editorstack = self.editorstacks[0]
+ filenames = []
+ filenames += [finfo.filename for finfo in editorstack.data]
+ return filenames
+
+ def set_open_filenames(self):
+ """
+ Set the recent opened files on editor based on active project.
+
+ If no project is active, then editor filenames are saved, otherwise
+ the opened filenames are stored in the project config info.
+ """
+ if self.projects is not None:
+ if not self.projects.get_active_project():
+ filenames = self.get_open_filenames()
+ self.set_option('filenames', filenames)
+
+ def setup_open_files(self):
+ """
+ Open the list of saved files per project.
+
+ Also open any files that the user selected in the recovery dialog.
+ """
+ self.set_create_new_file_if_empty(False)
+ active_project_path = None
+ if self.projects is not None:
+ active_project_path = self.projects.get_active_project_path()
+
+ if active_project_path:
+ filenames = self.projects.get_project_filenames()
+ else:
+ filenames = self.get_option('filenames', default=[])
+ self.close_all_files()
+
+ all_filenames = self.autosave.recover_files_to_open + filenames
+ if all_filenames and any([osp.isfile(f) for f in all_filenames]):
+ layout = self.get_option('layout_settings', None)
+ # Check if no saved layout settings exist, e.g. clean prefs file
+ # If not, load with default focus/layout, to fix issue #8458 .
+ if layout:
+ is_vertical, cfname, clines = layout.get('splitsettings')[0]
+ if cfname in filenames:
+ index = filenames.index(cfname)
+ # First we load the last focused file.
+ self.load(filenames[index], goto=clines[index], set_focus=True)
+ # Then we load the files located to the left of the last
+ # focused file in the tabbar, while keeping the focus on
+ # the last focused file.
+ if index > 0:
+ self.load(filenames[index::-1], goto=clines[index::-1],
+ set_focus=False, add_where='start')
+ # Then we load the files located to the right of the last
+ # focused file in the tabbar, while keeping the focus on
+ # the last focused file.
+ if index < (len(filenames) - 1):
+ self.load(filenames[index+1:], goto=clines[index:],
+ set_focus=False, add_where='end')
+ # Finally we load any recovered files at the end of the tabbar,
+ # while keeping focus on the last focused file.
+ if self.autosave.recover_files_to_open:
+ self.load(self.autosave.recover_files_to_open,
+ set_focus=False, add_where='end')
+ else:
+ if filenames:
+ self.load(filenames, goto=clines)
+ if self.autosave.recover_files_to_open:
+ self.load(self.autosave.recover_files_to_open)
+ else:
+ if filenames:
+ self.load(filenames)
+ if self.autosave.recover_files_to_open:
+ self.load(self.autosave.recover_files_to_open)
+
+ if self.__first_open_files_setup:
+ self.__first_open_files_setup = False
+ if layout is not None:
+ self.editorsplitter.set_layout_settings(
+ layout,
+ dont_goto=filenames[0])
+ win_layout = self.get_option('windows_layout_settings', [])
+ if win_layout:
+ for layout_settings in win_layout:
+ self.editorwindows_to_be_created.append(
+ layout_settings)
+ self.set_last_focus_editorstack(self, self.editorstacks[0])
+ else:
+ self.__load_temp_file()
+ self.set_create_new_file_if_empty(True)
+
+ def save_open_files(self):
+ """Save the list of open files"""
+ self.set_option('filenames', self.get_open_filenames())
+
+ def set_create_new_file_if_empty(self, value):
+ """Change the value of create_new_file_if_empty"""
+ for editorstack in self.editorstacks:
+ editorstack.create_new_file_if_empty = value
+
+ # --- File Menu actions (Mac only)
+ @Slot()
+ def go_to_next_file(self):
+ """Switch to next file tab on the current editor stack."""
+ editorstack = self.get_current_editorstack()
+ editorstack.tabs.tab_navigate(+1)
+
+ @Slot()
+ def go_to_previous_file(self):
+ """Switch to previous file tab on the current editor stack."""
+ editorstack = self.get_current_editorstack()
+ editorstack.tabs.tab_navigate(-1)
diff --git a/spyder/plugins/editor/tests/__init__.py b/spyder/plugins/editor/tests/__init__.py
new file mode 100644
index 00000000000..f859085cb3b
--- /dev/null
+++ b/spyder/plugins/editor/tests/__init__.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) Spyder Project Contributors
+#
+# Licensed under the terms of the MIT License
+# (see LICENSE.txt for details)
+# -----------------------------------------------------------------------------
+
+"""Tests for the Editor plugin."""
diff --git a/spyder/plugins/editor/tests/conftest.py b/spyder/plugins/editor/tests/conftest.py
new file mode 100644
index 00000000000..514cf39db63
--- /dev/null
+++ b/spyder/plugins/editor/tests/conftest.py
@@ -0,0 +1,120 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+"""Fixtures for the Editor plugin tests."""
+
+import os.path as osp
+try:
+ from unittest.mock import MagicMock, Mock
+except ImportError:
+ from mock import MagicMock, Mock # Python 2
+
+# This is needed to avoid an error because QtAwesome
+# needs a QApplication to work correctly.
+from spyder.utils.qthelpers import qapplication
+app = qapplication()
+
+from qtpy.QtWidgets import QMainWindow
+import pytest
+
+from spyder.config.main import CONF
+from spyder.plugins.editor.plugin import Editor
+
+
+@pytest.fixture
+def mock_RecoveryDialog(monkeypatch):
+ """Mock the RecoveryDialog in the editor plugin."""
+ mock = MagicMock()
+ monkeypatch.setattr('spyder.plugins.editor.utils.autosave.RecoveryDialog',
+ mock)
+ return mock
+
+
+@pytest.fixture
+def editor_plugin(qtbot, monkeypatch):
+ """Set up the Editor plugin."""
+ monkeypatch.setattr('spyder.plugins.editor.plugin.add_actions', Mock())
+
+ class MainMock(QMainWindow):
+ def __getattr__(self, attr):
+ if attr.endswith('actions'):
+ return []
+ elif attr == 'projects':
+ projects = Mock()
+ projects.get_active_project.return_value = None
+ return projects
+ else:
+ return Mock()
+
+ def get_spyder_pythonpath(*args):
+ return []
+
+ window = MainMock()
+ editor = Editor(window)
+ window.setCentralWidget(editor)
+ window.resize(640, 480)
+ qtbot.addWidget(window)
+ window.show()
+
+ yield editor
+ editor.close()
+
+ CONF.remove_option('editor', 'autosave_mapping')
+
+
+@pytest.fixture(scope="module")
+def python_files(tmpdir_factory):
+ """Create and save some python codes in temporary files."""
+ tmpdir = tmpdir_factory.mktemp("files")
+ tmpdir = osp.normcase(tmpdir.strpath)
+
+ filenames = [osp.join(tmpdir, f) for f in
+ ('file1.py', 'file2.py', 'file3.py', 'file4.py')]
+ for filename in filenames:
+ with open(filename, 'w') as f:
+ f.write("# -*- coding: utf-8 -*-\n"
+ "print(Hello World!)\n")
+
+ return filenames, tmpdir
+
+
+@pytest.fixture
+def editor_plugin_open_files(request, editor_plugin, python_files):
+ """
+ Setup an Editor with a set of open files, given a past file in focus.
+
+ If no/None ``last_focused_filename`` is passed, the ``"layout_settings"``
+ key is not included in the options dict.
+ If no/None ``expected_current_filename``, is assumed to be the first file.
+ """
+ def _get_editor_open_files(last_focused_filename,
+ expected_current_filename):
+ editor = editor_plugin
+ expected_filenames, tmpdir = python_files
+ if expected_current_filename is None:
+ expected_current_filename = expected_filenames[0]
+ expected_current_filename = osp.join(tmpdir, expected_current_filename)
+ options_dict = {
+ 'filenames': expected_filenames,
+ 'max_recent_files': 20,
+ }
+ if last_focused_filename is not None:
+ splitsettings = [(False,
+ osp.join(tmpdir, last_focused_filename),
+ [1] * len(expected_filenames))]
+ layout_dict = {'layout_settings': {'splitsettings': splitsettings}}
+ options_dict.update(layout_dict)
+
+ def get_option(option, default=None):
+ return options_dict.get(option)
+ editor.get_option = get_option
+
+ editor.setup_open_files()
+ return editor, expected_filenames, expected_current_filename
+
+ return _get_editor_open_files
diff --git a/spyder/plugins/editor/tests/test_plugin.py b/spyder/plugins/editor/tests/test_plugin.py
new file mode 100644
index 00000000000..b0bc0bca9ca
--- /dev/null
+++ b/spyder/plugins/editor/tests/test_plugin.py
@@ -0,0 +1,193 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+"""Tests for the Editor plugin."""
+
+# Standard library imports
+import os.path as osp
+import shutil
+
+# Third party imports
+import pytest
+
+# Local imports
+from spyder.plugins.editor.utils.autosave import AutosaveForPlugin
+
+
+# =============================================================================
+# ---- Tests
+# =============================================================================
+def test_basic_initialization(editor_plugin):
+ """Test Editor plugin initialization."""
+ editor = editor_plugin
+
+ # Assert that editor exists
+ assert editor is not None
+
+
+@pytest.mark.parametrize(
+ 'last_focused_filename, expected_current_filename',
+ [('other_file.py', 'file1.py'),
+ ('file1.py', 'file1.py'),
+ ('file2.py', 'file2.py'),
+ ('file4.py', 'file4.py')
+ ])
+def test_setup_open_files(editor_plugin_open_files, last_focused_filename,
+ expected_current_filename):
+ """Test Editor plugin open files setup.
+
+ Test that the file order is preserved during the Editor plugin setup and
+ that the current file correspond to the last focused file.
+ """
+ editor_factory = editor_plugin_open_files
+ editor, expected_filenames, expected_current_filename = (
+ editor_factory(last_focused_filename, expected_current_filename))
+
+ current_filename = editor.get_current_editorstack().get_current_filename()
+ current_filename = osp.normcase(current_filename)
+ assert current_filename == expected_current_filename
+ filenames = editor.get_current_editorstack().get_filenames()
+ filenames = [osp.normcase(f) for f in filenames]
+ assert filenames == expected_filenames
+
+
+def test_setup_open_files_cleanprefs(editor_plugin_open_files):
+ """Test that Editor successfully opens files if layout is not defined.
+
+ Regression test for #8458 .
+ """
+ editor_factory = editor_plugin_open_files
+ editor, expected_filenames, expected_current_filename = (
+ editor_factory(None, None))
+
+ filenames = editor.get_current_editorstack().get_filenames()
+ filenames = [osp.normcase(f) for f in filenames]
+ assert filenames == expected_filenames
+ current_filename = editor.get_current_editorstack().get_current_filename()
+ current_filename = osp.normcase(current_filename)
+ assert current_filename == expected_current_filename
+
+
+def test_renamed_tree(editor_plugin, mocker):
+ """Test editor.renamed_tree().
+
+ This tests that the file renaming functions are called correctly,
+ but does not test that all the renaming happens in File Explorer,
+ Project Explorer, and Editor widget as those aren't part of the plugin.
+ """
+ editor = editor_plugin
+ mocker.patch.object(editor, 'get_filenames')
+ mocker.patch.object(editor, 'renamed')
+ editor.get_filenames.return_value = ['/test/directory/file1.py',
+ '/test/directory/file2.txt',
+ '/home/spyder/testing/file3.py',
+ '/test/directory/file4.rst']
+
+ editor.renamed_tree('/test/directory', '/test/dir')
+ assert editor.renamed.call_count == 3
+ assert editor.renamed.called_with(source='/test/directory/file1.py',
+ dest='test/dir/file1.py')
+ assert editor.renamed.called_with(source='/test/directory/file2.txt',
+ dest='test/dir/file2.txt')
+ assert editor.renamed.called_with(source='/test/directory/file4.rst',
+ dest='test/dir/file4.rst')
+
+
+def test_no_template(editor_plugin):
+ """
+ Test that new files can be opened when no template is found.
+ """
+ editor = editor_plugin
+
+ # Move template to another file to simulate the lack of it
+ template = editor.TEMPLATE_PATH
+ shutil.move(template, osp.join(osp.dirname(template), 'template.py.old'))
+
+ # Open a new file
+ editor.new()
+
+ # Get contents
+ code_editor = editor.get_focus_widget()
+ contents = code_editor.get_text('sof', 'eof')
+
+ # Assert contents are empty
+ assert not contents
+
+ # Revert template back
+ shutil.move(osp.join(osp.dirname(template), 'template.py.old'), template)
+
+
+def test_editor_has_autosave_component(editor_plugin):
+ """Test that Editor includes an AutosaveForPlugin."""
+ editor = editor_plugin
+ assert isinstance(editor.autosave, AutosaveForPlugin)
+
+
+def test_autosave_component_do_autosave(editor_plugin, mocker):
+ """Test that AutosaveForPlugin's do_autosave() calls the current editor
+ stack's autosave_all()."""
+ editor = editor_plugin
+ editorStack = editor.get_current_editorstack()
+ mocker.patch.object(editorStack.autosave, 'autosave_all')
+ editor.autosave.do_autosave()
+ assert editorStack.autosave.autosave_all.called
+
+
+def test_editor_transmits_sig_option_changed(editor_plugin, qtbot):
+ editor = editor_plugin
+ editorStack = editor.get_current_editorstack()
+ with qtbot.waitSignal(editor.sig_option_changed) as blocker:
+ editorStack.sig_option_changed.emit('autosave_mapping', {1: 2})
+ assert blocker.args == ['autosave_mapping', {1: 2}]
+
+
+def test_editor_sets_autosave_mapping_on_first_editorstack(editor_plugin):
+ """Check that first editor stack gets autosave mapping from config."""
+ editor = editor_plugin
+ editorStack = editor.get_current_editorstack()
+ assert editorStack.autosave_mapping == {}
+
+
+def test_editor_syncs_autosave_mapping_among_editorstacks(editor_plugin, qtbot):
+ """Check that when an editorstack emits a sig_option_changed for
+ autosave_mapping, the autosave mapping of all other editorstacks is
+ updated."""
+ editor = editor_plugin
+ editor.editorsplitter.split()
+ assert len(editor.editorstacks) == 2
+ old_mapping = {}
+ for editorstack in editor.editorstacks:
+ assert editorstack.autosave_mapping == old_mapping
+ new_mapping = {'ham': 'spam'}
+ editor.get_current_editorstack().sig_option_changed.emit(
+ 'autosave_mapping', new_mapping)
+ for editorstack in editor.editorstacks:
+ if editorstack == editor.get_current_editorstack():
+ assert editorstack.autosave_mapping == old_mapping
+ else:
+ assert editorstack.autosave_mapping == new_mapping
+
+
+# The mock_RecoveryDialog fixture needs to be called before setup_editor, so
+# it needs to be mentioned first
+def test_editor_calls_recoverydialog_exec_if_nonempty(
+ mock_RecoveryDialog, editor_plugin):
+ """Check that editor tries to exec a recovery dialog on construction."""
+ editor = editor_plugin
+ assert mock_RecoveryDialog.return_value.exec_if_nonempty.called
+
+
+def test_closing_editor_plugin_stops_autosave_timer(editor_plugin):
+ editor = editor_plugin
+ assert editor.autosave.timer.isActive()
+ editor.closing_plugin()
+ assert not editor.autosave.timer.isActive()
+
+
+if __name__ == "__main__":
+ pytest.main(['-x', osp.basename(__file__), '-vv', '-rw'])
diff --git a/spyder/plugins/editor/utils/__init__.py b/spyder/plugins/editor/utils/__init__.py
new file mode 100644
index 00000000000..f42d1509c3c
--- /dev/null
+++ b/spyder/plugins/editor/utils/__init__.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+spyder.plugins.editor.utils
+===========================
+
+Some utility classes and functions for CodeEditor.
+"""
diff --git a/spyder/plugins/editor/utils/autosave.py b/spyder/plugins/editor/utils/autosave.py
new file mode 100644
index 00000000000..fe586c5dedc
--- /dev/null
+++ b/spyder/plugins/editor/utils/autosave.py
@@ -0,0 +1,252 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Autosave components for the Editor plugin and the EditorStack widget"""
+
+# Standard library imports
+import logging
+import os
+import os.path as osp
+
+# Third party imports
+from qtpy.QtCore import QTimer
+
+# Local imports
+from spyder.config.base import _, get_conf_path
+from spyder.config.main import CONF
+from spyder.plugins.editor.widgets.autosaveerror import AutosaveErrorDialog
+from spyder.plugins.editor.widgets.recover import RecoveryDialog
+
+
+logger = logging.getLogger(__name__)
+
+
+class AutosaveForPlugin(object):
+ """Component of editor plugin implementing autosave functionality."""
+
+ # Interval (in ms) between two autosaves
+ DEFAULT_AUTOSAVE_INTERVAL = 60 * 1000
+
+ def __init__(self, editor):
+ """
+ Constructor.
+
+ Autosave is disabled after construction and needs to be enabled
+ explicitly if required.
+
+ Args:
+ editor (Editor): editor plugin.
+ """
+ self.editor = editor
+ self.timer = QTimer(self.editor)
+ self.timer.setSingleShot(True)
+ self.timer.timeout.connect(self.do_autosave)
+ self._enabled = False # Can't use setter here
+ self._interval = self.DEFAULT_AUTOSAVE_INTERVAL
+
+ @property
+ def enabled(self):
+ """
+ Get or set whether autosave component is enabled.
+
+ The setter will start or stop the autosave component if appropriate.
+ """
+ return self._enabled
+
+ @enabled.setter
+ def enabled(self, new_enabled):
+ if new_enabled == self.enabled:
+ return
+ self.stop_autosave_timer()
+ self._enabled = new_enabled
+ self.start_autosave_timer()
+
+ @property
+ def interval(self):
+ """
+ Interval between two autosaves, in milliseconds.
+
+ The setter will perform an autosave if the interval is changed and
+ autosave is enabled.
+ """
+ return self._interval
+
+ @interval.setter
+ def interval(self, new_interval):
+ if new_interval == self.interval:
+ return
+ self.stop_autosave_timer()
+ self._interval = new_interval
+ if self.enabled:
+ self.do_autosave()
+
+ def start_autosave_timer(self):
+ """
+ Start a timer which calls do_autosave() after `self.interval`.
+
+ The autosave timer is only started if autosave is enabled.
+ """
+ if self.enabled:
+ self.timer.start(self.interval)
+
+ def stop_autosave_timer(self):
+ """Stop the autosave timer."""
+ self.timer.stop()
+
+ def do_autosave(self):
+ """Instruct current editorstack to autosave files where necessary."""
+ logger.debug('Autosave triggered')
+ stack = self.editor.get_current_editorstack()
+ stack.autosave.autosave_all()
+ self.start_autosave_timer()
+
+ def try_recover_from_autosave(self):
+ """Offer to recover files from autosave."""
+ autosave_dir = get_conf_path('autosave')
+ autosave_mapping = CONF.get('editor', 'autosave_mapping', {})
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping,
+ parent=self.editor)
+ dialog.exec_if_nonempty()
+ self.recover_files_to_open = dialog.files_to_open[:]
+
+
+class AutosaveForStack(object):
+ """
+ Component of EditorStack implementing autosave functionality.
+
+ Attributes:
+ stack (EditorStack): editor stack this component belongs to.
+ name_mapping (dict): map between names of opened and autosave files.
+ """
+
+ def __init__(self, editorstack):
+ """
+ Constructor.
+
+ Args:
+ editorstack (EditorStack): editor stack this component belongs to.
+ """
+ self.stack = editorstack
+ self.name_mapping = {}
+
+ def create_unique_autosave_filename(self, filename, autosave_dir):
+ """
+ Create unique autosave file name for specified file name.
+
+ Args:
+ filename (str): original file name
+ autosave_dir (str): directory in which autosave files are stored
+ """
+ basename = osp.basename(filename)
+ autosave_filename = osp.join(autosave_dir, basename)
+ if autosave_filename in self.name_mapping.values():
+ counter = 0
+ root, ext = osp.splitext(basename)
+ while autosave_filename in self.name_mapping.values():
+ counter += 1
+ autosave_basename = '{}-{}{}'.format(root, counter, ext)
+ autosave_filename = osp.join(autosave_dir, autosave_basename)
+ return autosave_filename
+
+ def remove_autosave_file(self, filename, errors='raise'):
+ """
+ Remove autosave file for specified file.
+
+ This function also updates `self.autosave_mapping` and clears the
+ `changed_since_autosave` flag.
+ """
+ if filename not in self.name_mapping:
+ return
+ autosave_filename = self.name_mapping[filename]
+ try:
+ os.remove(autosave_filename)
+ except EnvironmentError as error:
+ error_message = (_('{} while removing autosave file {}')
+ .format(type(error), autosave_filename))
+ if errors == 'ignore':
+ logger.debug('%s : %s', error_message, str(error))
+ else:
+ msgbox = AutosaveErrorDialog(error_message, error)
+ msgbox.exec_if_enabled()
+ del self.name_mapping[filename]
+ self.stack.sig_option_changed.emit(
+ 'autosave_mapping', self.name_mapping)
+ logger.debug('Removed autosave file %s', autosave_filename)
+
+ def remove_all_autosave_files(self, errors='raise'):
+ """
+ Remove all autosave files stored in this componet's mapping.
+
+ Args:
+ errors (str, optional): "raise" (default) or "ignore" errors.
+ """
+ if not self.name_mapping:
+ return
+ for filename in list(self.name_mapping):
+ self.remove_autosave_file(filename, errors=errors)
+
+ def get_autosave_filename(self, filename):
+ """
+ Get name of autosave file for specified file name.
+
+ This function uses the dict in `self.name_mapping`. If `filename` is
+ in the mapping, then return the corresponding autosave file name.
+ Otherwise, construct a unique file name and update the mapping.
+
+ Args:
+ filename (str): original file name
+ """
+ try:
+ autosave_filename = self.name_mapping[filename]
+ except KeyError:
+ autosave_dir = get_conf_path('autosave')
+ if not osp.isdir(autosave_dir):
+ try:
+ os.mkdir(autosave_dir)
+ except EnvironmentError as error:
+ action = _('Error while creating autosave directory')
+ msgbox = AutosaveErrorDialog(action, error)
+ msgbox.exec_if_enabled()
+ autosave_filename = self.create_unique_autosave_filename(
+ filename, autosave_dir)
+ self.name_mapping[filename] = autosave_filename
+ self.stack.sig_option_changed.emit(
+ 'autosave_mapping', self.name_mapping)
+ logger.debug('New autosave file name')
+ return autosave_filename
+
+ def autosave(self, index):
+ """
+ Autosave a file.
+
+ Do nothing if the `changed_since_autosave` flag is not set or the file
+ is newly created (and thus not named by the user). Otherwise, save a
+ copy of the file with the name given by `self.get_autosave_filename()`
+ and clear the `changed_since_autosave` flag. Errors raised when saving
+ are silently ignored.
+
+ Args:
+ index (int): index into self.stack.data
+ """
+ finfo = self.stack.data[index]
+ document = finfo.editor.document()
+ if not document.changed_since_autosave or finfo.newly_created:
+ return
+ autosave_filename = self.get_autosave_filename(finfo.filename)
+ logger.debug('Autosaving %s to %s', finfo.filename, autosave_filename)
+ try:
+ self.stack._write_to_file(finfo, autosave_filename)
+ document.changed_since_autosave = False
+ except EnvironmentError as error:
+ action = (_('Error while autosaving {} to {}')
+ .format(finfo.filename, autosave_filename))
+ msgbox = AutosaveErrorDialog(action, error)
+ msgbox.exec_if_enabled()
+
+ def autosave_all(self):
+ """Autosave all opened files."""
+ for index in range(self.stack.get_stack_count()):
+ self.autosave(index)
diff --git a/spyder/plugins/editor/utils/bookmarks.py b/spyder/plugins/editor/utils/bookmarks.py
new file mode 100644
index 00000000000..390526cab02
--- /dev/null
+++ b/spyder/plugins/editor/utils/bookmarks.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+Contains the bookmarsks utilities.
+"""
+# Standard imports
+import os.path as osp
+
+# Local imports
+from spyder.config.main import CONF
+
+
+def _load_all_bookmarks():
+ """Load all bookmarks from config."""
+ slots = CONF.get('editor', 'bookmarks', {})
+ for slot_num in list(slots.keys()):
+ if not osp.isfile(slots[slot_num][0]):
+ slots.pop(slot_num)
+ return slots
+
+
+def load_bookmarks(filename):
+ """Load all bookmarks for a specific file from config."""
+ bookmarks = _load_all_bookmarks()
+ return {k: v for k, v in bookmarks.items() if v[0] == filename}
+
+
+def load_bookmarks_without_file(filename):
+ """Load all bookmarks but those from a specific file."""
+ bookmarks = _load_all_bookmarks()
+ return {k: v for k, v in bookmarks.items() if v[0] != filename}
+
+
+def save_bookmarks(filename, bookmarks):
+ """Save all bookmarks from specific file to config."""
+ if not osp.isfile(filename):
+ return
+ slots = load_bookmarks_without_file(filename)
+ for slot_num, content in bookmarks.items():
+ slots[slot_num] = [filename, content[0], content[1]]
+ CONF.set('editor', 'bookmarks', slots)
diff --git a/spyder/plugins/editor/utils/debugger.py b/spyder/plugins/editor/utils/debugger.py
new file mode 100644
index 00000000000..f709c266be7
--- /dev/null
+++ b/spyder/plugins/editor/utils/debugger.py
@@ -0,0 +1,165 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+Contains the text debugger manager.
+"""
+import os.path as osp
+
+from qtpy.QtWidgets import QInputDialog, QLineEdit
+
+from spyder.config.main import CONF
+from spyder.config.base import _
+from spyder.py3compat import to_text_string
+from spyder.api.manager import Manager
+from spyder.plugins.editor.utils.editor import BlockUserData
+
+
+def _load_all_breakpoints():
+ bp_dict = CONF.get('run', 'breakpoints', {})
+ for filename in list(bp_dict.keys()):
+ if not osp.isfile(filename):
+ bp_dict.pop(filename)
+ return bp_dict
+
+
+def load_breakpoints(filename):
+ breakpoints = _load_all_breakpoints().get(filename, [])
+ if breakpoints and isinstance(breakpoints[0], int):
+ # Old breakpoints format
+ breakpoints = [(lineno, None) for lineno in breakpoints]
+ return breakpoints
+
+
+def save_breakpoints(filename, breakpoints):
+ if not osp.isfile(filename):
+ return
+ bp_dict = _load_all_breakpoints()
+ bp_dict[filename] = breakpoints
+ CONF.set('run', 'breakpoints', bp_dict)
+
+
+def clear_all_breakpoints():
+ CONF.set('run', 'breakpoints', {})
+
+
+def clear_breakpoint(filename, lineno):
+ breakpoints = load_breakpoints(filename)
+ if breakpoints:
+ for breakpoint in breakpoints[:]:
+ if breakpoint[0] == lineno:
+ breakpoints.remove(breakpoint)
+ save_breakpoints(filename, breakpoints)
+
+
+class DebuggerManager(Manager):
+ """
+ Manages adding/removing breakpoint from the editor.
+ """
+ def __init__(self, editor):
+ super(DebuggerManager, self).__init__(editor)
+ self.filename = None
+ self.breakpoints = self.get_breakpoints()
+ self.editor.sig_breakpoints_changed.connect(self.breakpoints_changed)
+ self.editor.sig_filename_changed.connect(self.set_filename)
+
+ def set_filename(self, filename):
+ if filename is None:
+ return
+ if self.filename != filename:
+ old_filename = self.filename
+ self.filename = filename
+ if self.breakpoints:
+ save_breakpoints(old_filename, []) # clear old breakpoints
+ self.save_breakpoints()
+
+ def toogle_breakpoint(self, line_number=None, condition=None,
+ edit_condition=False):
+ """Add/remove breakpoint."""
+ if not self.editor.is_python_like():
+ return
+ if line_number is None:
+ block = self.editor.textCursor().block()
+ else:
+ block = self.editor.document().findBlockByNumber(line_number-1)
+ data = block.userData()
+ if not data:
+ data = BlockUserData(self.editor)
+ data.breakpoint = True
+ elif not edit_condition:
+ data.breakpoint = not data.breakpoint
+ data.breakpoint_condition = None
+ if condition is not None:
+ data.breakpoint_condition = condition
+ if edit_condition:
+ condition = data.breakpoint_condition
+ condition, valid = QInputDialog.getText(self.editor,
+ _('Breakpoint'),
+ _("Condition:"),
+ QLineEdit.Normal,
+ condition)
+ if not valid:
+ return
+ data.breakpoint = True
+ data.breakpoint_condition = str(condition) if condition else None
+ if data.breakpoint:
+ text = to_text_string(block.text()).strip()
+ if len(text) == 0 or text.startswith(('#', '"', "'")):
+ data.breakpoint = False
+ block.setUserData(data)
+ self.editor.sig_flags_changed.emit()
+ self.editor.sig_breakpoints_changed.emit()
+
+ def get_breakpoints(self):
+ """Get breakpoints"""
+ breakpoints = []
+ block = self.editor.document().firstBlock()
+ for line_number in range(1, self.editor.document().blockCount()+1):
+ data = block.userData()
+ if data and data.breakpoint:
+ breakpoints.append((line_number, data.breakpoint_condition))
+ block = block.next()
+ return breakpoints
+
+ def clear_breakpoints(self):
+ """Clear breakpoints"""
+ self.breakpoints = []
+ for data in self.editor.blockuserdata_list():
+ data.breakpoint = False
+ # data.breakpoint_condition = None # not necessary, but logical
+
+ def set_breakpoints(self, breakpoints):
+ """Set breakpoints"""
+ self.clear_breakpoints()
+ for line_number, condition in breakpoints:
+ self.toogle_breakpoint(line_number, condition)
+ self.breakpoints = self.get_breakpoints()
+
+ def update_breakpoints(self):
+ """Update breakpoints"""
+ self.editor.sig_breakpoints_changed.emit()
+
+ def breakpoints_changed(self):
+ """Breakpoint list has changed"""
+ breakpoints = self.get_breakpoints()
+ if self.breakpoints != breakpoints:
+ self.breakpoints = breakpoints
+ self.save_breakpoints()
+
+ def save_breakpoints(self):
+ breakpoints = repr(self.breakpoints)
+ filename = to_text_string(self.filename)
+ breakpoints = to_text_string(breakpoints)
+ filename = osp.normpath(osp.abspath(filename))
+ if breakpoints:
+ breakpoints = eval(breakpoints)
+ else:
+ breakpoints = []
+ save_breakpoints(filename, breakpoints)
+ self.editor.sig_breakpoints_saved.emit()
+
+ def load_breakpoints(self):
+ self.set_breakpoints(load_breakpoints(self.filename))
diff --git a/spyder/plugins/editor/utils/decoration.py b/spyder/plugins/editor/utils/decoration.py
new file mode 100644
index 00000000000..174ce5e6c6a
--- /dev/null
+++ b/spyder/plugins/editor/utils/decoration.py
@@ -0,0 +1,122 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2013-2016 Colin Duquesnoy and others (see pyqode/AUTHORS.rst)
+# Copyright (c) 2016- Spyder Project Contributors (see AUTHORS.txt)
+#
+# Distributed under the terms of the MIT License
+# (see NOTICE.txt in the Spyder root directory for details)
+# -----------------------------------------------------------------------------
+
+"""
+Contains the text decorations manager.
+
+Adapted from pyqode/core/managers/decorations.py of the
+`PyQode project `_.
+Original file:
+
+"""
+
+# Third party imports
+from qtpy.QtGui import QTextCharFormat
+
+# Local imports
+from spyder.api.manager import Manager
+
+
+class TextDecorationsManager(Manager):
+ """
+ Manages the collection of TextDecoration that have been set on the editor
+ widget.
+ """
+ def __init__(self, editor):
+ super(TextDecorationsManager, self).__init__(editor)
+ self._decorations = []
+
+ def add(self, decorations):
+ """
+ Add text decorations on a CodeEditor instance.
+
+ Don't add duplicated decorations, and order decorations according
+ draw_order and the size of the selection.
+
+ Args:
+ decorations (sourcecode.api.TextDecoration) (could be a list)
+ Returns:
+ int: Amount of decorations added.
+ """
+ added = 0
+ if isinstance(decorations, list):
+ not_repeated = set(decorations) - set(self._decorations)
+ self._decorations.extend(list(not_repeated))
+ added = len(not_repeated)
+ elif decorations not in self._decorations:
+ self._decorations.append(decorations)
+ added = 1
+
+ if added > 0:
+ self._order_decorations()
+ self.update()
+ return added
+
+ def remove(self, decoration):
+ """
+ Removes a text decoration from the editor.
+
+ :param decoration: Text decoration to remove
+ :type decoration: spyder.api.TextDecoration
+ """
+ try:
+ self._decorations.remove(decoration)
+ self.update()
+ return True
+ except ValueError:
+ return False
+ except RuntimeError:
+ # This is needed to fix issue 9173
+ pass
+
+ def clear(self):
+ """Removes all text decoration from the editor."""
+ self._decorations[:] = []
+ try:
+ self.update()
+ except RuntimeError:
+ pass
+
+ def update(self):
+ """Update editor extra selections with added decorations.
+
+ NOTE: Update TextDecorations to use editor font, using a different
+ font family and point size could cause unwanted behaviors.
+ """
+ font = self.editor.font()
+ for decoration in self._decorations:
+ try:
+ decoration.format.setFont(
+ font, QTextCharFormat.FontPropertiesSpecifiedOnly)
+ except (TypeError, AttributeError): # Qt < 5.3
+ decoration.format.setFontFamily(font.family())
+ decoration.format.setFontPointSize(font.pointSize())
+ self.editor.setExtraSelections(self._decorations)
+
+ def __iter__(self):
+ return iter(self._decorations)
+
+ def __len__(self):
+ return len(self._decorations)
+
+ def _order_decorations(self):
+ """Order decorations according draw_order and size of selection.
+
+ Highest draw_order will appear on top of the lowest values.
+
+ If draw_order is equal,smaller selections are draw in top of
+ bigger selections.
+ """
+ def order_function(sel):
+ end = sel.cursor.selectionEnd()
+ start = sel.cursor.selectionStart()
+ return sel.draw_order, -(end - start)
+
+ self._decorations = sorted(self._decorations,
+ key=order_function)
diff --git a/spyder/plugins/editor/utils/editor.py b/spyder/plugins/editor/utils/editor.py
new file mode 100644
index 00000000000..732d3dc72a1
--- /dev/null
+++ b/spyder/plugins/editor/utils/editor.py
@@ -0,0 +1,1124 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2013-2016 Colin Duquesnoy and others (see pyqode/AUTHORS.rst)
+# Copyright (c) 2016- Spyder Project Contributors (see AUTHORS.txt)
+#
+# Distributed under the terms of the MIT License
+# (see NOTICE.txt in the Spyder root directory for details)
+# -----------------------------------------------------------------------------
+
+"""
+This module contains utility functions/classes for Spyder's Editor.
+
+Adapted from pyqode/core/api/utils.py of the
+`PyQode project `_.
+Original file:
+
+"""
+
+# Standard library imports
+import functools
+import weakref
+
+# Third party imports
+from qtpy.QtCore import QTimer, Qt
+from qtpy.QtGui import (QColor, QTextBlockUserData, QTextCursor, QTextBlock,
+ QTextDocument, QCursor)
+from qtpy.QtWidgets import QApplication
+
+# Local imports
+from spyder.py3compat import to_text_string
+
+
+def drift_color(base_color, factor=110):
+ """
+ Return color that is lighter or darker than the base color.
+
+ If base_color.lightness is higher than 128, the returned color is darker
+ otherwise is is lighter.
+
+ :param base_color: The base color to drift from
+ ;:param factor: drift factor (%)
+ :return A lighter or darker color.
+ """
+ base_color = QColor(base_color)
+ if base_color.lightness() > 128:
+ return base_color.darker(factor)
+ else:
+ if base_color == QColor('#000000'):
+ return drift_color(QColor('#101010'), factor + 20)
+ else:
+ return base_color.lighter(factor + 10)
+
+
+class BlockUserData(QTextBlockUserData):
+ def __init__(self, editor, cursor=None, color=None):
+ QTextBlockUserData.__init__(self)
+ self.editor = editor
+ self.breakpoint = False
+ self.breakpoint_condition = None
+ self.bookmarks = []
+ self.code_analysis = []
+ self.todo = ''
+ self.selection = cursor
+ self.color = color
+ self.oedata = None
+ self.import_statement = None
+
+ # Add a reference to the user data in the editor as the block won't.
+ # The list should /not/ be used to list BlockUserData as the blocks
+ # they refer to might not exist anymore.
+ # This prevent a segmentation fault.
+ if editor is None:
+ # Won't be destroyed
+ self.refloop = self
+ return
+ # Destroy with the editor
+ if not hasattr(editor, '_user_data_reference_list'):
+ editor._user_data_reference_list = []
+ editor._user_data_reference_list.append(self)
+
+
+class DelayJobRunner(object):
+ """
+ Utility class for running job after a certain delay.
+ If a new request is made during this delay, the previous request is dropped
+ and the timer is restarted for the new request.
+
+ We use this to implement a cooldown effect that prevents jobs from being
+ executed while the IDE is not idle.
+
+ A job is a simple callable.
+ """
+ def __init__(self, delay=500):
+ """
+ :param delay: Delay to wait before running the job. This delay applies
+ to all requests and cannot be changed afterwards.
+ """
+ self._timer = QTimer()
+ self.delay = delay
+ self._timer.timeout.connect(self._exec_requested_job)
+ self._args = []
+ self._kwargs = {}
+ self._job = lambda x: None
+
+ def request_job(self, job, *args, **kwargs):
+ """
+ Request a job execution.
+
+ The job will be executed after the delay specified in the
+ DelayJobRunner contructor elapsed if no other job is requested until
+ then.
+
+ :param job: job.
+ :type job: callable
+ :param args: job's position arguments
+ :param kwargs: job's keyworded arguments
+ """
+ self.cancel_requests()
+ self._job = job
+ self._args = args
+ self._kwargs = kwargs
+ self._timer.start(self.delay)
+
+ def cancel_requests(self):
+ """Cancels pending requests."""
+ self._timer.stop()
+ self._job = None
+ self._args = None
+ self._kwargs = None
+
+ def _exec_requested_job(self):
+ """Execute the requested job after the timer has timeout."""
+ self._timer.stop()
+ self._job(*self._args, **self._kwargs)
+
+
+class TextHelper(object):
+ """
+ Text helper helps you manipulate the content of CodeEditor and extends the
+ Qt text api for an easier usage.
+
+ FIXME: Some of this methods are already implemented in CodeEditor, move
+ and unify redundant methods.
+ """
+ @property
+ def _editor(self):
+ try:
+ return self._editor_ref()
+ except TypeError:
+ return self._editor_ref
+
+ def __init__(self, editor):
+ """:param editor: The editor to work on."""
+ try:
+ self._editor_ref = weakref.ref(editor)
+ except TypeError:
+ self._editor_ref = editor
+
+ def goto_line(self, line, column=0, end_column=0, move=True, word=''):
+ """
+ Moves the text cursor to the specified position.
+
+ :param line: Number of the line to go to (0 based)
+ :param column: Optional column number. Default is 0 (start of line).
+ :param move: True to move the cursor. False will return the cursor
+ without setting it on the editor.
+ :param word: Highlight the word, when moving to the line.
+ :return: The new text cursor
+ :rtype: QtGui.QTextCursor
+ """
+ line = min(line, self.line_count())
+ text_cursor = self._move_cursor_to(line)
+ if column:
+ text_cursor.movePosition(text_cursor.Right, text_cursor.MoveAnchor,
+ column)
+ if end_column:
+ text_cursor.movePosition(text_cursor.Right, text_cursor.KeepAnchor,
+ end_column)
+ if move:
+ block = text_cursor.block()
+ self.unfold_if_colapsed(block)
+ self._editor.setTextCursor(text_cursor)
+
+ if self._editor.isVisible():
+ self._editor.centerCursor()
+ else:
+ self._editor.focus_in.connect(
+ self._editor.center_cursor_on_next_focus)
+ if word and to_text_string(word) in to_text_string(block.text()):
+ self._editor.find(word, QTextDocument.FindCaseSensitively)
+ return text_cursor
+
+ def unfold_if_colapsed(self, block):
+ """Unfold parent fold trigger if the block is collapsed.
+
+ :param block: Block to unfold.
+ """
+ try:
+ folding_panel = self._editor.panels.get('FoldingPanel')
+ except KeyError:
+ pass
+ else:
+ from spyder.plugins.editor.utils.folding import FoldScope
+ if not block.isVisible():
+ block = FoldScope.find_parent_scope(block)
+ if TextBlockHelper.is_collapsed(block):
+ folding_panel.toggle_fold_trigger(block)
+
+ def selected_text(self):
+ """Returns the selected text."""
+ return self._editor.textCursor().selectedText()
+
+ def word_under_cursor(self, select_whole_word=False, text_cursor=None):
+ """
+ Gets the word under cursor using the separators defined by
+ :attr:`spyder.plugins.editor.widgets.codeeditor.CodeEditor.word_separators`.
+
+ FIXME: This is not working because CodeEditor have no attribute
+ word_separators
+
+ .. note: Instead of returning the word string, this function returns
+ a QTextCursor, that way you may get more information than just the
+ string. To get the word, just call ``selectedText`` on the returned
+ value.
+
+ :param select_whole_word: If set to true the whole word is selected,
+ else the selection stops at the cursor position.
+ :param text_cursor: Optional custom text cursor (e.g. from a
+ QTextDocument clone)
+ :returns: The QTextCursor that contains the selected word.
+ """
+ editor = self._editor
+ if not text_cursor:
+ text_cursor = editor.textCursor()
+ word_separators = editor.word_separators
+ end_pos = start_pos = text_cursor.position()
+ # select char by char until we are at the original cursor position.
+ while not text_cursor.atStart():
+ text_cursor.movePosition(
+ text_cursor.Left, text_cursor.KeepAnchor, 1)
+ try:
+ char = text_cursor.selectedText()[0]
+ word_separators = editor.word_separators
+ selected_txt = text_cursor.selectedText()
+ if (selected_txt in word_separators and
+ (selected_txt != "n" and selected_txt != "t") or
+ char.isspace()):
+ break # start boundary found
+ except IndexError:
+ break # nothing selectable
+ start_pos = text_cursor.position()
+ text_cursor.setPosition(start_pos)
+ if select_whole_word:
+ # select the resot of the word
+ text_cursor.setPosition(end_pos)
+ while not text_cursor.atEnd():
+ text_cursor.movePosition(text_cursor.Right,
+ text_cursor.KeepAnchor, 1)
+ char = text_cursor.selectedText()[0]
+ selected_txt = text_cursor.selectedText()
+ if (selected_txt in word_separators and
+ (selected_txt != "n" and selected_txt != "t") or
+ char.isspace()):
+ break # end boundary found
+ end_pos = text_cursor.position()
+ text_cursor.setPosition(end_pos)
+ # now that we habe the boundaries, we can select the text
+ text_cursor.setPosition(start_pos)
+ text_cursor.setPosition(end_pos, text_cursor.KeepAnchor)
+ return text_cursor
+
+ def word_under_mouse_cursor(self):
+ """
+ Selects the word under the **mouse** cursor.
+
+ :return: A QTextCursor with the word under mouse cursor selected.
+ """
+ editor = self._editor
+ text_cursor = editor.cursorForPosition(editor._last_mouse_pos)
+ text_cursor = self.word_under_cursor(True, text_cursor)
+ return text_cursor
+
+ def cursor_position(self):
+ """
+ Returns the QTextCursor position. The position is a tuple made up of
+ the line number (0 based) and the column number (0 based).
+
+ :return: tuple(line, column)
+ """
+ return (self._editor.textCursor().blockNumber(),
+ self._editor.textCursor().columnNumber())
+
+ def current_line_nbr(self):
+ """
+ Returns the text cursor's line number.
+
+ :return: Line number
+ """
+ return self.cursor_position()[0]
+
+ def current_column_nbr(self):
+ """
+ Returns the text cursor's column number.
+
+ :return: Column number
+ """
+ return self.cursor_position()[1]
+
+ def line_count(self):
+ """
+ Returns the line count of the specified editor.
+
+ :return: number of lines in the document.
+ """
+ return self._editor.document().blockCount()
+
+ def line_text(self, line_nbr):
+ """
+ Gets the text of the specified line.
+
+ :param line_nbr: The line number of the text to get
+
+ :return: Entire line's text
+ :rtype: str
+ """
+ doc = self._editor.document()
+ block = doc.findBlockByNumber(line_nbr)
+ return block.text()
+
+ def previous_line_text(self):
+ """
+ Gets the previous line text (relative to the current cursor pos).
+ :return: previous line text (str)
+ """
+ if self.current_line_nbr():
+ return self.line_text(self.current_line_nbr() - 1)
+ return ''
+
+ def current_line_text(self):
+ """
+ Returns the text of the current line.
+
+ :return: Text of the current line
+ """
+ return self.line_text(self.current_line_nbr())
+
+ def set_line_text(self, line_nbr, new_text):
+ """
+ Replace an entire line with ``new_text``.
+
+ :param line_nbr: line number of the line to change.
+ :param new_text: The replacement text.
+
+ """
+ editor = self._editor
+ text_cursor = self._move_cursor_to(line_nbr)
+ text_cursor.select(text_cursor.LineUnderCursor)
+ text_cursor.insertText(new_text)
+ editor.setTextCursor(text_cursor)
+
+ def remove_last_line(self):
+ """Removes the last line of the document."""
+ editor = self._editor
+ text_cursor = editor.textCursor()
+ text_cursor.movePosition(text_cursor.End, text_cursor.MoveAnchor)
+ text_cursor.select(text_cursor.LineUnderCursor)
+ text_cursor.removeSelectedText()
+ text_cursor.deletePreviousChar()
+ editor.setTextCursor(text_cursor)
+
+ def clean_document(self):
+ """
+ Removes trailing whitespaces and ensure one single blank line at the
+ end of the QTextDocument.
+
+ FIXME: It was deprecated in pyqode, maybe It should be deleted
+ """
+ editor = self._editor
+ value = editor.verticalScrollBar().value()
+ pos = self.cursor_position()
+ editor.textCursor().beginEditBlock()
+
+ # cleanup whitespaces
+ editor._cleaning = True
+ eaten = 0
+ removed = set()
+ for line in editor._modified_lines:
+ # parse line before and line after modified line (for cases where
+ # key_delete or key_return has been pressed)
+ for j in range(-1, 2):
+ # skip current line
+ if line + j != pos[0]:
+ if line + j >= 0:
+ txt = self.line_text(line + j)
+ stxt = txt.rstrip()
+ if txt != stxt:
+ self.set_line_text(line + j, stxt)
+ removed.add(line + j)
+ editor._modified_lines -= removed
+
+ # ensure there is only one blank line left at the end of the file
+ i = self.line_count()
+ while i:
+ line = self.line_text(i - 1)
+ if line.strip():
+ break
+ self.remove_last_line()
+ i -= 1
+ if self.line_text(self.line_count() - 1):
+ editor.appendPlainText('')
+
+ # restore cursor and scrollbars
+ text_cursor = editor.textCursor()
+ doc = editor.document()
+ assert isinstance(doc, QTextDocument)
+ text_cursor = self._move_cursor_to(pos[0])
+ text_cursor.movePosition(text_cursor.StartOfLine,
+ text_cursor.MoveAnchor)
+ cpos = text_cursor.position()
+ text_cursor.select(text_cursor.LineUnderCursor)
+ if text_cursor.selectedText():
+ text_cursor.setPosition(cpos)
+ offset = pos[1] - eaten
+ text_cursor.movePosition(text_cursor.Right, text_cursor.MoveAnchor,
+ offset)
+ else:
+ text_cursor.setPosition(cpos)
+ editor.setTextCursor(text_cursor)
+ editor.verticalScrollBar().setValue(value)
+
+ text_cursor.endEditBlock()
+ editor._cleaning = False
+
+ def select_whole_line(self, line=None, apply_selection=True):
+ """
+ Selects an entire line.
+
+ :param line: Line to select. If None, the current line will be selected
+ :param apply_selection: True to apply selection on the text editor
+ widget, False to just return the text cursor without setting it
+ on the editor.
+ :return: QTextCursor
+ """
+ if line is None:
+ line = self.current_line_nbr()
+ return self.select_lines(line, line, apply_selection=apply_selection)
+
+ def _move_cursor_to(self, line):
+ cursor = self._editor.textCursor()
+ block = self._editor.document().findBlockByNumber(line-1)
+ cursor.setPosition(block.position())
+ return cursor
+
+ def select_lines(self, start=0, end=-1, apply_selection=True):
+ """
+ Selects entire lines between start and end line numbers.
+
+ This functions apply the selection and returns the text cursor that
+ contains the selection.
+
+ Optionally it is possible to prevent the selection from being applied
+ on the code editor widget by setting ``apply_selection`` to False.
+
+ :param start: Start line number (0 based)
+ :param end: End line number (0 based). Use -1 to select up to the
+ end of the document
+ :param apply_selection: True to apply the selection before returning
+ the QTextCursor.
+ :returns: A QTextCursor that holds the requested selection
+ """
+ editor = self._editor
+ if end == -1:
+ end = self.line_count() - 1
+ if start < 0:
+ start = 0
+ text_cursor = self._move_cursor_to(start)
+ if end > start: # Going down
+ text_cursor.movePosition(text_cursor.Down,
+ text_cursor.KeepAnchor, end - start)
+ text_cursor.movePosition(text_cursor.EndOfLine,
+ text_cursor.KeepAnchor)
+ elif end < start: # going up
+ # don't miss end of line !
+ text_cursor.movePosition(text_cursor.EndOfLine,
+ text_cursor.MoveAnchor)
+ text_cursor.movePosition(text_cursor.Up,
+ text_cursor.KeepAnchor, start - end)
+ text_cursor.movePosition(text_cursor.StartOfLine,
+ text_cursor.KeepAnchor)
+ else:
+ text_cursor.movePosition(text_cursor.EndOfLine,
+ text_cursor.KeepAnchor)
+ if apply_selection:
+ editor.setTextCursor(text_cursor)
+ return text_cursor
+
+ def selection_range(self):
+ """
+ Returns the selected lines boundaries (start line, end line)
+
+ :return: tuple(int, int)
+ """
+ editor = self._editor
+ doc = editor.document()
+ start = doc.findBlock(
+ editor.textCursor().selectionStart()).blockNumber()
+ end = doc.findBlock(
+ editor.textCursor().selectionEnd()).blockNumber()
+ text_cursor = QTextCursor(editor.textCursor())
+ text_cursor.setPosition(editor.textCursor().selectionEnd())
+ if text_cursor.columnNumber() == 0 and start != end:
+ end -= 1
+ return start, end
+
+ def line_pos_from_number(self, line_number):
+ """
+ Computes line position on Y-Axis (at the center of the line) from line
+ number.
+
+ :param line_number: The line number for which we want to know the
+ position in pixels.
+ :return: The center position of the line.
+ """
+ editor = self._editor
+ block = editor.document().findBlockByNumber(line_number)
+ if block.isValid():
+ return int(editor.blockBoundingGeometry(block).translated(
+ editor.contentOffset()).top())
+ if line_number <= 0:
+ return 0
+ else:
+ return int(editor.blockBoundingGeometry(
+ block.previous()).translated(editor.contentOffset()).bottom())
+
+ def line_nbr_from_position(self, y_pos):
+ """
+ Returns the line number from the y_pos.
+
+ :param y_pos: Y pos in the editor
+ :return: Line number (0 based), -1 if out of range
+ """
+ editor = self._editor
+ height = editor.fontMetrics().height()
+ for top, line, block in editor.visible_blocks:
+ if top <= y_pos <= top + height:
+ return line
+ return -1
+
+ def mark_whole_doc_dirty(self):
+ """
+ Marks the whole document as dirty to force a full refresh. **SLOW**
+ """
+ text_cursor = self._editor.textCursor()
+ text_cursor.select(text_cursor.Document)
+ self._editor.document().markContentsDirty(text_cursor.selectionStart(),
+ text_cursor.selectionEnd())
+
+ def line_indent(self, line_nbr=None):
+ """
+ Returns the indent level of the specified line.
+
+ :param line_nbr: Number of the line to get indentation (1 base).
+ Pass None to use the current line number. Note that you can also
+ pass a QTextBlock instance instead of an int.
+ :return: Number of spaces that makes the indentation level of the
+ current line
+ """
+ if line_nbr is None:
+ line_nbr = self.current_line_nbr()
+ elif isinstance(line_nbr, QTextBlock):
+ line_nbr = line_nbr.blockNumber()
+ line = self.line_text(line_nbr)
+ indentation = len(line) - len(line.lstrip())
+ return indentation
+
+ def get_right_word(self, cursor=None):
+ """
+ Gets the character on the right of the text cursor.
+
+ :param cursor: QTextCursor where the search will start.
+
+ :return: The word that is on the right of the text cursor.
+ """
+ if cursor is None:
+ cursor = self._editor.textCursor()
+ cursor.movePosition(QTextCursor.WordRight,
+ QTextCursor.KeepAnchor)
+ return cursor.selectedText().strip()
+
+ def get_right_character(self, cursor=None):
+ """
+ Gets the character that is on the right of the text cursor.
+
+ :param cursor: QTextCursor that defines the position where the search
+ will start.
+ """
+ next_char = self.get_right_word(cursor=cursor)
+ if len(next_char):
+ next_char = next_char[0]
+ else:
+ next_char = None
+ return next_char
+
+ def insert_text(self, text, keep_position=True):
+ """
+ Inserts text at the cursor position.
+
+ :param text: text to insert
+ :param keep_position: Flag that specifies if the cursor position must
+ be kept. Pass False for a regular insert (the cursor will be at
+ the end of the inserted text).
+ """
+ text_cursor = self._editor.textCursor()
+ if keep_position:
+ s = text_cursor.selectionStart()
+ e = text_cursor.selectionEnd()
+ text_cursor.insertText(text)
+ if keep_position:
+ text_cursor.setPosition(s)
+ text_cursor.setPosition(e, text_cursor.KeepAnchor)
+ self._editor.setTextCursor(text_cursor)
+
+ def clear_selection(self):
+ """Clears text cursor selection."""
+ text_cursor = self._editor.textCursor()
+ text_cursor.clearSelection()
+ self._editor.setTextCursor(text_cursor)
+
+ def move_right(self, keep_anchor=False, nb_chars=1):
+ """
+ Moves the cursor on the right.
+
+ :param keep_anchor: True to keep anchor (to select text) or False to
+ move the anchor (no selection)
+ :param nb_chars: Number of characters to move.
+ """
+ text_cursor = self._editor.textCursor()
+ text_cursor.movePosition(
+ text_cursor.Right, text_cursor.KeepAnchor if keep_anchor else
+ text_cursor.MoveAnchor, nb_chars)
+ self._editor.setTextCursor(text_cursor)
+
+ def selected_text_to_lower(self):
+ """Replaces the selected text by its lower version."""
+ txt = self.selected_text()
+ self.insert_text(txt.lower())
+
+ def selected_text_to_upper(self):
+ """Replaces the selected text by its upper version."""
+ txt = self.selected_text()
+ self.insert_text(txt.upper())
+
+ def search_text(self, text_cursor, search_txt, search_flags):
+ """
+ Searches a text in a text document.
+
+ :param text_cursor: Current text cursor
+ :param search_txt: Text to search
+ :param search_flags: QTextDocument.FindFlags
+ :returns: the list of occurrences, the current occurrence index
+ :rtype: tuple([], int)
+
+ """
+ def compare_cursors(cursor_a, cursor_b):
+ """
+ Compares two QTextCursor.
+
+ :param cursor_a: cursor a
+ :param cursor_b: cursor b
+
+ :returns; True if both cursor are identical (same position, same
+ selection)
+ """
+ return (cursor_b.selectionStart() >= cursor_a.selectionStart() and
+ cursor_b.selectionEnd() <= cursor_a.selectionEnd())
+
+ text_document = self._editor.document()
+ occurrences = []
+ index = -1
+ cursor = text_document.find(search_txt, 0, search_flags)
+ original_cursor = text_cursor
+ while not cursor.isNull():
+ if compare_cursors(cursor, original_cursor):
+ index = len(occurrences)
+ occurrences.append((cursor.selectionStart(),
+ cursor.selectionEnd()))
+ cursor.setPosition(cursor.position() + 1)
+ cursor = text_document.find(search_txt, cursor, search_flags)
+ return occurrences, index
+
+ def is_comment_or_string(self, cursor_or_block, formats=None):
+ """
+ Checks if a block/cursor is a string or a comment.
+ :param cursor_or_block: QTextCursor or QTextBlock
+ :param formats: the list of color scheme formats to consider. By
+ default, it will consider the following keys: 'comment', 'string',
+ 'docstring'.
+ """
+ if formats is None:
+ formats = ["comment", "string", "docstring"]
+ layout = None
+ pos = 0
+ if isinstance(cursor_or_block, QTextBlock):
+ pos = len(cursor_or_block.text()) - 1
+ layout = cursor_or_block.layout()
+ elif isinstance(cursor_or_block, QTextCursor):
+ b = cursor_or_block.block()
+ pos = cursor_or_block.position() - b.position()
+ layout = b.layout()
+ if layout is not None:
+ additional_formats = layout.additionalFormats()
+ sh = self._editor.syntax_highlighter
+ if sh:
+ ref_formats = sh.color_scheme.formats
+ for r in additional_formats:
+ if r.start <= pos < (r.start + r.length):
+ for fmt_type in formats:
+ is_user_obj = (r.format.objectType() ==
+ r.format.UserObject)
+ if (ref_formats[fmt_type] == r.format and
+ is_user_obj):
+ return True
+ return False
+
+ def select_extended_word(self, continuation_chars=('.',)):
+ """
+ Performs extended word selection. Extended selection consists in
+ selecting the word under cursor and any other words that are linked
+ by a ``continuation_chars``.
+
+ :param continuation_chars: the list of characters that may extend a
+ word.
+ """
+ cursor = self._editor.textCursor()
+ original_pos = cursor.position()
+ start_pos = None
+ end_pos = None
+ # go left
+ stop = False
+ seps = self._editor.word_separators + [' ']
+ while not stop:
+ cursor.clearSelection()
+ cursor.movePosition(cursor.Left, cursor.KeepAnchor)
+ char = cursor.selectedText()
+ if cursor.atBlockStart():
+ stop = True
+ start_pos = cursor.position()
+ elif char in seps and char not in continuation_chars:
+ stop = True
+ start_pos = cursor.position() + 1
+ # go right
+ cursor.setPosition(original_pos)
+ stop = False
+ while not stop:
+ cursor.clearSelection()
+ cursor.movePosition(cursor.Right, cursor.KeepAnchor)
+ char = cursor.selectedText()
+ if cursor.atBlockEnd():
+ stop = True
+ end_pos = cursor.position()
+ if char in seps:
+ end_pos -= 1
+ elif char in seps and char not in continuation_chars:
+ stop = True
+ end_pos = cursor.position() - 1
+ if start_pos and end_pos:
+ cursor.setPosition(start_pos)
+ cursor.movePosition(cursor.Right, cursor.KeepAnchor,
+ end_pos - start_pos)
+ self._editor.setTextCursor(cursor)
+
+ def match_select(self, ignored_symbols=None):
+ """
+ Performs matched selection, selects text between matching quotes or
+ parentheses.
+
+ :param ignored_symbols; matching symbols to ignore.
+ """
+ def filter_matching(ignored_symbols, matching):
+ """
+ Removes any ignored symbol from the match dict.
+ """
+ if ignored_symbols is not None:
+ for symbol in matching.keys():
+ if symbol in ignored_symbols:
+ matching.pop(symbol)
+ return matching
+
+ def find_opening_symbol(cursor, matching):
+ """
+ Find the position ot the opening symbol
+ :param cursor: Current text cursor
+ :param matching: symbol matches map
+ """
+ start_pos = None
+ opening_char = None
+ closed = {k: 0 for k in matching.values()
+ if k not in ['"', "'"]}
+ # go left
+ stop = False
+ while not stop and not cursor.atStart():
+ cursor.clearSelection()
+ cursor.movePosition(cursor.Left, cursor.KeepAnchor)
+ char = cursor.selectedText()
+ if char in closed.keys():
+ closed[char] += 1
+ elif char in matching.keys():
+ opposite = matching[char]
+ if opposite in closed.keys() and closed[opposite]:
+ closed[opposite] -= 1
+ continue
+ else:
+ # found opening quote or parenthesis
+ start_pos = cursor.position() + 1
+ stop = True
+ opening_char = char
+ return opening_char, start_pos
+
+ def find_closing_symbol(cursor, matching, opening_char, original_pos):
+ """
+ Finds the position of the closing symbol.
+
+ :param cursor: current text cursor
+ :param matching: symbold matching dict
+ :param opening_char: the opening character
+ :param original_pos: position of the opening character.
+ """
+ end_pos = None
+ cursor.setPosition(original_pos)
+ rev_matching = {v: k for k, v in matching.items()}
+ opened = {k: 0 for k in rev_matching.values()
+ if k not in ['"', "'"]}
+ stop = False
+ while not stop and not cursor.atEnd():
+ cursor.clearSelection()
+ cursor.movePosition(cursor.Right, cursor.KeepAnchor)
+ char = cursor.selectedText()
+ if char in opened.keys():
+ opened[char] += 1
+ elif char in rev_matching.keys():
+ opposite = rev_matching[char]
+ if opposite in opened.keys() and opened[opposite]:
+ opened[opposite] -= 1
+ continue
+ elif matching[opening_char] == char:
+ # found opening quote or parenthesis
+ end_pos = cursor.position() - 1
+ stop = True
+ return end_pos
+
+ matching = {'(': ')', '{': '}', '[': ']', '"': '"', "'": "'"}
+ filter_matching(ignored_symbols, matching)
+ cursor = self._editor.textCursor()
+ original_pos = cursor.position()
+ end_pos = None
+ opening_char, start_pos = find_opening_symbol(cursor, matching)
+ if opening_char:
+ end_pos = find_closing_symbol(
+ cursor, matching, opening_char, original_pos)
+ if start_pos and end_pos:
+ cursor.setPosition(start_pos)
+ cursor.movePosition(cursor.Right, cursor.KeepAnchor,
+ end_pos - start_pos)
+ self._editor.setTextCursor(cursor)
+ return True
+ else:
+ return False
+
+
+class TextBlockHelper(object):
+ """
+ Helps retrieving the various part of the user state bitmask.
+
+ This helper should be used to replace calls to
+ ``QTextBlock.setUserState``/``QTextBlock.getUserState`` as well as
+ ``QSyntaxHighlighter.setCurrentBlockState``/
+ ``QSyntaxHighlighter.currentBlockState`` and
+ ``QSyntaxHighlighter.previousBlockState``.
+
+ The bitmask is made up of the following fields:
+
+ - bit0 -> bit26: User state (for syntax highlighting)
+ - bit26: fold trigger state
+ - bit27-bit29: fold level (8 level max)
+ - bit30: fold trigger flag
+
+ - bit0 -> bit15: 16 bits for syntax highlighter user state (
+ for syntax highlighting)
+ - bit16-bit25: 10 bits for the fold level (1024 levels)
+ - bit26: 1 bit for the fold trigger flag (trigger or not trigger)
+ - bit27: 1 bit for the fold trigger state (expanded/collapsed)
+
+ """
+ @staticmethod
+ def get_state(block):
+ """
+ Gets the user state, generally used for syntax highlighting.
+ :param block: block to access
+ :return: The block state
+
+ """
+ if block is None:
+ return -1
+ state = block.userState()
+ if state == -1:
+ return state
+ return state & 0x0000FFFF
+
+ @staticmethod
+ def set_state(block, state):
+ """
+ Sets the user state, generally used for syntax highlighting.
+
+ :param block: block to modify
+ :param state: new state value.
+ :return:
+ """
+ if block is None:
+ return
+ user_state = block.userState()
+ if user_state == -1:
+ user_state = 0
+ higher_part = user_state & 0x7FFF0000
+ state &= 0x0000FFFF
+ state |= higher_part
+ block.setUserState(state)
+
+ @staticmethod
+ def get_fold_lvl(block):
+ """
+ Gets the block fold level.
+
+ :param block: block to access.
+ :returns: The block fold level
+ """
+ if block is None:
+ return 0
+ state = block.userState()
+ if state == -1:
+ state = 0
+ return (state & 0x03FF0000) >> 16
+
+ @staticmethod
+ def set_fold_lvl(block, val):
+ """
+ Sets the block fold level.
+
+ :param block: block to modify
+ :param val: The new fold level [0-7]
+ """
+ if block is None:
+ return
+ state = block.userState()
+ if state == -1:
+ state = 0
+ if val >= 0x3FF:
+ val = 0x3FF
+ state &= 0x7C00FFFF
+ state |= val << 16
+ block.setUserState(state)
+
+ @staticmethod
+ def is_fold_trigger(block):
+ """
+ Checks if the block is a fold trigger.
+
+ :param block: block to check
+ :return: True if the block is a fold trigger (represented as a node in
+ the fold panel)
+ """
+ if block is None:
+ return False
+ state = block.userState()
+ if state == -1:
+ state = 0
+ return bool(state & 0x04000000)
+
+ @staticmethod
+ def set_fold_trigger(block, val):
+ """
+ Set the block fold trigger flag (True means the block is a fold
+ trigger).
+
+ :param block: block to set
+ :param val: value to set
+ """
+ if block is None:
+ return
+ state = block.userState()
+ if state == -1:
+ state = 0
+ state &= 0x7BFFFFFF
+ state |= int(val) << 26
+ block.setUserState(state)
+
+ @staticmethod
+ def is_collapsed(block):
+ """
+ Checks if the block is expanded or collased.
+
+ :param block: QTextBlock
+ :return: False for an open trigger, True for for closed trigger
+ """
+ if block is None:
+ return False
+ state = block.userState()
+ if state == -1:
+ state = 0
+ return bool(state & 0x08000000)
+
+ @staticmethod
+ def set_collapsed(block, val):
+ """
+ Sets the fold trigger state (collapsed or expanded).
+
+ :param block: The block to modify
+ :param val: The new trigger state (True=collapsed, False=expanded)
+ """
+ if block is None:
+ return
+ state = block.userState()
+ if state == -1:
+ state = 0
+ state &= 0x77FFFFFF
+ state |= int(val) << 27
+ block.setUserState(state)
+
+
+class ParenthesisInfo(object):
+ """
+ Stores information about a parenthesis in a line of code.
+ """
+ def __init__(self, pos, char):
+ #: Position of the parenthesis, expressed as a number of character
+ self.position = pos
+ #: The parenthesis character, one of "(", ")", "{", "}", "[", "]"
+ self.character = char
+
+
+def get_block_symbol_data(editor, block):
+ """
+ Gets the list of ParenthesisInfo for specific text block.
+
+ :param editor: Code editor instance
+ :param block: block to parse
+ """
+ def list_symbols(editor, block, character):
+ """
+ Retuns a list of symbols found in the block text
+
+ :param editor: code editor instance
+ :param block: block to parse
+ :param character: character to look for.
+ """
+ text = block.text()
+ symbols = []
+ cursor = QTextCursor(block)
+ cursor.movePosition(cursor.StartOfBlock)
+ pos = text.find(character, 0)
+ cursor.movePosition(cursor.Right, cursor.MoveAnchor, pos)
+
+ while pos != -1:
+ if not TextHelper(editor).is_comment_or_string(cursor):
+ # skips symbols in string literal or comment
+ info = ParenthesisInfo(pos, character)
+ symbols.append(info)
+ pos = text.find(character, pos + 1)
+ cursor.movePosition(cursor.StartOfBlock)
+ cursor.movePosition(cursor.Right, cursor.MoveAnchor, pos)
+ return symbols
+
+ parentheses = sorted(
+ list_symbols(editor, block, '(') + list_symbols(editor, block, ')'),
+ key=lambda x: x.position)
+ square_brackets = sorted(
+ list_symbols(editor, block, '[') + list_symbols(editor, block, ']'),
+ key=lambda x: x.position)
+ braces = sorted(
+ list_symbols(editor, block, '{') + list_symbols(editor, block, '}'),
+ key=lambda x: x.position)
+ return parentheses, square_brackets, braces
+
+
+def keep_tc_pos(func):
+ """
+ Cache text cursor position and restore it when the wrapped
+ function exits.
+
+ This decorator can only be used on modes or panels.
+
+ :param func: wrapped function
+ """
+ @functools.wraps(func)
+ def wrapper(editor, *args, **kwds):
+ """ Decorator """
+ sb = editor.verticalScrollBar()
+ spos = sb.sliderPosition()
+ pos = editor.textCursor().position()
+ retval = func(editor, *args, **kwds)
+ text_cursor = editor.textCursor()
+ text_cursor.setPosition(pos)
+ editor.setTextCursor(text_cursor)
+ sb.setSliderPosition(spos)
+ return retval
+ return wrapper
+
+
+def with_wait_cursor(func):
+ """
+ Show a wait cursor while the wrapped function is running. The cursor is
+ restored as soon as the function exits.
+
+ :param func: wrapped function
+ """
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ QApplication.setOverrideCursor(
+ QCursor(Qt.WaitCursor))
+ try:
+ ret_val = func(*args, **kwargs)
+ finally:
+ QApplication.restoreOverrideCursor()
+ return ret_val
+ return wrapper
diff --git a/spyder/plugins/editor/utils/findtasks.py b/spyder/plugins/editor/utils/findtasks.py
new file mode 100644
index 00000000000..87026d35323
--- /dev/null
+++ b/spyder/plugins/editor/utils/findtasks.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+Source code analysis utilities.
+"""
+
+import re
+
+# Local import
+from spyder.config.base import get_debug_level
+
+DEBUG_EDITOR = get_debug_level() >= 3
+
+# =============================================================================
+# Find tasks - TODOs
+# =============================================================================
+TASKS_PATTERN = r"(^|#)[ ]*(TODO|FIXME|XXX|HINT|TIP|@todo|" \
+ r"HACK|BUG|OPTIMIZE|!!!|\?\?\?)([^#]*)"
+
+
+def find_tasks(source_code):
+ """Find tasks in source code (TODO, FIXME, XXX, ...)."""
+ results = []
+ for line, text in enumerate(source_code.splitlines()):
+ for todo in re.findall(TASKS_PATTERN, text):
+ todo_text = (todo[-1].strip(' :').capitalize() if todo[-1]
+ else todo[-2])
+ results.append((todo_text, line + 1))
+ return results
diff --git a/spyder/plugins/editor/utils/folding.py b/spyder/plugins/editor/utils/folding.py
new file mode 100644
index 00000000000..61533e9c1b9
--- /dev/null
+++ b/spyder/plugins/editor/utils/folding.py
@@ -0,0 +1,282 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2013-2016 Colin Duquesnoy and others (see pyqode/AUTHORS.rst)
+# Copyright (c) 2016- Spyder Project Contributors (see AUTHORS.txt)
+#
+# Distributed under the terms of the MIT License
+# (see NOTICE.txt in the Spyder root directory for details)
+# -----------------------------------------------------------------------------
+
+"""
+This module contains some implementations of fold detectors.
+
+Adapted from pyqode/core/api/folding.py of the
+`PyQode project `_.
+Original file:
+
+"""
+
+# Standard library imports
+import sys
+
+# Local imports
+from spyder.plugins.editor.api.folding import FoldDetector
+from spyder.plugins.editor.utils.editor import TextBlockHelper
+
+
+class FoldScope(object):
+ """
+ Utility class for manipulating fold-able code scope (fold/unfold,
+ get range, child and parent scopes and so on).
+
+ A scope is built from a fold trigger (QTextBlock).
+ """
+
+ @property
+ def trigger_level(self):
+ """
+ Returns the fold level of the block trigger.
+ :return:
+ """
+ return TextBlockHelper.get_fold_lvl(self._trigger)
+
+ @property
+ def scope_level(self):
+ """
+ Returns the fold level of the first block of the foldable scope (
+ just after the trigger).
+
+ :return:
+ """
+ return TextBlockHelper.get_fold_lvl(self._trigger.next())
+
+ @property
+ def collapsed(self):
+ """Returns True if the block is collasped, False if it is expanded."""
+ return TextBlockHelper.is_collapsed(self._trigger)
+
+ def __init__(self, block):
+ """
+ Create a fold-able region from a fold trigger block.
+
+ :param block: The block **must** be a fold trigger.
+ :type block: QTextBlock
+
+ :raise: `ValueError` if the text block is not a fold trigger.
+ """
+ if not TextBlockHelper.is_fold_trigger(block):
+ raise ValueError('Not a fold trigger')
+ self._trigger = block
+
+ def get_range(self, ignore_blank_lines=True):
+ """
+ Gets the fold region range (start and end line).
+
+ .. note:: Start line do no encompass the trigger line.
+
+ :param ignore_blank_lines: True to ignore blank lines at the end of the
+ scope (the method will rewind to find that last meaningful block
+ that is part of the fold scope).
+ :returns: tuple(int, int)
+ """
+ ref_lvl = self.trigger_level
+ first_line = self._trigger.blockNumber()
+ block = self._trigger.next()
+ last_line = block.blockNumber()
+ lvl = self.scope_level
+ if ref_lvl == lvl: # for zone set programmatically such as imports
+ # in pyqode.python
+ ref_lvl -= 1
+ while (block.isValid() and
+ TextBlockHelper.get_fold_lvl(block) > ref_lvl):
+ last_line = block.blockNumber()
+ block = block.next()
+
+ if ignore_blank_lines and last_line:
+ block = block.document().findBlockByNumber(last_line)
+ while block.blockNumber() and block.text().strip() == '':
+ block = block.previous()
+ last_line = block.blockNumber()
+ return first_line, last_line
+
+ def fold(self):
+ """Folds the region."""
+ start, end = self.get_range()
+ TextBlockHelper.set_collapsed(self._trigger, True)
+ block = self._trigger.next()
+ while block.blockNumber() <= end and block.isValid():
+ block.setVisible(False)
+ block = block.next()
+
+ def unfold(self):
+ """Unfolds the region."""
+ # set all direct child blocks which are not triggers to be visible
+ self._trigger.setVisible(True)
+ TextBlockHelper.set_collapsed(self._trigger, False)
+ for block in self.blocks(ignore_blank_lines=False):
+ block.setVisible(True)
+ if TextBlockHelper.is_fold_trigger(block):
+ TextBlockHelper.set_collapsed(block, False)
+
+ def blocks(self, ignore_blank_lines=True):
+ """
+ This generator generates the list of blocks directly under the fold
+ region. This list does not contain blocks from child regions.
+
+ :param ignore_blank_lines: True to ignore last blank lines.
+ """
+ start, end = self.get_range(ignore_blank_lines=ignore_blank_lines)
+ block = self._trigger.next()
+ while block.blockNumber() <= end and block.isValid():
+ yield block
+ block = block.next()
+
+ def child_regions(self):
+ """This generator generates the list of direct child regions."""
+ start, end = self.get_range()
+ block = self._trigger.next()
+ ref_lvl = self.scope_level
+ while block.blockNumber() <= end and block.isValid():
+ lvl = TextBlockHelper.get_fold_lvl(block)
+ trigger = TextBlockHelper.is_fold_trigger(block)
+ if lvl == ref_lvl and trigger:
+ yield FoldScope(block)
+ block = block.next()
+
+ def parent(self):
+ """
+ Return the parent scope.
+
+ :return: FoldScope or None
+ """
+ if TextBlockHelper.get_fold_lvl(self._trigger) > 0 and \
+ self._trigger.blockNumber():
+ block = self._trigger.previous()
+ ref_lvl = self.trigger_level - 1
+ while (block.blockNumber() and
+ (not TextBlockHelper.is_fold_trigger(block) or
+ TextBlockHelper.get_fold_lvl(block) > ref_lvl)):
+ block = block.previous()
+ try:
+ return FoldScope(block)
+ except ValueError:
+ return None
+ return None
+
+ def text(self, max_lines=sys.maxsize):
+ """
+ Get the scope text, with a possible maximum number of lines.
+
+ :param max_lines: limit the number of lines returned to a maximum.
+ :return: str
+ """
+ ret_val = []
+ block = self._trigger.next()
+ _, end = self.get_range()
+ while (block.isValid() and block.blockNumber() <= end and
+ len(ret_val) < max_lines):
+ ret_val.append(block.text())
+ block = block.next()
+ return '\n'.join(ret_val)
+
+ @staticmethod
+ def find_parent_scope(block):
+ """
+ Find parent scope, if the block is not a fold trigger.
+
+ :param block: block from which the research will start
+ """
+ # if we moved up for more than n lines, just give up otherwise this
+ # would take too much time.
+ limit = 5000
+ counter = 0
+ original = block
+ if not TextBlockHelper.is_fold_trigger(block):
+ # search level of next non blank line
+ while block.text().strip() == '' and block.isValid():
+ block = block.next()
+ ref_lvl = TextBlockHelper.get_fold_lvl(block) - 1
+ block = original
+ while (block.blockNumber() and counter < limit and
+ (not TextBlockHelper.is_fold_trigger(block) or
+ TextBlockHelper.get_fold_lvl(block) > ref_lvl)):
+ counter += 1
+ block = block.previous()
+ if counter < limit:
+ return block
+ return None
+
+ def __repr__(self):
+ return 'FoldScope(start=%r, end=%d)' % self.get_range()
+
+
+class IndentFoldDetector(FoldDetector):
+ """Simple fold detector based on the line indentation level."""
+
+ def detect_fold_level(self, prev_block, block):
+ """
+ Detects fold level by looking at the block indentation.
+
+ :param prev_block: previous text block
+ :param block: current block to highlight
+ """
+ text = block.text()
+ prev_lvl = TextBlockHelper().get_fold_lvl(prev_block)
+ # round down to previous indentation guide to ensure contiguous block
+ # fold level evolution.
+ indent_len = 0
+ if (prev_lvl and prev_block is not None and
+ not self.editor.is_comment(prev_block)):
+ # ignore commented lines (could have arbitary indentation)
+ prev_text = prev_block.text()
+ indent_len = (len(prev_text) - len(prev_text.lstrip())) // prev_lvl
+ if indent_len == 0:
+ indent_len = len(self.editor.indent_chars)
+
+ return (len(text) - len(text.lstrip())) // indent_len
+
+
+class CharBasedFoldDetector(FoldDetector):
+ """
+ Fold detector based on trigger charachters (e.g. a { increase fold level
+ and } decrease fold level).
+ """
+ def __init__(self, open_chars=('{'), close_chars=('}')):
+ super(CharBasedFoldDetector, self).__init__()
+ self.open_chars = open_chars
+ self.close_chars = close_chars
+
+ def detect_fold_level(self, prev_block, block):
+ if prev_block:
+ prev_text = prev_block.text().strip()
+ else:
+ prev_text = ''
+ text = block.text().strip()
+ if text in self.open_chars:
+ return TextBlockHelper.get_fold_lvl(prev_block) + 1
+ if prev_text.endswith(self.open_chars) and prev_text not in \
+ self.open_chars:
+ return TextBlockHelper.get_fold_lvl(prev_block) + 1
+ if self.close_chars in prev_text:
+ return TextBlockHelper.get_fold_lvl(prev_block) - 1
+ return TextBlockHelper.get_fold_lvl(prev_block)
+
+
+if __name__ == '__main__':
+ """Print folding blocks of this file for debugging"""
+ from spyder.plugins.editor.api.folding import print_tree
+ from spyder.utils.qthelpers import qapplication
+ from spyder.plugins.editor.widgets.codeeditor import CodeEditor
+
+ if len(sys.argv) > 1:
+ fname = sys.argv[1]
+ else:
+ fname = __file__
+
+ app = qapplication()
+ editor = CodeEditor(parent=None)
+ editor.setup_editor(language='Python')
+
+ editor.set_text_from_file(fname)
+
+ print_tree(editor)
diff --git a/spyder/widgets/sourcecode/kill_ring.py b/spyder/plugins/editor/utils/kill_ring.py
similarity index 86%
rename from spyder/widgets/sourcecode/kill_ring.py
rename to spyder/plugins/editor/utils/kill_ring.py
index d7678e88eb2..0937c189d71 100644
--- a/spyder/widgets/sourcecode/kill_ring.py
+++ b/spyder/plugins/editor/utils/kill_ring.py
@@ -1,8 +1,18 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2001-2015 IPython Development Team
+# Copyright (c) 2015 Jupyter Development Team
+# Copyright (c) 2015- Spyder Project Contributors
+#
+# Distributed under the terms of the Modified BSD License
+# (BSD 3-clause; see NOTICE.txt in the Spyder root directory for details).
+# -----------------------------------------------------------------------------
+
"""
A generic Emacs-style kill ring, as well as a Qt-specific version.
-Copyright (c) 2001-2015, IPython Development Team
-Copyright (c) 2015-, Jupyter Development Team
-All rights reserved.
+
+Adapted from qtconsole/kill_ring.py of the
+`Jupyter QtConsole Project `_.
"""
# Third party imports
diff --git a/spyder/plugins/editor/utils/languages.py b/spyder/plugins/editor/utils/languages.py
new file mode 100644
index 00000000000..2155aa4adeb
--- /dev/null
+++ b/spyder/plugins/editor/utils/languages.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+Language utilities
+"""
+
+ALL_LANGUAGES = {
+ 'Python': ('py', 'pyw', 'python', 'ipy'),
+ 'Cython': ('pyx', 'pxi', 'pxd'),
+ 'Enaml': ('enaml',),
+ 'Fortran77': ('f', 'for', 'f77'),
+ 'Fortran': ('f90', 'f95', 'f2k', 'f03', 'f08'),
+ 'Idl': ('pro',),
+ 'Diff': ('diff', 'patch', 'rej'),
+ 'GetText': ('po', 'pot'),
+ 'Nsis': ('nsi', 'nsh'),
+ 'Html': ('htm', 'html'),
+ 'Cpp': ('c', 'cc', 'cpp', 'cxx', 'h', 'hh', 'hpp', 'hxx'),
+ 'OpenCL': ('cl',),
+ 'Yaml': ('yaml', 'yml'),
+ "Markdown": ('md', 'mdw'),
+ }
+
+PYTHON_LIKE_LANGUAGES = ('Python', 'Cython', 'Enaml')
+
+CELL_LANGUAGES = {'Python': ('#%%', '# %%', '# ', '# In[')}
diff --git a/spyder/plugins/editor/utils/lsp.py b/spyder/plugins/editor/utils/lsp.py
new file mode 100644
index 00000000000..0c28852ba7d
--- /dev/null
+++ b/spyder/plugins/editor/utils/lsp.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Spyder Language Server Protocol Client auxiliar decorators (Sourcecode)."""
+
+import functools
+
+
+def request(req=None, method=None, requires_response=True):
+ """Call function req and then emit its results to the LSP server."""
+ if req is None:
+ return functools.partial(request, method=method,
+ requires_response=requires_response)
+
+ @functools.wraps(req)
+ def wrapper(self, *args, **kwargs):
+ if self.lsp_ready:
+ params = req(self, *args, **kwargs)
+ if params is not None:
+ self.emit_request(method, params, requires_response)
+ return wrapper
+
+
+def class_register(cls):
+ """Class decorator that allows to map LSP method names to class methods."""
+ cls.handler_registry = {}
+ for method_name in dir(cls):
+ method = getattr(cls, method_name)
+ if hasattr(method, '_handle'):
+ cls.handler_registry.update({method._handle: method_name})
+ return cls
+
+
+def handles(method_name):
+ """Assign an LSP method name to a python handler."""
+ def wrapper(func):
+ func._handle = method_name
+ return func
+ return wrapper
diff --git a/spyder/plugins/editor/utils/tests/test_autosave.py b/spyder/plugins/editor/utils/tests/test_autosave.py
new file mode 100644
index 00000000000..0f1baebdabb
--- /dev/null
+++ b/spyder/plugins/editor/utils/tests/test_autosave.py
@@ -0,0 +1,96 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+"""Tests for autosave.py"""
+
+# Third party imports
+import pytest
+
+# Local imports
+from spyder.plugins.editor.utils.autosave import (AutosaveForStack,
+ AutosaveForPlugin)
+
+
+def test_autosave_component_set_interval(mocker):
+ """Test that setting the interval does indeed change it and calls
+ do_autosave if enabled."""
+ mocker.patch.object(AutosaveForPlugin, 'do_autosave')
+ addon = AutosaveForPlugin(None)
+ addon.do_autosave.assert_not_called()
+ addon.interval = 10000
+ assert addon.interval == 10000
+ addon.do_autosave.assert_not_called()
+ addon.enabled = True
+ addon.interval = 20000
+ assert addon.do_autosave.called
+
+
+@pytest.mark.parametrize('enabled', [False, True])
+def test_autosave_component_timer_if_enabled(qtbot, mocker, enabled):
+ """Test that AutosaveForPlugin calls do_autosave() on timer if enabled."""
+ mocker.patch.object(AutosaveForPlugin, 'do_autosave')
+ addon = AutosaveForPlugin(None)
+ addon.do_autosave.assert_not_called()
+ addon.interval = 100
+ addon.enabled = enabled
+ qtbot.wait(500)
+ if enabled:
+ assert addon.do_autosave.called
+ else:
+ addon.do_autosave.assert_not_called()
+
+
+@pytest.mark.parametrize('exception', [False, True])
+@pytest.mark.parametrize('errors', ['raise', 'ignore'])
+def test_autosave_remove_autosave_file(mocker, exception, errors):
+ """Test that AutosaveForStack.remove_autosave_file removes the autosave
+ file and that an error dialog is displayed if an exception is raised."""
+ mock_remove = mocker.patch('os.remove')
+ if exception:
+ mock_remove.side_effect = EnvironmentError()
+ mock_dialog = mocker.patch(
+ 'spyder.plugins.editor.utils.autosave.AutosaveErrorDialog')
+ mock_stack = mocker.Mock()
+ fileinfo = mocker.Mock()
+ fileinfo.filename = 'orig'
+ addon = AutosaveForStack(mock_stack)
+ addon.name_mapping = {'orig': 'autosave'}
+
+ addon.remove_autosave_file(fileinfo.filename, errors=errors)
+ assert addon.name_mapping == {}
+ mock_remove.assert_called_with('autosave')
+ assert mock_dialog.called == (exception and errors == 'raise')
+
+
+@pytest.mark.parametrize('exception', [False, True])
+@pytest.mark.parametrize('errors', ['raise', 'ignore'])
+def test_autosave_remove_all_autosave_files(mocker, exception, errors):
+ """
+ Test that ``remove_all_autosave_files`` succeeds and handles errors.
+
+ Check that AutosaveForStack.remove_all_autosave_files removes all
+ autosaves and that an error dialog is displayed if an exception is raised.
+ """
+ mock_remove = mocker.patch('os.remove')
+ if exception:
+ mock_remove.side_effect = EnvironmentError()
+ mock_dialog = mocker.patch(
+ 'spyder.plugins.editor.utils.autosave.AutosaveErrorDialog')
+ mock_stack = mocker.Mock()
+ addon = AutosaveForStack(mock_stack)
+ addon.name_mapping = {}
+ for idx in range(3):
+ addon.name_mapping['orig_' + str(idx)] = 'autosave_' + str(idx)
+
+ addon.remove_all_autosave_files(errors=errors)
+ assert addon.name_mapping == {}
+ assert mock_remove.call_count == 3
+ assert mock_remove.call_args_list == [
+ (('autosave_' + str(idx),),) for idx in range(3)]
+ assert mock_dialog.called == (exception and errors == 'raise')
+
+
+if __name__ == "__main__":
+ pytest.main()
diff --git a/spyder/plugins/editor/widgets/__init__.py b/spyder/plugins/editor/widgets/__init__.py
new file mode 100644
index 00000000000..56d13d59f86
--- /dev/null
+++ b/spyder/plugins/editor/widgets/__init__.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors
+#
+# Distributed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+
+"""
+spyder.plugins.editor.widgets
+=============================
+
+Editor related widgets (Editor, EditorStack, CodeEditor) based on only Qt.
+"""
diff --git a/spyder/plugins/editor/widgets/autosaveerror.py b/spyder/plugins/editor/widgets/autosaveerror.py
new file mode 100644
index 00000000000..e3c593f5eb0
--- /dev/null
+++ b/spyder/plugins/editor/widgets/autosaveerror.py
@@ -0,0 +1,85 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Dialog window notifying user of autosave-related errors."""
+
+# Standard library imports
+import logging
+
+# Third party imports
+from qtpy.QtWidgets import (QCheckBox, QDialog, QDialogButtonBox, QLabel,
+ QVBoxLayout)
+
+# Local imports
+from spyder.config.base import _
+
+
+logger = logging.getLogger(__name__)
+
+
+class AutosaveErrorDialog(QDialog):
+ """
+ Dialog window notifying user of autosave-related errors.
+
+ The window also includes a check box which allows the user to hide any
+ future autosave-related errors.
+
+ Class attribute:
+ show_errors (bool): whether to show errors or not
+ """
+
+ show_errors = True
+
+ def __init__(self, action, error):
+ """
+ Constructor.
+
+ Args:
+ action (str): what Spyder was trying to do when error occured
+ error (Exception): the error that occured
+ """
+ logger.error(action, exc_info=error)
+
+ QDialog.__init__(self)
+ self.setWindowTitle(_('Autosave error'))
+ self.setModal(True)
+
+ layout = QVBoxLayout()
+
+ header = _('Error message:')
+ txt = '
{}
{}
{!s}'.format(action, header, error)
+ layout.addWidget(QLabel(txt))
+ layout.addSpacing(15)
+
+ txt = _("Hide all future autosave-related errors during this session")
+ self.dismiss_box = QCheckBox(txt)
+ layout.addWidget(self.dismiss_box)
+ layout.addSpacing(15)
+
+ button_box = QDialogButtonBox(QDialogButtonBox.Ok)
+ button_box.accepted.connect(self.accept)
+ layout.addWidget(button_box)
+
+ self.setLayout(layout)
+
+ def exec_if_enabled(self):
+ """
+ Execute dialog box unless disabled by the user.
+
+ The dialog box is disabled once the user clicks the 'Hide all future
+ errors' check box on one dialog box.
+ """
+ if AutosaveErrorDialog.show_errors:
+ return self.exec_()
+
+ def accept(self):
+ """
+ Update `show_errors` and hide dialog box.
+
+ Overrides method of `QDialogBox`.
+ """
+ AutosaveErrorDialog.show_errors = not self.dismiss_box.isChecked()
+ return QDialog.accept(self)
diff --git a/spyder/plugins/editor/widgets/base.py b/spyder/plugins/editor/widgets/base.py
new file mode 100644
index 00000000000..071c281b924
--- /dev/null
+++ b/spyder/plugins/editor/widgets/base.py
@@ -0,0 +1,1319 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""QPlainTextEdit base class"""
+
+# pylint: disable=C0103
+# pylint: disable=R0903
+# pylint: disable=R0911
+# pylint: disable=R0201
+
+# Standard library imports
+import os
+import os.path as osp
+import sys
+
+# Third party imports
+from qtpy.compat import to_qvariant
+from qtpy.QtCore import QEvent, QEventLoop, QPoint, Qt, Signal, Slot
+from qtpy.QtGui import (QClipboard, QColor, QMouseEvent, QPalette, QTextFormat,
+ QTextOption, QTextCursor)
+from qtpy.QtWidgets import (QAbstractItemView, QApplication, QListWidget,
+ QListWidgetItem, QMainWindow, QPlainTextEdit,
+ QToolTip)
+
+# Local imports
+from spyder.config.gui import get_font
+from spyder.config.main import CONF
+from spyder.py3compat import PY3, to_text_string
+from spyder.utils import icon_manager as ima
+from spyder.widgets.calltip import CallTipWidget, ToolTipWidget
+from spyder.widgets.mixins import BaseEditMixin
+from spyder.plugins.editor.api.decoration import TextDecoration, DRAW_ORDERS
+from spyder.plugins.editor.utils.decoration import TextDecorationsManager
+from spyder.plugins.editor.lsp import CompletionItemKind
+
+
+class CompletionWidget(QListWidget):
+ """Completion list widget"""
+
+ sig_show_completions = Signal(object)
+
+ def __init__(self, parent, ancestor):
+ QListWidget.__init__(self, ancestor)
+ self.setWindowFlags(Qt.SubWindow | Qt.FramelessWindowHint)
+ self.textedit = parent
+ self.hide()
+ self.itemActivated.connect(self.item_selected)
+ self.currentRowChanged.connect(self.row_changed)
+ self.is_internal_console = False
+ self.completion_list = None
+ self.completion_position = None
+ self.automatic = False
+ # Text to be displayed if no match is found.
+ self.empty_text = 'No match'
+
+ def setup_appearance(self, size, font):
+ self.resize(*size)
+ self.setFont(font)
+
+ def is_empty(self):
+ """Check if widget is empty."""
+ if self.count() == 0:
+ return True
+ if self.count() == 1 and self.item(0).text() == self.empty_text:
+ return True
+ return False
+
+ def show_list(self, completion_list, position, automatic):
+ """Show list corresponding to position."""
+
+ if not completion_list:
+ self.hide()
+ return
+
+ self.automatic = automatic
+
+ if position is None:
+ # Somehow the position was not saved.
+ # Hope that the current position is still valid
+ self.completion_position = self.textedit.textCursor().position()
+
+ elif self.textedit.textCursor().position() < position:
+ # hide the text as we moved away from the position
+ self.hide()
+ return
+
+ else:
+ self.completion_position = position
+
+ # Completions are handled differently for the Internal
+ # console.
+ if not isinstance(completion_list[0], dict):
+ self.is_internal_console = True
+ self.completion_list = completion_list
+ # Check everything is in order
+ self.update_current()
+
+ # If update_current called close, stop loading
+ if not self.completion_list:
+ return
+
+ # If only one, must be chosen if not automatic
+ single_match = (self.count() == 1 and
+ self.item(0).text() != self.empty_text)
+ if single_match and not self.automatic:
+ self.item_selected()
+ self.hide()
+ # signal used for testing
+ self.sig_show_completions.emit(completion_list)
+ return
+
+ self.show()
+ self.setFocus()
+ self.raise_()
+
+ # Retrieving current screen height
+ desktop = QApplication.desktop()
+ srect = desktop.availableGeometry(desktop.screenNumber(self))
+ screen_right = srect.right()
+ screen_bottom = srect.bottom()
+
+ point = self.textedit.cursorRect().bottomRight()
+ point = self.textedit.calculate_real_position(point)
+ point = self.textedit.mapToGlobal(point)
+
+ # Computing completion widget and its parent right positions
+ comp_right = point.x() + self.width()
+ ancestor = self.parent()
+ if ancestor is None:
+ anc_right = screen_right
+ else:
+ anc_right = min([ancestor.x() + ancestor.width(), screen_right])
+
+ # Moving completion widget to the left
+ # if there is not enough space to the right
+ if comp_right > anc_right:
+ point.setX(point.x() - self.width())
+
+ # Computing completion widget and its parent bottom positions
+ comp_bottom = point.y() + self.height()
+ ancestor = self.parent()
+ if ancestor is None:
+ anc_bottom = screen_bottom
+ else:
+ anc_bottom = min([ancestor.y() + ancestor.height(), screen_bottom])
+
+ # Moving completion widget above if there is not enough space below
+ x_position = point.x()
+ if comp_bottom > anc_bottom:
+ point = self.textedit.cursorRect().topRight()
+ point = self.textedit.mapToGlobal(point)
+ point.setX(x_position)
+ point.setY(point.y() - self.height())
+
+ if ancestor is not None:
+ # Useful only if we set parent to 'ancestor' in __init__
+ point = ancestor.mapFromGlobal(point)
+ self.move(point)
+
+ if not self.is_internal_console:
+ tooltip_point = QPoint(point)
+ tooltip_point.setX(point.x() + self.width())
+ tooltip_point.setY(point.y() - (3 * self.height()) // 4)
+ for completion in completion_list:
+ completion['point'] = tooltip_point
+
+ # signal used for testing
+ self.sig_show_completions.emit(completion_list)
+
+ def update_list(self, filter_text):
+ """
+ Update the displayed list by filtering self.completion_list.
+
+ If returns False, the autocompletion should stop.
+ """
+ self.clear()
+ icons_map = {CompletionItemKind.PROPERTY: 'attribute',
+ CompletionItemKind.VARIABLE: 'attribute',
+ CompletionItemKind.METHOD: 'method',
+ CompletionItemKind.FUNCTION: 'function',
+ CompletionItemKind.CLASS: 'class',
+ CompletionItemKind.MODULE: 'module',
+ CompletionItemKind.CONSTRUCTOR: 'method',
+ CompletionItemKind.REFERENCE: 'attribute'}
+
+ for completion in self.completion_list:
+ if not self.is_internal_console:
+ completion_label = completion['filterText']
+ icon = icons_map.get(completion['kind'], 'no_match')
+ item = QListWidgetItem(ima.icon(icon),
+ completion['insertText'])
+ else:
+ completion_label = completion[0]
+ item = QListWidgetItem(completion_label)
+
+ if self.check_can_complete(
+ completion_label, filter_text):
+ self.addItem(item)
+
+ if self.count() > 0:
+ self.setCurrentRow(0)
+ self.scrollTo(self.currentIndex(),
+ QAbstractItemView.PositionAtTop)
+ else:
+ self.addItem(QListWidgetItem(self.empty_text))
+
+ def hide(self):
+ """Hide the widget."""
+ self.completion_position = None
+ self.completion_list = None
+ self.clear()
+ QToolTip.hideText()
+ QListWidget.hide(self)
+ self.textedit.setFocus()
+
+ def keyPressEvent(self, event):
+ """Process keypress."""
+ text, key = event.text(), event.key()
+ alt = event.modifiers() & Qt.AltModifier
+ shift = event.modifiers() & Qt.ShiftModifier
+ ctrl = event.modifiers() & Qt.ControlModifier
+ modifier = shift or ctrl or alt
+ if key in (Qt.Key_Return, Qt.Key_Enter, Qt.Key_Tab):
+ # Check that what was selected can be selected,
+ # otherwise timing issues
+ if self.up_to_date():
+ self.item_selected()
+ else:
+ self.hide()
+ self.textedit.keyPressEvent(event)
+ elif key == Qt.Key_Escape:
+ self.hide()
+ elif key in (Qt.Key_Left, Qt.Key_Right) or text in ('.', ':'):
+ self.hide()
+ self.textedit.keyPressEvent(event)
+ elif key in (Qt.Key_Up, Qt.Key_Down, Qt.Key_PageUp, Qt.Key_PageDown,
+ Qt.Key_Home, Qt.Key_End,
+ Qt.Key_CapsLock) and not modifier:
+ if key == Qt.Key_Up and self.currentRow() == 0:
+ self.setCurrentRow(self.count() - 1)
+ elif key == Qt.Key_Down and self.currentRow() == self.count()-1:
+ self.setCurrentRow(0)
+ else:
+ QListWidget.keyPressEvent(self, event)
+ elif len(text) or key == Qt.Key_Backspace:
+ self.textedit.keyPressEvent(event)
+ self.update_current()
+ elif modifier:
+ self.textedit.keyPressEvent(event)
+ else:
+ self.hide()
+ QListWidget.keyPressEvent(self, event)
+
+ def up_to_date(self):
+ """
+ Check if the selection is up to date.
+ """
+ if self.is_empty():
+ return False
+ if not self.is_position_correct():
+ return False
+ completion_text = self.textedit.get_current_word(completion=True)
+ selected_text = self.currentItem().text()
+ return self.check_can_complete(selected_text, completion_text)
+
+ def check_can_complete(self, text, sub):
+ """Check if sub can be completed to text."""
+ if not sub:
+ return True
+ return to_text_string(text).lower().startswith(
+ to_text_string(sub).lower())
+
+ def is_position_correct(self):
+ """Check if the position is correct."""
+
+ if self.completion_position is None:
+ return False
+
+ cursor_position = self.textedit.textCursor().position()
+
+ # Can only go forward from the data we have
+ if cursor_position < self.completion_position:
+ return False
+
+ completion_text = self.textedit.get_current_word_and_position(
+ completion=True)
+
+ # If no text found, we must be at self.completion_position
+ if completion_text is None:
+ if self.completion_position == cursor_position:
+ return True
+ else:
+ return False
+
+ completion_text, text_position = completion_text
+ completion_text = to_text_string(completion_text)
+
+ # The position of text must compatible with completion_position
+ if not text_position <= self.completion_position <= (
+ text_position + len(completion_text)):
+ return False
+
+ return True
+
+ def update_current(self):
+ """
+ Update the displayed list.
+ """
+ if not self.is_position_correct():
+ self.hide()
+ return
+
+ completion_text = self.textedit.get_current_word(completion=True)
+ self.update_list(completion_text)
+
+ def focusOutEvent(self, event):
+ event.ignore()
+ # Don't hide it on Mac when main window loses focus because
+ # keyboard input is lost
+ # Fixes Issue 1318
+ if sys.platform == "darwin":
+ if event.reason() != Qt.ActiveWindowFocusReason:
+ self.hide()
+ else:
+ # Avoid an error when running tests that show
+ # the completion widget
+ try:
+ self.hide()
+ except RuntimeError:
+ pass
+
+ def item_selected(self, item=None):
+ """Perform the item selected action."""
+ if item is None:
+ item = self.currentItem()
+
+ if item is not None and self.completion_position is not None:
+ self.textedit.insert_completion(to_text_string(item.text()),
+ self.completion_position)
+ self.hide()
+
+ @Slot(int)
+ def row_changed(self, row):
+ if self.completion_list:
+ item = self.completion_list[row]
+ if len(item['documentation']) > 0:
+ # TODO: LSP - Define an UI element to display the documentation
+ # self.textedit.show_calltip(
+ # item['detail'], item['documentation'], color='#daa520',
+ # at_point=item['point'])
+ return
+ QToolTip.hideText()
+
+
+class TextEditBaseWidget(QPlainTextEdit, BaseEditMixin):
+ """Text edit base widget"""
+ BRACE_MATCHING_SCOPE = ('sof', 'eof')
+ cell_separators = None
+ focus_in = Signal()
+ zoom_in = Signal()
+ zoom_out = Signal()
+ zoom_reset = Signal()
+ focus_changed = Signal()
+ sig_eol_chars_changed = Signal(str)
+
+ def __init__(self, parent=None):
+ QPlainTextEdit.__init__(self, parent)
+ BaseEditMixin.__init__(self)
+ self.setAttribute(Qt.WA_DeleteOnClose)
+
+ self.extra_selections_dict = {}
+
+ self.textChanged.connect(self.changed)
+ self.cursorPositionChanged.connect(self.cursor_position_changed)
+
+ self.indent_chars = " "*4
+ self.tab_stop_width_spaces = 4
+
+ # Code completion / calltips
+ if parent is not None:
+ mainwin = parent
+ while not isinstance(mainwin, QMainWindow):
+ mainwin = mainwin.parent()
+ if mainwin is None:
+ break
+ if mainwin is not None:
+ parent = mainwin
+
+ self.completion_widget = CompletionWidget(self, parent)
+ self.codecompletion_auto = False
+ self.setup_completion()
+
+ self.calltip_widget = CallTipWidget(self, hide_timer_on=False)
+ self.calltip_position = None
+ self.tooltip_widget = ToolTipWidget(self, as_tooltip=True)
+
+ self.highlight_current_cell_enabled = False
+
+ # The color values may be overridden by the syntax highlighter
+ # Highlight current line color
+ self.currentline_color = QColor(Qt.red).lighter(190)
+ self.currentcell_color = QColor(Qt.red).lighter(194)
+
+ # Brace matching
+ self.bracepos = None
+ self.matched_p_color = QColor(Qt.green)
+ self.unmatched_p_color = QColor(Qt.red)
+
+ self.last_cursor_cell = None
+
+ self.decorations = TextDecorationsManager(self)
+
+ def setup_completion(self):
+ size = CONF.get('main', 'completion/size')
+ font = get_font()
+ self.completion_widget.setup_appearance(size, font)
+
+ def set_indent_chars(self, indent_chars):
+ self.indent_chars = indent_chars
+
+ def set_tab_stop_width_spaces(self, tab_stop_width_spaces):
+ self.tab_stop_width_spaces = tab_stop_width_spaces
+ self.update_tab_stop_width_spaces()
+
+ def update_tab_stop_width_spaces(self):
+ self.setTabStopWidth(self.fontMetrics().width(
+ ' ' * self.tab_stop_width_spaces))
+
+ def set_palette(self, background, foreground):
+ """
+ Set text editor palette colors:
+ background color and caret (text cursor) color
+ """
+ # Because QtStylsheet overrides QPalette and because some style do not
+ # use the palette for all drawing (e.g. macOS styles), the background
+ # and foreground color of each TextEditBaseWidget instance must be set
+ # with a stylesheet extended with an ID Selector.
+ # Fixes Issue 2028, 8069 and 9248.
+ if not self.objectName():
+ self.setObjectName(self.__class__.__name__ + str(id(self)))
+ style = "QPlainTextEdit#%s {background: %s; color: %s;}" % \
+ (self.objectName(), background.name(), foreground.name())
+ self.setStyleSheet(style)
+
+ # ---- Extra selections
+ def get_extra_selections(self, key):
+ """Return editor extra selections.
+
+ Args:
+ key (str) name of the extra selections group
+
+ Returns:
+ list of sourcecode.api.TextDecoration.
+ """
+ return self.extra_selections_dict.get(key, [])
+
+ def set_extra_selections(self, key, extra_selections):
+ """Set extra selections for a key.
+
+ Also assign draw orders to leave current_cell and current_line
+ in the backgrund (and avoid them to cover other decorations)
+
+ NOTE: This will remove previous decorations added to the same key.
+
+ Args:
+ key (str) name of the extra selections group.
+ extra_selections (list of sourcecode.api.TextDecoration).
+ """
+ # use draw orders to highlight current_cell and current_line first
+ draw_order = DRAW_ORDERS.get(key)
+ if draw_order is None:
+ draw_order = DRAW_ORDERS.get('on_top')
+
+ for selection in extra_selections:
+ selection.draw_order = draw_order
+
+ self.clear_extra_selections(key)
+ self.extra_selections_dict[key] = extra_selections
+
+ def update_extra_selections(self):
+ """Add extra selections to DecorationsManager.
+
+ TODO: This method could be remove it and decorations could be
+ added/removed in set_extra_selections/clear_extra_selections.
+ """
+ extra_selections = []
+
+ for key, extra in list(self.extra_selections_dict.items()):
+ extra_selections.extend(extra)
+ self.decorations.add(extra_selections)
+
+ def clear_extra_selections(self, key):
+ """Remove decorations added through set_extra_selections.
+
+ Args:
+ key (str) name of the extra selections group.
+ """
+ for decoration in self.extra_selections_dict.get(key, []):
+ self.decorations.remove(decoration)
+ self.extra_selections_dict[key] = []
+
+ def changed(self):
+ """Emit changed signal"""
+ self.modificationChanged.emit(self.document().isModified())
+
+
+ #------Highlight current line
+ def highlight_current_line(self):
+ """Highlight current line"""
+ selection = TextDecoration(self.textCursor())
+ selection.format.setProperty(QTextFormat.FullWidthSelection,
+ to_qvariant(True))
+ selection.format.setBackground(self.currentline_color)
+ selection.cursor.clearSelection()
+ self.set_extra_selections('current_line', [selection])
+ self.update_extra_selections()
+
+ def unhighlight_current_line(self):
+ """Unhighlight current line"""
+ self.clear_extra_selections('current_line')
+
+ #------Highlight current cell
+ def highlight_current_cell(self):
+ """Highlight current cell"""
+ if self.cell_separators is None or \
+ not self.highlight_current_cell_enabled:
+ return
+ cursor, whole_file_selected, whole_screen_selected =\
+ self.select_current_cell_in_visible_portion()
+ selection = TextDecoration(cursor)
+ selection.format.setProperty(QTextFormat.FullWidthSelection,
+ to_qvariant(True))
+ selection.format.setBackground(self.currentcell_color)
+
+ if whole_file_selected:
+ self.clear_extra_selections('current_cell')
+ elif whole_screen_selected:
+ if self.highlighter.found_cell_separators:
+ self.set_extra_selections('current_cell', [selection])
+ self.update_extra_selections()
+ else:
+ self.clear_extra_selections('current_cell')
+ else:
+ self.set_extra_selections('current_cell', [selection])
+ self.update_extra_selections()
+
+ def unhighlight_current_cell(self):
+ """Unhighlight current cell"""
+ self.clear_extra_selections('current_cell')
+
+ #------Brace matching
+ def find_brace_match(self, position, brace, forward):
+ start_pos, end_pos = self.BRACE_MATCHING_SCOPE
+ if forward:
+ bracemap = {'(': ')', '[': ']', '{': '}'}
+ text = self.get_text(position, end_pos)
+ i_start_open = 1
+ i_start_close = 1
+ else:
+ bracemap = {')': '(', ']': '[', '}': '{'}
+ text = self.get_text(start_pos, position)
+ i_start_open = len(text)-1
+ i_start_close = len(text)-1
+
+ while True:
+ if forward:
+ i_close = text.find(bracemap[brace], i_start_close)
+ else:
+ i_close = text.rfind(bracemap[brace], 0, i_start_close+1)
+ if i_close > -1:
+ if forward:
+ i_start_close = i_close+1
+ i_open = text.find(brace, i_start_open, i_close)
+ else:
+ i_start_close = i_close-1
+ i_open = text.rfind(brace, i_close, i_start_open+1)
+ if i_open > -1:
+ if forward:
+ i_start_open = i_open+1
+ else:
+ i_start_open = i_open-1
+ else:
+ # found matching brace
+ if forward:
+ return position+i_close
+ else:
+ return position-(len(text)-i_close)
+ else:
+ # no matching brace
+ return
+
+ def __highlight(self, positions, color=None, cancel=False):
+ if cancel:
+ self.clear_extra_selections('brace_matching')
+ return
+ extra_selections = []
+ for position in positions:
+ if position > self.get_position('eof'):
+ return
+ selection = TextDecoration(self.textCursor())
+ selection.format.setBackground(color)
+ selection.cursor.clearSelection()
+ selection.cursor.setPosition(position)
+ selection.cursor.movePosition(QTextCursor.NextCharacter,
+ QTextCursor.KeepAnchor)
+ extra_selections.append(selection)
+ self.set_extra_selections('brace_matching', extra_selections)
+ self.update_extra_selections()
+
+ def cursor_position_changed(self):
+ """Brace matching"""
+ if self.bracepos is not None:
+ self.__highlight(self.bracepos, cancel=True)
+ self.bracepos = None
+ cursor = self.textCursor()
+ if cursor.position() == 0:
+ return
+ cursor.movePosition(QTextCursor.PreviousCharacter,
+ QTextCursor.KeepAnchor)
+ text = to_text_string(cursor.selectedText())
+ pos1 = cursor.position()
+ if text in (')', ']', '}'):
+ pos2 = self.find_brace_match(pos1, text, forward=False)
+ elif text in ('(', '[', '{'):
+ pos2 = self.find_brace_match(pos1, text, forward=True)
+ else:
+ return
+ if pos2 is not None:
+ self.bracepos = (pos1, pos2)
+ self.__highlight(self.bracepos, color=self.matched_p_color)
+ else:
+ self.bracepos = (pos1,)
+ self.__highlight(self.bracepos, color=self.unmatched_p_color)
+
+
+ #-----Widget setup and options
+ def set_codecompletion_auto(self, state):
+ """Set code completion state"""
+ self.codecompletion_auto = state
+
+ def set_wrap_mode(self, mode=None):
+ """
+ Set wrap mode
+ Valid *mode* values: None, 'word', 'character'
+ """
+ if mode == 'word':
+ wrap_mode = QTextOption.WrapAtWordBoundaryOrAnywhere
+ elif mode == 'character':
+ wrap_mode = QTextOption.WrapAnywhere
+ else:
+ wrap_mode = QTextOption.NoWrap
+ self.setWordWrapMode(wrap_mode)
+
+
+ #------Reimplementing Qt methods
+ @Slot()
+ def copy(self):
+ """
+ Reimplement Qt method
+ Copy text to clipboard with correct EOL chars
+ """
+ if self.get_selected_text():
+ QApplication.clipboard().setText(self.get_selected_text())
+
+ def toPlainText(self):
+ """
+ Reimplement Qt method
+ Fix PyQt4 bug on Windows and Python 3
+ """
+ # Fix what appears to be a PyQt4 bug when getting file
+ # contents under Windows and PY3. This bug leads to
+ # corruptions when saving files with certain combinations
+ # of unicode chars on them (like the one attached on
+ # Issue 1546)
+ if os.name == 'nt' and PY3:
+ text = self.get_text('sof', 'eof')
+ return text.replace('\u2028', '\n').replace('\u2029', '\n')\
+ .replace('\u0085', '\n')
+ else:
+ return super(TextEditBaseWidget, self).toPlainText()
+
+ def keyPressEvent(self, event):
+ text, key = event.text(), event.key()
+ ctrl = event.modifiers() & Qt.ControlModifier
+ meta = event.modifiers() & Qt.MetaModifier
+ # Use our own copy method for {Ctrl,Cmd}+C to avoid Qt
+ # copying text in HTML (See Issue 2285)
+ if (ctrl or meta) and key == Qt.Key_C:
+ self.copy()
+ else:
+ super(TextEditBaseWidget, self).keyPressEvent(event)
+
+ #------Text: get, set, ...
+ def get_selection_as_executable_code(self):
+ """Return selected text as a processed text,
+ to be executable in a Python/IPython interpreter"""
+ ls = self.get_line_separator()
+
+ _indent = lambda line: len(line)-len(line.lstrip())
+
+ line_from, line_to = self.get_selection_bounds()
+ text = self.get_selected_text()
+ if not text:
+ return
+
+ lines = text.split(ls)
+ if len(lines) > 1:
+ # Multiline selection -> eventually fixing indentation
+ original_indent = _indent(self.get_text_line(line_from))
+ text = (" "*(original_indent-_indent(lines[0])))+text
+
+ # If there is a common indent to all lines, find it.
+ # Moving from bottom line to top line ensures that blank
+ # lines inherit the indent of the line *below* it,
+ # which is the desired behavior.
+ min_indent = 999
+ current_indent = 0
+ lines = text.split(ls)
+ for i in range(len(lines)-1, -1, -1):
+ line = lines[i]
+ if line.strip():
+ current_indent = _indent(line)
+ min_indent = min(current_indent, min_indent)
+ else:
+ lines[i] = ' ' * current_indent
+ if min_indent:
+ lines = [line[min_indent:] for line in lines]
+
+ # Remove any leading whitespace or comment lines
+ # since they confuse the reserved word detector that follows below
+ lines_removed = 0
+ while lines:
+ first_line = lines[0].lstrip()
+ if first_line == '' or first_line[0] == '#':
+ lines_removed += 1
+ lines.pop(0)
+ else:
+ break
+
+ # Add an EOL character after the last line of code so that it gets
+ # evaluated automatically by the console and any quote characters
+ # are separated from the triple quotes of runcell
+ lines.append(ls)
+
+ # Add removed lines back to have correct traceback line numbers
+ leading_lines_str = ls * lines_removed
+
+ return leading_lines_str + ls.join(lines)
+
+ def __exec_cell(self):
+ ls = self.get_line_separator()
+ init_cursor = QTextCursor(self.textCursor())
+ start_pos, end_pos = self.__save_selection()
+ cursor, whole_file_selected = self.select_current_cell()
+ self.setTextCursor(cursor)
+ line_from, line_to = self.get_selection_bounds()
+ block = self.get_selection_first_block()
+ text = self.get_selection_as_executable_code()
+ self.last_cursor_cell = init_cursor
+ self.__restore_selection(start_pos, end_pos)
+ if text is not None:
+ text = ls * line_from + text
+ return text, block
+
+ def get_cell_as_executable_code(self):
+ """Return cell contents as executable code"""
+ return self.__exec_cell()
+
+ def get_last_cell_as_executable_code(self):
+ if self.last_cursor_cell:
+ self.setTextCursor(self.last_cursor_cell)
+ self.highlight_current_cell()
+ return self.__exec_cell()
+ return None
+
+ def is_cell_separator(self, cursor=None, block=None):
+ """Return True if cursor (or text block) is on a block separator"""
+ assert cursor is not None or block is not None
+ if cursor is not None:
+ cursor0 = QTextCursor(cursor)
+ cursor0.select(QTextCursor.BlockUnderCursor)
+ text = to_text_string(cursor0.selectedText())
+ else:
+ text = to_text_string(block.text())
+ if self.cell_separators is None:
+ return False
+ else:
+ return text.lstrip().startswith(self.cell_separators)
+
+ def select_current_cell(self):
+ """Select cell under cursor
+ cell = group of lines separated by CELL_SEPARATORS
+ returns the textCursor and a boolean indicating if the
+ entire file is selected"""
+ cursor = self.textCursor()
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ cur_pos = prev_pos = cursor.position()
+
+ # Moving to the next line that is not a separator, if we are
+ # exactly at one of them
+ while self.is_cell_separator(cursor):
+ cursor.movePosition(QTextCursor.NextBlock)
+ prev_pos = cur_pos
+ cur_pos = cursor.position()
+ if cur_pos == prev_pos:
+ return cursor, False
+ prev_pos = cur_pos
+ # If not, move backwards to find the previous separator
+ while not self.is_cell_separator(cursor):
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ prev_pos = cur_pos
+ cur_pos = cursor.position()
+ if cur_pos == prev_pos:
+ if self.is_cell_separator(cursor):
+ return cursor, False
+ else:
+ break
+ cursor.setPosition(prev_pos)
+ cell_at_file_start = cursor.atStart()
+ # Once we find it (or reach the beginning of the file)
+ # move to the next separator (or the end of the file)
+ # so we can grab the cell contents
+ while not self.is_cell_separator(cursor):
+ cursor.movePosition(QTextCursor.NextBlock,
+ QTextCursor.KeepAnchor)
+ cur_pos = cursor.position()
+ if cur_pos == prev_pos:
+ cursor.movePosition(QTextCursor.EndOfBlock,
+ QTextCursor.KeepAnchor)
+ break
+ prev_pos = cur_pos
+ cell_at_file_end = cursor.atEnd()
+ return cursor, cell_at_file_start and cell_at_file_end
+
+ def select_current_cell_in_visible_portion(self):
+ """Select cell under cursor in the visible portion of the file
+ cell = group of lines separated by CELL_SEPARATORS
+ returns
+ -the textCursor
+ -a boolean indicating if the entire file is selected
+ -a boolean indicating if the entire visible portion of the file is selected"""
+ cursor = self.textCursor()
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ cur_pos = prev_pos = cursor.position()
+
+ beg_pos = self.cursorForPosition(QPoint(0, 0)).position()
+ bottom_right = QPoint(self.viewport().width() - 1,
+ self.viewport().height() - 1)
+ end_pos = self.cursorForPosition(bottom_right).position()
+
+ # Moving to the next line that is not a separator, if we are
+ # exactly at one of them
+ while self.is_cell_separator(cursor):
+ cursor.movePosition(QTextCursor.NextBlock)
+ prev_pos = cur_pos
+ cur_pos = cursor.position()
+ if cur_pos == prev_pos:
+ return cursor, False, False
+ prev_pos = cur_pos
+ # If not, move backwards to find the previous separator
+ while not self.is_cell_separator(cursor)\
+ and cursor.position() >= beg_pos:
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ prev_pos = cur_pos
+ cur_pos = cursor.position()
+ if cur_pos == prev_pos:
+ if self.is_cell_separator(cursor):
+ return cursor, False, False
+ else:
+ break
+ cell_at_screen_start = cursor.position() <= beg_pos
+ cursor.setPosition(prev_pos)
+ cell_at_file_start = cursor.atStart()
+ # Selecting cell header
+ if not cell_at_file_start:
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ cursor.movePosition(QTextCursor.NextBlock,
+ QTextCursor.KeepAnchor)
+ # Once we find it (or reach the beginning of the file)
+ # move to the next separator (or the end of the file)
+ # so we can grab the cell contents
+ while not self.is_cell_separator(cursor)\
+ and cursor.position() <= end_pos:
+ cursor.movePosition(QTextCursor.NextBlock,
+ QTextCursor.KeepAnchor)
+ cur_pos = cursor.position()
+ if cur_pos == prev_pos:
+ cursor.movePosition(QTextCursor.EndOfBlock,
+ QTextCursor.KeepAnchor)
+ break
+ prev_pos = cur_pos
+ cell_at_file_end = cursor.atEnd()
+ cell_at_screen_end = cursor.position() >= end_pos
+ return cursor,\
+ cell_at_file_start and cell_at_file_end,\
+ cell_at_screen_start and cell_at_screen_end
+
+ def go_to_next_cell(self):
+ """Go to the next cell of lines"""
+ cursor = self.textCursor()
+ cursor.movePosition(QTextCursor.NextBlock)
+ cur_pos = prev_pos = cursor.position()
+ while not self.is_cell_separator(cursor):
+ # Moving to the next code cell
+ cursor.movePosition(QTextCursor.NextBlock)
+ prev_pos = cur_pos
+ cur_pos = cursor.position()
+ if cur_pos == prev_pos:
+ return
+ self.setTextCursor(cursor)
+
+ def go_to_previous_cell(self):
+ """Go to the previous cell of lines"""
+ cursor = self.textCursor()
+ cur_pos = prev_pos = cursor.position()
+
+ if self.is_cell_separator(cursor):
+ # Move to the previous cell
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ cur_pos = prev_pos = cursor.position()
+
+ while not self.is_cell_separator(cursor):
+ # Move to the previous cell or the beginning of the current cell
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ prev_pos = cur_pos
+ cur_pos = cursor.position()
+ if cur_pos == prev_pos:
+ return
+
+ self.setTextCursor(cursor)
+
+ def get_line_count(self):
+ """Return document total line number"""
+ return self.blockCount()
+
+ def __save_selection(self):
+ """Save current cursor selection and return position bounds"""
+ cursor = self.textCursor()
+ return cursor.selectionStart(), cursor.selectionEnd()
+
+ def __restore_selection(self, start_pos, end_pos):
+ """Restore cursor selection from position bounds"""
+ cursor = self.textCursor()
+ cursor.setPosition(start_pos)
+ cursor.setPosition(end_pos, QTextCursor.KeepAnchor)
+ self.setTextCursor(cursor)
+
+ def __duplicate_line_or_selection(self, after_current_line=True):
+ """Duplicate current line or selected text"""
+ cursor = self.textCursor()
+ cursor.beginEditBlock()
+ start_pos, end_pos = self.__save_selection()
+ if to_text_string(cursor.selectedText()):
+ cursor.setPosition(end_pos)
+ # Check if end_pos is at the start of a block: if so, starting
+ # changes from the previous block
+ cursor.movePosition(QTextCursor.StartOfBlock,
+ QTextCursor.KeepAnchor)
+ if not to_text_string(cursor.selectedText()):
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ end_pos = cursor.position()
+
+ cursor.setPosition(start_pos)
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ while cursor.position() <= end_pos:
+ cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor)
+ if cursor.atEnd():
+ cursor_temp = QTextCursor(cursor)
+ cursor_temp.clearSelection()
+ cursor_temp.insertText(self.get_line_separator())
+ break
+ cursor.movePosition(QTextCursor.NextBlock, QTextCursor.KeepAnchor)
+ text = cursor.selectedText()
+ cursor.clearSelection()
+
+ if not after_current_line:
+ # Moving cursor before current line/selected text
+ cursor.setPosition(start_pos)
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ start_pos += len(text)
+ end_pos += len(text)
+
+ cursor.insertText(text)
+ cursor.endEditBlock()
+ self.setTextCursor(cursor)
+ self.__restore_selection(start_pos, end_pos)
+
+ def duplicate_line(self):
+ """
+ Duplicate current line or selected text
+ Paste the duplicated text *after* the current line/selected text
+ """
+ self.__duplicate_line_or_selection(after_current_line=True)
+
+ def copy_line(self):
+ """
+ Copy current line or selected text
+ Paste the duplicated text *before* the current line/selected text
+ """
+ self.__duplicate_line_or_selection(after_current_line=False)
+
+ def __move_line_or_selection(self, after_current_line=True):
+ """Move current line or selected text"""
+ cursor = self.textCursor()
+ cursor.beginEditBlock()
+ start_pos, end_pos = self.__save_selection()
+ last_line = False
+
+ # ------ Select text
+
+ # Get selection start location
+ cursor.setPosition(start_pos)
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ start_pos = cursor.position()
+
+ # Get selection end location
+ cursor.setPosition(end_pos)
+ if not cursor.atBlockStart() or end_pos == start_pos:
+ cursor.movePosition(QTextCursor.EndOfBlock)
+ cursor.movePosition(QTextCursor.NextBlock)
+ end_pos = cursor.position()
+
+ # Check if selection ends on the last line of the document
+ if cursor.atEnd():
+ if not cursor.atBlockStart() or end_pos == start_pos:
+ last_line = True
+
+ # ------ Stop if at document boundary
+
+ cursor.setPosition(start_pos)
+ if cursor.atStart() and not after_current_line:
+ # Stop if selection is already at top of the file while moving up
+ cursor.endEditBlock()
+ self.setTextCursor(cursor)
+ self.__restore_selection(start_pos, end_pos)
+ return
+
+ cursor.setPosition(end_pos, QTextCursor.KeepAnchor)
+ if last_line and after_current_line:
+ # Stop if selection is already at end of the file while moving down
+ cursor.endEditBlock()
+ self.setTextCursor(cursor)
+ self.__restore_selection(start_pos, end_pos)
+ return
+
+ # ------ Move text
+
+ sel_text = to_text_string(cursor.selectedText())
+ cursor.removeSelectedText()
+
+
+ if after_current_line:
+ # Shift selection down
+ text = to_text_string(cursor.block().text())
+ sel_text = os.linesep + sel_text[0:-1] # Move linesep at the start
+ cursor.movePosition(QTextCursor.EndOfBlock)
+ start_pos += len(text)+1
+ end_pos += len(text)
+ if not cursor.atEnd():
+ end_pos += 1
+ else:
+ # Shift selection up
+ if last_line:
+ # Remove the last linesep and add it to the selected text
+ cursor.deletePreviousChar()
+ sel_text = sel_text + os.linesep
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ end_pos += 1
+ else:
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ text = to_text_string(cursor.block().text())
+ start_pos -= len(text)+1
+ end_pos -= len(text)+1
+
+ cursor.insertText(sel_text)
+
+ cursor.endEditBlock()
+ self.setTextCursor(cursor)
+ self.__restore_selection(start_pos, end_pos)
+
+ def move_line_up(self):
+ """Move up current line or selected text"""
+ self.__move_line_or_selection(after_current_line=False)
+
+ def move_line_down(self):
+ """Move down current line or selected text"""
+ self.__move_line_or_selection(after_current_line=True)
+
+ def go_to_new_line(self):
+ """Go to the end of the current line and create a new line"""
+ self.stdkey_end(False, False)
+ self.insert_text(self.get_line_separator())
+
+ def extend_selection_to_complete_lines(self):
+ """Extend current selection to complete lines"""
+ cursor = self.textCursor()
+ start_pos, end_pos = cursor.selectionStart(), cursor.selectionEnd()
+ cursor.setPosition(start_pos)
+ cursor.setPosition(end_pos, QTextCursor.KeepAnchor)
+ if cursor.atBlockStart():
+ cursor.movePosition(QTextCursor.PreviousBlock,
+ QTextCursor.KeepAnchor)
+ cursor.movePosition(QTextCursor.EndOfBlock,
+ QTextCursor.KeepAnchor)
+ self.setTextCursor(cursor)
+
+ def delete_line(self):
+ """Delete current line."""
+ cursor = self.textCursor()
+ if self.has_selected_text():
+ self.extend_selection_to_complete_lines()
+ start_pos, end_pos = cursor.selectionStart(), cursor.selectionEnd()
+ cursor.setPosition(start_pos)
+ else:
+ start_pos = end_pos = cursor.position()
+ cursor.beginEditBlock()
+ cursor.setPosition(start_pos)
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ while cursor.position() <= end_pos:
+ cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor)
+ if cursor.atEnd():
+ break
+ cursor.movePosition(QTextCursor.NextBlock, QTextCursor.KeepAnchor)
+ cursor.removeSelectedText()
+ cursor.endEditBlock()
+ self.ensureCursorVisible()
+ self.document_did_change()
+
+ def set_selection(self, start, end):
+ cursor = self.textCursor()
+ cursor.setPosition(start)
+ cursor.setPosition(end, QTextCursor.KeepAnchor)
+ self.setTextCursor(cursor)
+
+ def truncate_selection(self, position_from):
+ """Unselect read-only parts in shell, like prompt"""
+ position_from = self.get_position(position_from)
+ cursor = self.textCursor()
+ start, end = cursor.selectionStart(), cursor.selectionEnd()
+ if start < end:
+ start = max([position_from, start])
+ else:
+ end = max([position_from, end])
+ self.set_selection(start, end)
+
+ def restrict_cursor_position(self, position_from, position_to):
+ """In shell, avoid editing text except between prompt and EOF"""
+ position_from = self.get_position(position_from)
+ position_to = self.get_position(position_to)
+ cursor = self.textCursor()
+ cursor_position = cursor.position()
+ if cursor_position < position_from or cursor_position > position_to:
+ self.set_cursor_position(position_to)
+
+ #------Code completion / Calltips
+ def hide_tooltip_if_necessary(self, key):
+ """Hide calltip when necessary"""
+ try:
+ calltip_char = self.get_character(self.calltip_position)
+ before = self.is_cursor_before(self.calltip_position,
+ char_offset=1)
+ other = key in (Qt.Key_ParenRight, Qt.Key_Period, Qt.Key_Tab)
+ if calltip_char not in ('?', '(') or before or other:
+ QToolTip.hideText()
+ except (IndexError, TypeError):
+ QToolTip.hideText()
+
+ def select_completion_list(self):
+ """Completion list is active, Enter was just pressed"""
+ self.completion_widget.item_selected()
+
+ def insert_completion(self, text, completion_position):
+ if text:
+ # Get word on the left of the cursor.
+ result = self.get_current_word_and_position(completion=True)
+ cursor = self.textCursor()
+ if result is not None:
+ current_text, start_position = result
+ end_position = start_position + len(current_text)
+ # Check if the completion position is in the expected range
+ if not start_position <= completion_position <= end_position:
+ return
+ cursor.setPosition(start_position)
+ # Remove the word under the cursor
+ cursor.setPosition(end_position,
+ QTextCursor.KeepAnchor)
+ cursor.removeSelectedText()
+ self.setTextCursor(cursor)
+ else:
+ # Check if we are in the correct position
+ if cursor.position() != completion_position:
+ return
+ # Add text
+ self.insert_text(text)
+ self.document_did_change()
+
+ def is_completion_widget_visible(self):
+ """Return True is completion list widget is visible"""
+ return self.completion_widget.isVisible()
+
+ #------Standard keys
+ def stdkey_clear(self):
+ if not self.has_selected_text():
+ self.moveCursor(QTextCursor.NextCharacter, QTextCursor.KeepAnchor)
+ self.remove_selected_text()
+
+ def stdkey_backspace(self):
+ if not self.has_selected_text():
+ self.moveCursor(QTextCursor.PreviousCharacter,
+ QTextCursor.KeepAnchor)
+ self.remove_selected_text()
+
+ def __get_move_mode(self, shift):
+ return QTextCursor.KeepAnchor if shift else QTextCursor.MoveAnchor
+
+ def stdkey_up(self, shift):
+ self.moveCursor(QTextCursor.Up, self.__get_move_mode(shift))
+
+ def stdkey_down(self, shift):
+ self.moveCursor(QTextCursor.Down, self.__get_move_mode(shift))
+
+ def stdkey_tab(self):
+ self.insert_text(self.indent_chars)
+
+ def stdkey_home(self, shift, ctrl, prompt_pos=None):
+ """Smart HOME feature: cursor is first moved at
+ indentation position, then at the start of the line"""
+ move_mode = self.__get_move_mode(shift)
+ if ctrl:
+ self.moveCursor(QTextCursor.Start, move_mode)
+ else:
+ cursor = self.textCursor()
+ if prompt_pos is None:
+ start_position = self.get_position('sol')
+ else:
+ start_position = self.get_position(prompt_pos)
+ text = self.get_text(start_position, 'eol')
+ indent_pos = start_position+len(text)-len(text.lstrip())
+ if cursor.position() != indent_pos:
+ cursor.setPosition(indent_pos, move_mode)
+ else:
+ cursor.setPosition(start_position, move_mode)
+ self.setTextCursor(cursor)
+
+ def stdkey_end(self, shift, ctrl):
+ move_mode = self.__get_move_mode(shift)
+ if ctrl:
+ self.moveCursor(QTextCursor.End, move_mode)
+ else:
+ self.moveCursor(QTextCursor.EndOfBlock, move_mode)
+
+ def stdkey_pageup(self):
+ pass
+
+ def stdkey_pagedown(self):
+ pass
+
+ def stdkey_escape(self):
+ pass
+
+
+ #----Qt Events
+ def mousePressEvent(self, event):
+ """Reimplement Qt method"""
+ if sys.platform.startswith('linux') and event.button() == Qt.MidButton:
+ self.calltip_widget.hide()
+ self.setFocus()
+ event = QMouseEvent(QEvent.MouseButtonPress, event.pos(),
+ Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)
+ QPlainTextEdit.mousePressEvent(self, event)
+ QPlainTextEdit.mouseReleaseEvent(self, event)
+ # Send selection text to clipboard to be able to use
+ # the paste method and avoid the strange Issue 1445
+ # NOTE: This issue seems a focusing problem but it
+ # seems really hard to track
+ mode_clip = QClipboard.Clipboard
+ mode_sel = QClipboard.Selection
+ text_clip = QApplication.clipboard().text(mode=mode_clip)
+ text_sel = QApplication.clipboard().text(mode=mode_sel)
+ QApplication.clipboard().setText(text_sel, mode=mode_clip)
+ self.paste()
+ QApplication.clipboard().setText(text_clip, mode=mode_clip)
+ else:
+ self.calltip_widget.hide()
+ QPlainTextEdit.mousePressEvent(self, event)
+
+ def focusInEvent(self, event):
+ """Reimplemented to handle focus"""
+ self.focus_changed.emit()
+ self.focus_in.emit()
+ self.highlight_current_cell()
+ QPlainTextEdit.focusInEvent(self, event)
+
+ def focusOutEvent(self, event):
+ """Reimplemented to handle focus"""
+ self.focus_changed.emit()
+ QPlainTextEdit.focusOutEvent(self, event)
+
+ def wheelEvent(self, event):
+ """Reimplemented to emit zoom in/out signals when Ctrl is pressed"""
+ # This feature is disabled on MacOS, see Issue 1510
+ if sys.platform != 'darwin':
+ if event.modifiers() & Qt.ControlModifier:
+ if hasattr(event, 'angleDelta'):
+ if event.angleDelta().y() < 0:
+ self.zoom_out.emit()
+ elif event.angleDelta().y() > 0:
+ self.zoom_in.emit()
+ elif hasattr(event, 'delta'):
+ if event.delta() < 0:
+ self.zoom_out.emit()
+ elif event.delta() > 0:
+ self.zoom_in.emit()
+ return
+ QPlainTextEdit.wheelEvent(self, event)
+ self.highlight_current_cell()
diff --git a/spyder/plugins/editor/widgets/codeeditor.py b/spyder/plugins/editor/widgets/codeeditor.py
new file mode 100644
index 00000000000..bc1e985b921
--- /dev/null
+++ b/spyder/plugins/editor/widgets/codeeditor.py
@@ -0,0 +1,3785 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+Editor widget based on QtGui.QPlainTextEdit
+"""
+
+# TODO: Try to separate this module from spyder to create a self
+# consistent editor module (Qt source code and shell widgets library)
+
+# %% This line is for cell execution testing
+# pylint: disable=C0103
+# pylint: disable=R0903
+# pylint: disable=R0911
+# pylint: disable=R0201
+
+# Standard library imports
+from __future__ import division, print_function
+
+import logging
+import os.path as osp
+import re
+import sre_constants
+import sys
+import time
+from unicodedata import category
+
+# Third party imports
+from qtpy.compat import to_qvariant
+from qtpy.QtCore import QRegExp, Qt, QTimer, QUrl, Signal, Slot, QEvent
+from qtpy.QtGui import (QColor, QCursor, QFont, QIntValidator,
+ QKeySequence, QPaintEvent, QPainter, QMouseEvent,
+ QTextCharFormat, QTextCursor, QDesktopServices,
+ QKeyEvent, QTextDocument, QTextFormat, QTextOption)
+from qtpy.QtPrintSupport import QPrinter
+from qtpy.QtWidgets import (QApplication, QDialog, QDialogButtonBox,
+ QGridLayout, QHBoxLayout, QLabel,
+ QLineEdit, QMenu, QMessageBox, QSplitter,
+ QToolTip, QVBoxLayout, QScrollBar)
+from spyder_kernels.utils.dochelpers import getobj
+
+# %% This line is for cell execution testing
+
+# Local imports
+from spyder.api.panel import Panel
+from spyder.config.base import _, get_debug_level, running_under_pytest
+from spyder.config.gui import get_shortcut, config_shortcut
+from spyder.config.main import CONF
+from spyder.plugins.editor.api.decoration import TextDecoration
+from spyder.plugins.editor.extensions import (CloseBracketsExtension,
+ CloseQuotesExtension,
+ DocstringWriterExtension,
+ QMenuOnlyForEnter,
+ EditorExtensionsManager)
+from spyder.plugins.editor.lsp import (LSPRequestTypes, TextDocumentSyncKind,
+ DiagnosticSeverity)
+from spyder.plugins.editor.panels import (ClassFunctionDropdown,
+ DebuggerPanel, EdgeLine,
+ FoldingPanel, IndentationGuide,
+ LineNumberArea, PanelsManager,
+ ScrollFlagArea)
+from spyder.plugins.editor.utils.editor import TextHelper, BlockUserData
+from spyder.plugins.editor.utils.debugger import DebuggerManager
+from spyder.plugins.editor.utils.folding import IndentFoldDetector
+from spyder.plugins.editor.utils.kill_ring import QtKillRing
+from spyder.plugins.editor.utils.languages import ALL_LANGUAGES, CELL_LANGUAGES
+from spyder.plugins.editor.utils.lsp import request, handles, class_register
+from spyder.plugins.editor.widgets.base import TextEditBaseWidget
+from spyder.plugins.outlineexplorer.languages import PythonCFM
+from spyder.py3compat import PY2, to_text_string
+from spyder.utils import encoding, programs, sourcecode
+from spyder.utils import icon_manager as ima
+from spyder.utils import syntaxhighlighters as sh
+from spyder.utils.qthelpers import (add_actions, create_action, file_uri,
+ mimedata2url)
+
+
+try:
+ import nbformat as nbformat
+ from nbconvert import PythonExporter as nbexporter
+except Exception:
+ nbformat = None # analysis:ignore
+
+
+logger = logging.getLogger(__name__)
+
+
+# %% This line is for cell execution testing
+def is_letter_or_number(char):
+ """Returns whether the specified unicode character is a letter or a number.
+ """
+ cat = category(char)
+ return cat.startswith('L') or cat.startswith('N')
+
+# =============================================================================
+# Go to line dialog box
+# =============================================================================
+class GoToLineDialog(QDialog):
+ def __init__(self, editor):
+ QDialog.__init__(self, editor, Qt.WindowTitleHint
+ | Qt.WindowCloseButtonHint)
+
+ # Destroying the C++ object right after closing the dialog box,
+ # otherwise it may be garbage-collected in another QThread
+ # (e.g. the editor's analysis thread in Spyder), thus leading to
+ # a segmentation fault on UNIX or an application crash on Windows
+ self.setAttribute(Qt.WA_DeleteOnClose)
+
+ self.lineno = None
+ self.editor = editor
+
+ self.setWindowTitle(_("Editor"))
+ self.setModal(True)
+
+ label = QLabel(_("Go to line:"))
+ self.lineedit = QLineEdit()
+ validator = QIntValidator(self.lineedit)
+ validator.setRange(1, editor.get_line_count())
+ self.lineedit.setValidator(validator)
+ self.lineedit.textChanged.connect(self.text_has_changed)
+ cl_label = QLabel(_("Current line:"))
+ cl_label_v = QLabel("%d" % editor.get_cursor_line_number())
+ last_label = QLabel(_("Line count:"))
+ last_label_v = QLabel("%d" % editor.get_line_count())
+
+ glayout = QGridLayout()
+ glayout.addWidget(label, 0, 0, Qt.AlignVCenter|Qt.AlignRight)
+ glayout.addWidget(self.lineedit, 0, 1, Qt.AlignVCenter)
+ glayout.addWidget(cl_label, 1, 0, Qt.AlignVCenter|Qt.AlignRight)
+ glayout.addWidget(cl_label_v, 1, 1, Qt.AlignVCenter)
+ glayout.addWidget(last_label, 2, 0, Qt.AlignVCenter|Qt.AlignRight)
+ glayout.addWidget(last_label_v, 2, 1, Qt.AlignVCenter)
+
+ bbox = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel,
+ Qt.Vertical, self)
+ bbox.accepted.connect(self.accept)
+ bbox.rejected.connect(self.reject)
+ btnlayout = QVBoxLayout()
+ btnlayout.addWidget(bbox)
+ btnlayout.addStretch(1)
+
+ ok_button = bbox.button(QDialogButtonBox.Ok)
+ ok_button.setEnabled(False)
+ self.lineedit.textChanged.connect(
+ lambda text: ok_button.setEnabled(len(text) > 0))
+
+ layout = QHBoxLayout()
+ layout.addLayout(glayout)
+ layout.addLayout(btnlayout)
+ self.setLayout(layout)
+
+ self.lineedit.setFocus()
+
+ def text_has_changed(self, text):
+ """Line edit's text has changed"""
+ text = to_text_string(text)
+ if text:
+ self.lineno = int(text)
+ else:
+ self.lineno = None
+
+ def get_line_number(self):
+ """Return line number"""
+ # It is import to avoid accessing Qt C++ object as it has probably
+ # already been destroyed, due to the Qt.WA_DeleteOnClose attribute
+ return self.lineno
+
+
+#===============================================================================
+# CodeEditor widget
+#===============================================================================
+def get_file_language(filename, text=None):
+ """Get file language from filename"""
+ ext = osp.splitext(filename)[1]
+ if ext.startswith('.'):
+ ext = ext[1:] # file extension with leading dot
+ language = ext
+ if not ext:
+ if text is None:
+ text, _enc = encoding.read(filename)
+ for line in text.splitlines():
+ if not line.strip():
+ continue
+ if line.startswith('#!'):
+ shebang = line[2:]
+ if 'python' in shebang:
+ language = 'python'
+ else:
+ break
+ return language
+
+
+@class_register
+class CodeEditor(TextEditBaseWidget):
+ """Source Code Editor Widget based exclusively on Qt"""
+
+ LANGUAGES = {'Python': (sh.PythonSH, '#', PythonCFM),
+ 'Cython': (sh.CythonSH, '#', PythonCFM),
+ 'Fortran77': (sh.Fortran77SH, 'c', None),
+ 'Fortran': (sh.FortranSH, '!', None),
+ 'Idl': (sh.IdlSH, ';', None),
+ 'Diff': (sh.DiffSH, '', None),
+ 'GetText': (sh.GetTextSH, '#', None),
+ 'Nsis': (sh.NsisSH, '#', None),
+ 'Html': (sh.HtmlSH, '', None),
+ 'Yaml': (sh.YamlSH, '#', None),
+ 'Cpp': (sh.CppSH, '//', None),
+ 'OpenCL': (sh.OpenCLSH, '//', None),
+ 'Enaml': (sh.EnamlSH, '#', PythonCFM),
+ 'Markdown': (sh.MarkdownSH, '#', None),
+ }
+
+ TAB_ALWAYS_INDENTS = ('py', 'pyw', 'python', 'c', 'cpp', 'cl', 'h')
+
+ # Custom signal to be emitted upon completion of the editor's paintEvent
+ painted = Signal(QPaintEvent)
+
+ # To have these attrs when early viewportEvent's are triggered
+ edge_line = None
+ indent_guides = None
+
+ sig_breakpoints_changed = Signal()
+ sig_debug_stop = Signal((int,), ())
+ sig_debug_start = Signal()
+ sig_breakpoints_saved = Signal()
+ sig_filename_changed = Signal(str)
+ sig_bookmarks_changed = Signal()
+ get_completions = Signal(bool)
+ go_to_definition = Signal(str, int, int)
+ sig_show_object_info = Signal(int)
+ sig_run_selection = Signal()
+ sig_run_cell_and_advance = Signal()
+ sig_run_cell = Signal()
+ sig_re_run_last_cell = Signal()
+ go_to_definition_regex = Signal(str, int, int)
+ sig_cursor_position_changed = Signal(int, int)
+ sig_new_file = Signal(str)
+
+ #: Signal emitted when the editor loses focus
+ sig_focus_changed = Signal()
+
+ #: Signal emitted when a key is pressed
+ sig_key_pressed = Signal(QKeyEvent)
+
+ #: Signal emitted when a key is released
+ sig_key_released = Signal(QKeyEvent)
+
+ #: Signal emitted when the alt key is pressed and the left button of the
+ # mouse is clicked
+ sig_alt_left_mouse_pressed = Signal(QMouseEvent)
+
+ #: Signal emitted when the alt key is pressed and the cursor moves over
+ # the editor
+ sig_alt_mouse_moved = Signal(QMouseEvent)
+
+ #: Signal emitted when the cursor leaves the editor
+ sig_leave_out = Signal()
+
+ #: Signal emitted when the flags need to be updated in the scrollflagarea
+ sig_flags_changed = Signal()
+
+ #: Signal emitted when a new text is set on the widget
+ new_text_set = Signal()
+
+ # -- LSP signals
+ #: Signal emitted when an LSP request is sent to the LSP manager
+ sig_perform_lsp_request = Signal(str, str, dict)
+
+ #: Signal emitted when a response is received from an LSP server
+ # For now it's only used on tests, but it could be used to track
+ # and profile LSP diagnostics.
+ lsp_response_signal = Signal(str, dict)
+
+ #: Signal to display object information on the Help plugin
+ sig_display_object_info = Signal(str, bool)
+
+ #: Signal only used for tests
+ # TODO: Remove it!
+ sig_signature_invoked = Signal(dict)
+
+ #: Signal emmited when processing code analysis warnings is finished
+ sig_process_code_analysis = Signal()
+
+ # Used for testing. When the mouse moves with Ctrl/Cmd pressed and
+ # a URI is found, this signal is emmited
+ sig_uri_found = Signal(str)
+
+ # Used for testing. When the mouse moves with Ctrl/Cmd pressed and
+ # the mouse left button is pressed, this signal is emmited
+ sig_go_to_uri = Signal(str)
+
+ def __init__(self, parent=None):
+ TextEditBaseWidget.__init__(self, parent)
+
+ self.setFocusPolicy(Qt.StrongFocus)
+
+ # Caret (text cursor)
+ self.setCursorWidth( CONF.get('main', 'cursor/width') )
+
+ self.text_helper = TextHelper(self)
+
+ self._panels = PanelsManager(self)
+
+ # Mouse moving timer / Hover hints handling
+ # See: mouseMoveEvent
+ self.tooltip_widget.sig_help_requested.connect(
+ self.show_object_info)
+ self._last_point = None
+ self._last_hover_word = None
+ self._last_hover_cursor = None
+ self._timer_mouse_moving = QTimer(self)
+ self._timer_mouse_moving.setInterval(350)
+ self._timer_mouse_moving.timeout.connect(lambda: self._handle_hover())
+
+ # Goto uri
+ self._last_hover_uri = None
+
+ # 79-col edge line
+ self.edge_line = self.panels.register(EdgeLine(self),
+ Panel.Position.FLOATING)
+
+ # indent guides
+ self.indent_guides = self.panels.register(IndentationGuide(self),
+ Panel.Position.FLOATING)
+ # Blanks enabled
+ self.blanks_enabled = False
+
+ # Scrolling past the end of the document
+ self.scrollpastend_enabled = False
+
+ self.background = QColor('white')
+
+ # Folding
+ self.panels.register(FoldingPanel())
+
+ # Debugger panel (Breakpoints)
+ self.debugger = DebuggerManager(self)
+ self.panels.register(DebuggerPanel())
+ # Update breakpoints if the number of lines in the file changes
+ self.blockCountChanged.connect(self.debugger.update_breakpoints)
+
+ # Line number area management
+ self.linenumberarea = self.panels.register(LineNumberArea(self))
+
+ # Class and Method/Function Dropdowns
+ self.classfuncdropdown = self.panels.register(
+ ClassFunctionDropdown(self),
+ Panel.Position.TOP,
+ )
+
+ # Colors to be defined in _apply_highlighter_color_scheme()
+ # Currentcell color and current line color are defined in base.py
+ self.occurrence_color = None
+ self.ctrl_click_color = None
+ self.sideareas_color = None
+ self.matched_p_color = None
+ self.unmatched_p_color = None
+ self.normal_color = None
+ self.comment_color = None
+
+ # --- Syntax highlight entrypoint ---
+ #
+ # - if set, self.highlighter is responsible for
+ # - coloring raw text data inside editor on load
+ # - coloring text data when editor is cloned
+ # - updating document highlight on line edits
+ # - providing color palette (scheme) for the editor
+ # - providing data for Outliner
+ # - self.highlighter is not responsible for
+ # - background highlight for current line
+ # - background highlight for search / current line occurrences
+
+ self.highlighter_class = sh.TextSH
+ self.highlighter = None
+ ccs = 'Spyder'
+ if ccs not in sh.COLOR_SCHEME_NAMES:
+ ccs = sh.COLOR_SCHEME_NAMES[0]
+ self.color_scheme = ccs
+
+ self.highlight_current_line_enabled = False
+
+ # Vertical scrollbar
+ # This is required to avoid a "RuntimeError: no access to protected
+ # functions or signals for objects not created from Python" in
+ # Linux Ubuntu. See PR #5215.
+ self.setVerticalScrollBar(QScrollBar())
+
+ # Scrollbar flag area
+ self.scrollflagarea = self.panels.register(ScrollFlagArea(self),
+ Panel.Position.RIGHT)
+ self.scrollflagarea.hide()
+ self.warning_color = "#FFAD07"
+ self.error_color = "#EA2B0E"
+ self.todo_color = "#B4D4F3"
+ self.breakpoint_color = "#30E62E"
+
+ self.panels.refresh()
+
+ self.document_id = id(self)
+
+ # Indicate occurrences of the selected word
+ self.cursorPositionChanged.connect(self.__cursor_position_changed)
+ self.__find_first_pos = None
+ self.__find_flags = None
+
+ self.language = None
+ self.supported_language = False
+ self.supported_cell_language = False
+ self.classfunc_match = None
+ self.comment_string = None
+ self._kill_ring = QtKillRing(self)
+
+ # Block user data
+ self.blockCountChanged.connect(self.update_bookmarks)
+
+ # Highlight using Pygments highlighter timer
+ # ---------------------------------------------------------------------
+ # For files that use the PygmentsSH we parse the full file inside
+ # the highlighter in order to generate the correct coloring.
+ self.timer_syntax_highlight = QTimer(self)
+ self.timer_syntax_highlight.setSingleShot(True)
+ # We wait 300 ms to trigger a new coloring as this value is a good
+ # proxy for estimating when an user has stopped typing
+ self.timer_syntax_highlight.setInterval(300)
+ self.timer_syntax_highlight.timeout.connect(
+ self.run_pygments_highlighter)
+
+ # Mark occurrences timer
+ self.occurrence_highlighting = None
+ self.occurrence_timer = QTimer(self)
+ self.occurrence_timer.setSingleShot(True)
+ self.occurrence_timer.setInterval(1500)
+ self.occurrence_timer.timeout.connect(self.__mark_occurrences)
+ self.occurrences = []
+ self.occurrence_color = QColor(Qt.yellow).lighter(160)
+
+ # Mark found results
+ self.textChanged.connect(self.__text_has_changed)
+ self.found_results = []
+ self.found_results_color = QColor(Qt.magenta).lighter(180)
+
+ # Docstring
+ self.writer_docstring = DocstringWriterExtension(self)
+
+ # Context menu
+ self.gotodef_action = None
+ self.setup_context_menu()
+
+ # Tab key behavior
+ self.tab_indents = None
+ self.tab_mode = True # see CodeEditor.set_tab_mode
+
+ # Intelligent backspace mode
+ self.intelligent_backspace = True
+
+ self.close_parentheses_enabled = True
+ self.close_quotes_enabled = False
+ self.add_colons_enabled = True
+ self.auto_unindent_enabled = True
+
+ # Mouse tracking
+ self.setMouseTracking(True)
+ self.__cursor_changed = False
+ self.ctrl_click_color = QColor(Qt.blue)
+
+ self.bookmarks = self.get_bookmarks()
+
+ # Keyboard shortcuts
+ self.shortcuts = self.create_shortcuts()
+
+ # Code editor
+ self.__visible_blocks = [] # Visible blocks, update with repaint
+ self.painted.connect(self._draw_editor_cell_divider)
+
+ self.verticalScrollBar().valueChanged.connect(
+ lambda value: self.rehighlight_cells())
+
+ self.oe_proxy = None
+
+ # Line stripping
+ self.last_change_position = None
+ self.last_position = None
+ self.last_auto_indent = None
+ self.skip_rstrip = False
+ self.strip_trailing_spaces_on_modify = True
+
+ # Language Server
+ self.lsp_requests = {}
+ self.document_opened = False
+ self.filename = None
+ self.lsp_ready = False
+ self.text_version = 0
+ self.save_include_text = True
+ self.open_close_notifications = True
+ self.sync_mode = TextDocumentSyncKind.FULL
+ self.will_save_notify = False
+ self.will_save_until_notify = False
+ self.enable_hover = False
+ self.auto_completion_characters = []
+ self.signature_completion_characters = []
+ self.go_to_definition_enabled = False
+ self.find_references_enabled = False
+ self.highlight_enabled = False
+ self.formatting_enabled = False
+ self.range_formatting_enabled = False
+ self.formatting_characters = []
+ self.rename_support = False
+ self.completion_args = None
+
+ # Editor Extensions
+ self.editor_extensions = EditorExtensionsManager(self)
+
+ self.editor_extensions.add(CloseQuotesExtension())
+ self.editor_extensions.add(CloseBracketsExtension())
+
+ # --- Helper private methods
+ # ------------------------------------------------------------------------
+
+ # --- Hover/Hints
+ def _should_display_hover(self, point):
+ """Check if a hover hint should be displayed:"""
+ return (CONF.get('lsp-server', 'enable_hover_hints') and point
+ and self.get_word_at(point))
+
+ def _handle_hover(self):
+ """Handle hover hint trigger after delay."""
+ self._timer_mouse_moving.stop()
+ pos = self._last_point
+
+ # These are textual characters but should not trigger a completion
+ # FIXME: update per language
+ ignore_chars = ['(', ')', '.']
+
+ if self._should_display_hover(pos):
+ uri, cursor = self.get_uri_at(pos)
+ text = self.get_word_at(pos)
+ if uri:
+ ctrl_text = 'Cmd' if sys.platform == "darwin" else 'Ctrl'
+
+ if uri.startswith('file://'):
+ hint_text = ctrl_text + ' + click to open file'
+ elif uri.startswith('mailto:'):
+ hint_text = ctrl_text + ' + click to send email'
+ elif uri.startswith('http'):
+ hint_text = ctrl_text + ' + click to open url'
+ else:
+ hint_text = ctrl_text + ' + click to open'
+
+ hint_text = ' {} '.format(hint_text)
+
+ self.show_tooltip(text=hint_text, at_point=pos)
+ return
+
+ cursor = self.cursorForPosition(pos)
+ line, col = cursor.blockNumber(), cursor.columnNumber()
+ self._last_point = pos
+ if text and self._last_hover_word != text:
+ if all(char not in text for char in ignore_chars):
+ self._last_hover_word = text
+ self.request_hover(line, col)
+ else:
+ self.hide_tooltip()
+ else:
+ self.hide_tooltip()
+
+ def blockuserdata_list(self):
+ """Get the list of all user data in document."""
+ block = self.document().firstBlock()
+ while block.isValid():
+ data = block.userData()
+ if data:
+ yield data
+ block = block.next()
+
+ def outlineexplorer_data_list(self):
+ """Get the list of all user data in document."""
+ for data in self.blockuserdata_list():
+ if data.oedata:
+ yield data.oedata
+
+ # ---- Keyboard Shortcuts
+
+ def create_cursor_callback(self, attr):
+ """Make a callback for cursor move event type, (e.g. "Start")"""
+ def cursor_move_event():
+ cursor = self.textCursor()
+ move_type = getattr(QTextCursor, attr)
+ cursor.movePosition(move_type)
+ self.setTextCursor(cursor)
+ return cursor_move_event
+
+ def create_shortcuts(self):
+ """Create the local shortcuts for the CodeEditor."""
+ shortcut_context_name_callbacks = (
+ ('editor', 'code completion', self.do_completion),
+ ('editor', 'duplicate line', self.duplicate_line),
+ ('editor', 'copy line', self.copy_line),
+ ('editor', 'delete line', self.delete_line),
+ ('editor', 'move line up', self.move_line_up),
+ ('editor', 'move line down', self.move_line_down),
+ ('editor', 'go to new line', self.go_to_new_line),
+ ('editor', 'go to definition', self.go_to_definition_from_cursor),
+ ('editor', 'toggle comment', self.toggle_comment),
+ ('editor', 'blockcomment', self.blockcomment),
+ ('editor', 'unblockcomment', self.unblockcomment),
+ ('editor', 'transform to uppercase', self.transform_to_uppercase),
+ ('editor', 'transform to lowercase', self.transform_to_lowercase),
+ ('editor', 'indent', lambda: self.indent(force=True)),
+ ('editor', 'unindent', lambda: self.unindent(force=True)),
+ ('editor', 'start of line',
+ self.create_cursor_callback('StartOfLine')),
+ ('editor', 'end of line',
+ self.create_cursor_callback('EndOfLine')),
+ ('editor', 'previous line', self.create_cursor_callback('Up')),
+ ('editor', 'next line', self.create_cursor_callback('Down')),
+ ('editor', 'previous char', self.create_cursor_callback('Left')),
+ ('editor', 'next char', self.create_cursor_callback('Right')),
+ ('editor', 'previous word',
+ self.create_cursor_callback('PreviousWord')),
+ ('editor', 'next word', self.create_cursor_callback('NextWord')),
+ ('editor', 'kill to line end', self.kill_line_end),
+ ('editor', 'kill to line start', self.kill_line_start),
+ ('editor', 'yank', self._kill_ring.yank),
+ ('editor', 'rotate kill ring', self._kill_ring.rotate),
+ ('editor', 'kill previous word', self.kill_prev_word),
+ ('editor', 'kill next word', self.kill_next_word),
+ ('editor', 'start of document',
+ self.create_cursor_callback('Start')),
+ ('editor', 'end of document',
+ self.create_cursor_callback('End')),
+ ('editor', 'undo', self.undo),
+ ('editor', 'redo', self.redo),
+ ('editor', 'cut', self.cut),
+ ('editor', 'copy', self.copy),
+ ('editor', 'paste', self.paste),
+ ('editor', 'delete', self.delete),
+ ('editor', 'select all', self.selectAll),
+ ('editor', 'docstring',
+ self.writer_docstring.write_docstring_for_shortcut),
+ ('array_builder', 'enter array inline', self.enter_array_inline),
+ ('array_builder', 'enter array table', self.enter_array_table)
+ )
+
+ shortcuts = []
+ for context, name, callback in shortcut_context_name_callbacks:
+ shortcuts.append(
+ config_shortcut(
+ callback, context=context, name=name, parent=self))
+ return shortcuts
+
+ def get_shortcut_data(self):
+ """
+ Returns shortcut data, a list of tuples (shortcut, text, default)
+ shortcut (QShortcut or QAction instance)
+ text (string): action/shortcut description
+ default (string): default key sequence
+ """
+ return [sc.data for sc in self.shortcuts]
+
+ def closeEvent(self, event):
+ TextEditBaseWidget.closeEvent(self, event)
+
+ def get_document_id(self):
+ return self.document_id
+
+ def set_as_clone(self, editor):
+ """Set as clone editor"""
+ self.setDocument(editor.document())
+ self.document_id = editor.get_document_id()
+ self.highlighter = editor.highlighter
+ self.eol_chars = editor.eol_chars
+ self._apply_highlighter_color_scheme()
+
+ # ---- Widget setup and options
+ def toggle_wrap_mode(self, enable):
+ """Enable/disable wrap mode"""
+ self.set_wrap_mode('word' if enable else None)
+
+ def toggle_line_numbers(self, linenumbers=True, markers=False):
+ """Enable/disable line numbers."""
+ self.linenumberarea.setup_margins(linenumbers, markers)
+
+ @property
+ def panels(self):
+ """
+ Returns a reference to the
+ :class:`spyder.widgets.panels.managers.PanelsManager`
+ used to manage the collection of installed panels
+ """
+ return self._panels
+
+ def setup_editor(self,
+ linenumbers=True,
+ language=None,
+ markers=False,
+ font=None,
+ color_scheme=None,
+ wrap=False,
+ tab_mode=True,
+ strip_mode=False,
+ intelligent_backspace=True,
+ highlight_current_line=True,
+ highlight_current_cell=True,
+ occurrence_highlighting=True,
+ scrollflagarea=True,
+ edge_line=True,
+ edge_line_columns=(79,),
+ show_blanks=False,
+ close_parentheses=True,
+ close_quotes=False,
+ add_colons=True,
+ auto_unindent=True,
+ indent_chars=" "*4,
+ tab_stop_width_spaces=4,
+ cloned_from=None,
+ filename=None,
+ occurrence_timeout=1500,
+ show_class_func_dropdown=False,
+ indent_guides=False,
+ scroll_past_end=False,
+ debug_panel=True,
+ folding=True):
+
+ self.set_close_parentheses_enabled(close_parentheses)
+ self.set_close_quotes_enabled(close_quotes)
+ self.set_add_colons_enabled(add_colons)
+ self.set_auto_unindent_enabled(auto_unindent)
+ self.set_indent_chars(indent_chars)
+
+ # Show/hide the debug panel depending on the language and parameter
+ self.set_debug_panel(debug_panel, language)
+
+ # Show/hide folding panel depending on parameter
+ self.set_folding_panel(folding)
+
+ # Scrollbar flag area
+ self.scrollflagarea.set_enabled(scrollflagarea)
+
+ # Debugging
+ self.debugger.set_filename(filename)
+
+ # Edge line
+ self.edge_line.set_enabled(edge_line)
+ self.edge_line.set_columns(edge_line_columns)
+
+ # Indent guides
+ self.indent_guides.set_enabled(indent_guides)
+ if self.indent_chars == '\t':
+ self.indent_guides.set_indentation_width(self.tab_stop_width_spaces)
+ else:
+ self.indent_guides.set_indentation_width(len(self.indent_chars))
+
+ # Blanks
+ self.set_blanks_enabled(show_blanks)
+
+ # Scrolling past the end
+ self.set_scrollpastend_enabled(scroll_past_end)
+
+ # Line number area
+ if cloned_from:
+ self.setFont(font) # this is required for line numbers area
+ self.toggle_line_numbers(linenumbers, markers)
+
+ # Lexer
+ self.filename = filename
+ self.set_language(language, filename)
+
+ # Highlight current cell
+ self.set_highlight_current_cell(highlight_current_cell)
+
+ # Highlight current line
+ self.set_highlight_current_line(highlight_current_line)
+
+ # Occurrence highlighting
+ self.set_occurrence_highlighting(occurrence_highlighting)
+ self.set_occurrence_timeout(occurrence_timeout)
+
+ # Tab always indents (even when cursor is not at the begin of line)
+ self.set_tab_mode(tab_mode)
+
+ # Intelligent backspace
+ self.toggle_intelligent_backspace(intelligent_backspace)
+
+ if cloned_from is not None:
+ self.set_as_clone(cloned_from)
+ self.panels.refresh()
+ elif font is not None:
+ self.set_font(font, color_scheme)
+ elif color_scheme is not None:
+ self.set_color_scheme(color_scheme)
+
+ # Set tab spacing after font is set
+ self.set_tab_stop_width_spaces(tab_stop_width_spaces)
+
+ self.toggle_wrap_mode(wrap)
+
+ # Class/Function dropdown will be disabled if we're not in a Python file.
+ self.classfuncdropdown.setVisible(show_class_func_dropdown
+ and self.is_python_like())
+
+ self.set_strip_mode(strip_mode)
+
+ # --- Language Server Protocol methods -----------------------------------
+ # ------------------------------------------------------------------------
+ @Slot(str, dict)
+ def handle_response(self, method, params):
+ if method in self.handler_registry:
+ handler_name = self.handler_registry[method]
+ handler = getattr(self, handler_name)
+ handler(params)
+ # This signal is only used on tests.
+ # It could be used to track and profile LSP diagnostics.
+ self.lsp_response_signal.emit(method, params)
+
+ def emit_request(self, method, params, requires_response):
+ """Send request to LSP manager."""
+ params['requires_response'] = requires_response
+ params['response_codeeditor'] = self
+ self.sig_perform_lsp_request.emit(
+ self.language.lower(), method, params)
+
+ def log_lsp_handle_errors(self, message):
+ """
+ Log errors when handling LSP responses.
+
+ This works when debugging is on or off.
+ """
+ if get_debug_level() > 0:
+ # We log the error normally when running on debug mode.
+ logger.error(message, exc_info=True)
+ else:
+ # We need this because logger.error activates our error
+ # report dialog but it doesn't show the entire traceback
+ # there. So we intentionally leave an error in this call
+ # to get the entire stack info generated by it, which
+ # gives the info we need from users.
+ if PY2:
+ logger.error(message, exc_info=True)
+ print(message, file=sys.stderr)
+ else:
+ logger.error('%', 1, stack_info=True)
+
+ # ------------- LSP: Configuration and protocol start/end ----------------
+ def start_lsp_services(self, config):
+ """Start LSP integration if it wasn't done before."""
+ if not self.lsp_ready:
+ logger.debug("LSP available for: %s" % self.filename)
+ self.parse_lsp_config(config)
+ self.lsp_ready = True
+ self.document_did_open()
+
+ def stop_lsp_services(self):
+ self.lsp_ready = False
+
+ def parse_lsp_config(self, config):
+ """Parse and load LSP server editor capabilities."""
+ sync_options = config['textDocumentSync']
+ completion_options = config['completionProvider']
+ signature_options = config['signatureHelpProvider']
+ range_formatting_options = config['documentOnTypeFormattingProvider']
+ self.open_close_notifications = sync_options['openClose']
+ self.sync_mode = sync_options['change']
+ self.will_save_notify = sync_options['willSave']
+ self.will_save_until_notify = sync_options['willSaveWaitUntil']
+ self.save_include_text = sync_options['save']['includeText']
+ self.enable_hover = config['hoverProvider']
+ self.auto_completion_characters = (
+ completion_options['triggerCharacters'])
+ self.signature_completion_characters = (
+ signature_options['triggerCharacters'] + ['=']) # FIXME:
+ self.go_to_definition_enabled = config['definitionProvider']
+ self.find_references_enabled = config['referencesProvider']
+ self.highlight_enabled = config['documentHighlightProvider']
+ self.formatting_enabled = config['documentFormattingProvider']
+ self.range_formatting_enabled = (
+ config['documentRangeFormattingProvider'])
+ self.formatting_characters.append(
+ range_formatting_options['firstTriggerCharacter'])
+ self.formatting_characters += (
+ range_formatting_options.get('moreTriggerCharacter', []))
+
+ @request(method=LSPRequestTypes.DOCUMENT_DID_OPEN, requires_response=False)
+ def document_did_open(self):
+ """Send textDocument/didOpen request to the server."""
+ self.document_opened = True
+ params = {
+ 'file': self.filename,
+ 'language': self.language,
+ 'version': self.text_version,
+ 'text': self.toPlainText(),
+ 'codeeditor': self
+ }
+ return params
+
+ # ------------- LSP: Linting ---------------------------------------
+ @request(
+ method=LSPRequestTypes.DOCUMENT_DID_CHANGE, requires_response=False)
+ def document_did_change(self, text=None):
+ """Send textDocument/didChange request to the server."""
+ self.text_version += 1
+ params = {
+ 'file': self.filename,
+ 'version': self.text_version,
+ 'text': self.toPlainText()
+ }
+ return params
+
+ @handles(LSPRequestTypes.DOCUMENT_PUBLISH_DIAGNOSTICS)
+ def process_diagnostics(self, params):
+ """Handle linting response."""
+ try:
+ self.process_code_analysis(params['params'])
+ except Exception:
+ self.log_lsp_handle_errors("Error when processing linting")
+
+ # ------------- LSP: Completion ---------------------------------------
+ @request(method=LSPRequestTypes.DOCUMENT_COMPLETION)
+ def do_completion(self, automatic=False):
+ """Trigger completion."""
+ self.document_did_change('')
+ line, column = self.get_cursor_line_column()
+ params = {
+ 'file': self.filename,
+ 'line': line,
+ 'column': column
+ }
+ self.completion_args = (self.textCursor().position(), automatic)
+ return params
+
+ @handles(LSPRequestTypes.DOCUMENT_COMPLETION)
+ def process_completion(self, params):
+ """Handle completion response."""
+ args = self.completion_args
+ if args is None:
+ # This should not happen
+ return
+ self.completion_args = None
+ position, automatic = args
+ try:
+ completions = params['params']
+ if completions is not None and len(completions) > 0:
+ completion_list = sorted(completions,
+ key=lambda x: x['sortText'])
+ self.completion_widget.show_list(
+ completion_list, position, automatic)
+ except Exception:
+ self.log_lsp_handle_errors('Error when processing completions')
+
+ # ------------- LSP: Signature Hints ------------------------------------
+ @request(method=LSPRequestTypes.DOCUMENT_SIGNATURE)
+ def request_signature(self):
+ """Ask for signature."""
+ self.document_did_change('')
+ line, column = self.get_cursor_line_column()
+ params = {
+ 'file': self.filename,
+ 'line': line,
+ 'column': column
+ }
+ return params
+
+ @handles(LSPRequestTypes.DOCUMENT_SIGNATURE)
+ def process_signatures(self, params):
+ """Handle signature response."""
+ try:
+ signature_params = params['params']
+ if (signature_params is not None and
+ 'activeParameter' in signature_params):
+ self.sig_signature_invoked.emit(signature_params)
+ signature_data = signature_params['signatures']
+ documentation = signature_data['documentation']
+
+ # The language server returns encoded text with
+ # spaces defined as `\xa0`
+ documentation = documentation.replace(u'\xa0', ' ')
+
+ parameter_idx = signature_params['activeParameter']
+ parameters = signature_data['parameters']
+ parameter_data = parameters[parameter_idx]
+
+ signature = signature_data['label']
+ parameter = parameter_data['label']
+
+ # This method is part of spyder/widgets/mixins
+ self.show_calltip(
+ signature=signature,
+ parameter=parameter,
+ documentation=documentation,
+ )
+ except Exception:
+ self.log_lsp_handle_errors("Error when processing signature")
+
+ # ------------- LSP: Hover ---------------------------------------
+ @request(method=LSPRequestTypes.DOCUMENT_HOVER)
+ def request_hover(self, line, col, show_hint=True, clicked=True):
+ """Request hover information."""
+ params = {
+ 'file': self.filename,
+ 'line': line,
+ 'column': col
+ }
+ self._show_hint = show_hint
+ self._request_hover_clicked = clicked
+ return params
+
+ @handles(LSPRequestTypes.DOCUMENT_HOVER)
+ def handle_hover_response(self, contents):
+ """Handle hover response."""
+ try:
+ content = contents['params']
+ if CONF.get('lsp-server', 'enable_hover_hints'):
+ self.sig_display_object_info.emit(content,
+ self._request_hover_clicked)
+ if self._show_hint and self._last_point and content:
+ # This is located in spyder/widgets/mixins.py
+ word = self._last_hover_word,
+ content = content.replace(u'\xa0', ' ')
+ self.show_hint(content, inspect_word=word,
+ at_point=self._last_point)
+ self._last_point = None
+
+ except Exception:
+ self.log_lsp_handle_errors("Error when processing hover")
+
+ # ------------- LSP: Go To Definition ----------------------------
+ @Slot()
+ @request(method=LSPRequestTypes.DOCUMENT_DEFINITION)
+ def go_to_definition_from_cursor(self, cursor=None):
+ """Go to definition from cursor instance (QTextCursor)."""
+ if (not self.go_to_definition_enabled or
+ self.in_comment_or_string()):
+ return
+
+ if cursor is None:
+ cursor = self.textCursor()
+
+ text = to_text_string(cursor.selectedText())
+
+ if len(text) == 0:
+ cursor.select(QTextCursor.WordUnderCursor)
+ text = to_text_string(cursor.selectedText())
+
+ if text is not None:
+ line, column = self.get_cursor_line_column()
+ params = {
+ 'file': self.filename,
+ 'line': line,
+ 'column': column
+ }
+ return params
+
+ @handles(LSPRequestTypes.DOCUMENT_DEFINITION)
+ def handle_go_to_definition(self, position):
+ """Handle go to definition response."""
+ try:
+ position = position['params']
+ if position is not None:
+ def_range = position['range']
+ start = def_range['start']
+ if self.filename == position['file']:
+ self.go_to_line(start['line'] + 1,
+ start['character'],
+ None,
+ word=None)
+ else:
+ self.go_to_definition.emit(position['file'],
+ start['line'] + 1,
+ start['character'])
+ except Exception:
+ self.log_lsp_handle_errors(
+ "Error when processing go to definition")
+
+ # ------------- LSP: Save/close file -----------------------------------
+ @request(method=LSPRequestTypes.DOCUMENT_DID_SAVE,
+ requires_response=False)
+ def notify_save(self):
+ """Send save request."""
+ # self.document_did_change()
+ params = {'file': self.filename}
+ if self.save_include_text:
+ params['text'] = self.toPlainText()
+ return params
+
+ @request(method=LSPRequestTypes.DOCUMENT_DID_CLOSE,
+ requires_response=False)
+ def notify_close(self):
+ """Send close request."""
+ if self.lsp_ready:
+ params = {
+ 'file': self.filename,
+ 'codeeditor': self
+ }
+ return params
+
+ # -------------------------------------------------------------------------
+ def set_debug_panel(self, debug_panel, language):
+ """Enable/disable debug panel."""
+ debugger_panel = self.panels.get(DebuggerPanel)
+ if language == 'py' and debug_panel:
+ debugger_panel.setVisible(True)
+ else:
+ debugger_panel.setVisible(False)
+
+ def set_folding_panel(self, folding):
+ """Enable/disable folding panel."""
+ folding_panel = self.panels.get(FoldingPanel)
+ folding_panel.setVisible(folding)
+
+ def set_tab_mode(self, enable):
+ """
+ enabled = tab always indent
+ (otherwise tab indents only when cursor is at the beginning of a line)
+ """
+ self.tab_mode = enable
+
+ def set_strip_mode(self, enable):
+ """
+ Strip all trailing spaces if enabled, else only strip on auto-indents.
+ """
+ self.strip_trailing_spaces_on_modify = enable
+
+ def toggle_intelligent_backspace(self, state):
+ self.intelligent_backspace = state
+
+ def set_close_parentheses_enabled(self, enable):
+ """Enable/disable automatic parentheses insertion feature"""
+ self.close_parentheses_enabled = enable
+ bracket_extension = self.editor_extensions.get(CloseBracketsExtension)
+ if bracket_extension is not None:
+ bracket_extension.enabled = enable
+
+ def set_close_quotes_enabled(self, enable):
+ """Enable/disable automatic quote insertion feature"""
+ self.close_quotes_enabled = enable
+ quote_extension = self.editor_extensions.get(CloseQuotesExtension)
+ if quote_extension is not None:
+ quote_extension.enabled = enable
+
+ def set_add_colons_enabled(self, enable):
+ """Enable/disable automatic colons insertion feature"""
+ self.add_colons_enabled = enable
+
+ def set_auto_unindent_enabled(self, enable):
+ """Enable/disable automatic unindent after else/elif/finally/except"""
+ self.auto_unindent_enabled = enable
+
+ def set_occurrence_highlighting(self, enable):
+ """Enable/disable occurrence highlighting"""
+ self.occurrence_highlighting = enable
+ if not enable:
+ self.__clear_occurrences()
+
+ def set_occurrence_timeout(self, timeout):
+ """Set occurrence highlighting timeout (ms)"""
+ self.occurrence_timer.setInterval(timeout)
+
+ def set_highlight_current_line(self, enable):
+ """Enable/disable current line highlighting"""
+ self.highlight_current_line_enabled = enable
+ if self.highlight_current_line_enabled:
+ self.highlight_current_line()
+ else:
+ self.unhighlight_current_line()
+
+ def set_highlight_current_cell(self, enable):
+ """Enable/disable current line highlighting"""
+ hl_cell_enable = enable and self.supported_cell_language
+ self.highlight_current_cell_enabled = hl_cell_enable
+ if self.highlight_current_cell_enabled:
+ self.highlight_current_cell()
+ else:
+ self.unhighlight_current_cell()
+
+ def set_language(self, language, filename=None):
+ self.tab_indents = language in self.TAB_ALWAYS_INDENTS
+ self.comment_string = ''
+ sh_class = sh.TextSH
+ self.language = 'Text'
+ if language is not None:
+ for (key, value) in ALL_LANGUAGES.items():
+ if language.lower() in value:
+ self.supported_language = True
+ sh_class, comment_string, CFMatch = self.LANGUAGES[key]
+ self.language = key
+ self.comment_string = comment_string
+ if key in CELL_LANGUAGES:
+ self.supported_cell_language = True
+ self.cell_separators = CELL_LANGUAGES[key]
+ if CFMatch is None:
+ self.classfunc_match = None
+ else:
+ self.classfunc_match = CFMatch()
+ break
+ if filename is not None and not self.supported_language:
+ sh_class = sh.guess_pygments_highlighter(filename)
+ self.support_language = sh_class is not sh.TextSH
+ if self.support_language:
+ self.language = sh_class._lexer.name
+ self._set_highlighter(sh_class)
+
+ def _set_highlighter(self, sh_class):
+ self.highlighter_class = sh_class
+ if self.highlighter is not None:
+ # Removing old highlighter
+ # TODO: test if leaving parent/document as is eats memory
+ self.highlighter.setParent(None)
+ self.highlighter.setDocument(None)
+ self.highlighter = self.highlighter_class(self.document(),
+ self.font(),
+ self.color_scheme)
+ self._apply_highlighter_color_scheme()
+
+ self.highlighter.fold_detector = IndentFoldDetector()
+ self.highlighter.editor = self
+
+ def is_json(self):
+ return (isinstance(self.highlighter, sh.PygmentsSH) and
+ self.highlighter._lexer.name == 'JSON')
+
+ def is_python(self):
+ return self.highlighter_class is sh.PythonSH
+
+ def is_cython(self):
+ return self.highlighter_class is sh.CythonSH
+
+ def is_enaml(self):
+ return self.highlighter_class is sh.EnamlSH
+
+ def is_python_like(self):
+ return self.is_python() or self.is_cython() or self.is_enaml()
+
+ def intelligent_tab(self):
+ """Provide intelligent behavoir for Tab key press"""
+ leading_text = self.get_text('sol', 'cursor')
+ if not leading_text.strip() or leading_text.endswith('#'):
+ # blank line or start of comment
+ self.indent_or_replace()
+ elif self.in_comment_or_string() and not leading_text.endswith(' '):
+ # in a word in a comment
+ self.do_completion()
+ elif leading_text.endswith('import ') or leading_text[-1] == '.':
+ # blank import or dot completion
+ self.do_completion()
+ elif (leading_text.split()[0] in ['from', 'import'] and
+ not ';' in leading_text):
+ # import line with a single statement
+ # (prevents lines like: `import pdb; pdb.set_trace()`)
+ self.do_completion()
+ elif leading_text[-1] in '(,' or leading_text.endswith(', '):
+ self.indent_or_replace()
+ elif leading_text.endswith(' '):
+ # if the line ends with a space, indent
+ self.indent_or_replace()
+ elif re.search(r"[^\d\W]\w*\Z", leading_text, re.UNICODE):
+ # if the line ends with a non-whitespace character
+ self.do_completion()
+ else:
+ self.indent_or_replace()
+
+ def intelligent_backtab(self):
+ """Provide intelligent behavoir for Shift+Tab key press"""
+ leading_text = self.get_text('sol', 'cursor')
+ if not leading_text.strip():
+ # blank line
+ self.unindent()
+ elif self.in_comment_or_string():
+ self.unindent()
+ elif leading_text[-1] in '(,' or leading_text.endswith(', '):
+ position = self.get_position('cursor')
+ self.show_object_info(position)
+ else:
+ # if the line ends with any other character but comma
+ self.unindent()
+
+ def rehighlight(self):
+ """
+ Rehighlight the whole document to rebuild outline explorer data
+ and import statements data from scratch
+ """
+ if self.highlighter is not None:
+ self.highlighter.rehighlight()
+ if self.highlight_current_cell_enabled:
+ self.highlight_current_cell()
+ else:
+ self.unhighlight_current_cell()
+ if self.highlight_current_line_enabled:
+ self.highlight_current_line()
+ else:
+ self.unhighlight_current_line()
+
+ def rehighlight_cells(self):
+ """Rehighlight cells when moving the scrollbar"""
+ if self.highlight_current_cell_enabled:
+ self.highlight_current_cell()
+
+ def remove_trailing_spaces(self):
+ """Remove trailing spaces"""
+ cursor = self.textCursor()
+ cursor.beginEditBlock()
+ cursor.movePosition(QTextCursor.Start)
+ while True:
+ cursor.movePosition(QTextCursor.EndOfBlock)
+ text = to_text_string(cursor.block().text())
+ length = len(text)-len(text.rstrip())
+ if length > 0:
+ cursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor,
+ length)
+ cursor.removeSelectedText()
+ if cursor.atEnd():
+ break
+ cursor.movePosition(QTextCursor.NextBlock)
+ cursor.endEditBlock()
+ self.document_did_change()
+
+ def fix_indentation(self):
+ """Replace tabs by spaces."""
+ text_before = to_text_string(self.toPlainText())
+ text_after = sourcecode.fix_indentation(text_before, self.indent_chars)
+ if text_before != text_after:
+ # We do the following rather than using self.setPlainText
+ # to benefit from QTextEdit's undo/redo feature.
+ self.selectAll()
+ self.skip_rstrip = True
+ self.insertPlainText(text_after)
+ self.document_did_change()
+ self.skip_rstrip = False
+
+ def get_current_object(self):
+ """Return current object (string) """
+ source_code = to_text_string(self.toPlainText())
+ offset = self.get_position('cursor')
+ return sourcecode.get_primary_at(source_code, offset)
+
+ @Slot()
+ def delete(self):
+ """Remove selected text or next character."""
+ if not self.has_selected_text():
+ cursor = self.textCursor()
+ position = cursor.position()
+ if not cursor.atEnd():
+ cursor.setPosition(position + 1, QTextCursor.KeepAnchor)
+ self.setTextCursor(cursor)
+ self.remove_selected_text()
+ self.document_did_change()
+
+ #------Find occurrences
+ def __find_first(self, text):
+ """Find first occurrence: scan whole document"""
+ flags = QTextDocument.FindCaseSensitively|QTextDocument.FindWholeWords
+ cursor = self.textCursor()
+ # Scanning whole document
+ cursor.movePosition(QTextCursor.Start)
+ regexp = QRegExp(r"\b%s\b" % QRegExp.escape(text), Qt.CaseSensitive)
+ cursor = self.document().find(regexp, cursor, flags)
+ self.__find_first_pos = cursor.position()
+ return cursor
+
+ def __find_next(self, text, cursor):
+ """Find next occurrence"""
+ flags = QTextDocument.FindCaseSensitively|QTextDocument.FindWholeWords
+ regexp = QRegExp(r"\b%s\b" % QRegExp.escape(text), Qt.CaseSensitive)
+ cursor = self.document().find(regexp, cursor, flags)
+ if cursor.position() != self.__find_first_pos:
+ return cursor
+
+ def __cursor_position_changed(self):
+ """Cursor position has changed"""
+ line, column = self.get_cursor_line_column()
+ self.sig_cursor_position_changed.emit(line, column)
+ if self.highlight_current_cell_enabled:
+ self.highlight_current_cell()
+ else:
+ self.unhighlight_current_cell()
+ if self.highlight_current_line_enabled:
+ self.highlight_current_line()
+ else:
+ self.unhighlight_current_line()
+ if self.occurrence_highlighting:
+ self.occurrence_timer.stop()
+ self.occurrence_timer.start()
+
+ # Strip if needed
+ self.strip_trailing_spaces()
+
+ def __clear_occurrences(self):
+ """Clear occurrence markers"""
+ self.occurrences = []
+ self.clear_extra_selections('occurrences')
+ self.sig_flags_changed.emit()
+
+ def __highlight_selection(self, key, cursor, foreground_color=None,
+ background_color=None, underline_color=None,
+ outline_color=None,
+ underline_style=QTextCharFormat.WaveUnderline,
+ update=False):
+ if cursor is None:
+ return
+ extra_selections = self.get_extra_selections(key)
+ selection = TextDecoration(cursor)
+ if foreground_color is not None:
+ selection.format.setForeground(foreground_color)
+ if background_color is not None:
+ selection.format.setBackground(background_color)
+ if underline_color is not None:
+ selection.format.setProperty(QTextFormat.TextUnderlineStyle,
+ to_qvariant(underline_style))
+ selection.format.setProperty(QTextFormat.TextUnderlineColor,
+ to_qvariant(underline_color))
+ if outline_color is not None:
+ selection.set_outline(outline_color)
+ # selection.format.setProperty(QTextFormat.FullWidthSelection,
+ # to_qvariant(True))
+ extra_selections.append(selection)
+ self.set_extra_selections(key, extra_selections)
+ if update:
+ self.update_extra_selections()
+
+ def __mark_occurrences(self):
+ """Marking occurrences of the currently selected word"""
+ self.__clear_occurrences()
+
+ if not self.supported_language:
+ return
+
+ text = self.get_selected_text().strip()
+ if not text:
+ text = self.get_current_word()
+ if text is None:
+ return
+ if (self.has_selected_text() and
+ self.get_selected_text().strip() != text):
+ return
+
+ if (self.is_python_like()) and \
+ (sourcecode.is_keyword(to_text_string(text)) or \
+ to_text_string(text) == 'self'):
+ return
+
+ # Highlighting all occurrences of word *text*
+ cursor = self.__find_first(text)
+ self.occurrences = []
+ while cursor:
+ self.occurrences.append(cursor.blockNumber())
+ self.__highlight_selection('occurrences', cursor,
+ background_color=self.occurrence_color)
+ cursor = self.__find_next(text, cursor)
+ self.update_extra_selections()
+ if len(self.occurrences) > 1 and self.occurrences[-1] == 0:
+ # XXX: this is never happening with PySide but it's necessary
+ # for PyQt4... this must be related to a different behavior for
+ # the QTextDocument.find function between those two libraries
+ self.occurrences.pop(-1)
+ self.sig_flags_changed.emit()
+
+ #-----highlight found results (find/replace widget)
+ def highlight_found_results(self, pattern, words=False, regexp=False):
+ """Highlight all found patterns"""
+ pattern = to_text_string(pattern)
+ if not pattern:
+ return
+ if not regexp:
+ pattern = re.escape(to_text_string(pattern))
+ pattern = r"\b%s\b" % pattern if words else pattern
+ text = to_text_string(self.toPlainText())
+ try:
+ regobj = re.compile(pattern)
+ except sre_constants.error:
+ return
+ extra_selections = []
+ self.found_results = []
+ for match in regobj.finditer(text):
+ pos1, pos2 = match.span()
+ selection = TextDecoration(self.textCursor())
+ selection.format.setBackground(self.found_results_color)
+ selection.cursor.setPosition(pos1)
+ self.found_results.append(selection.cursor.blockNumber())
+ selection.cursor.setPosition(pos2, QTextCursor.KeepAnchor)
+ extra_selections.append(selection)
+ self.set_extra_selections('find', extra_selections)
+ self.update_extra_selections()
+
+ def clear_found_results(self):
+ """Clear found results highlighting"""
+ self.found_results = []
+ self.clear_extra_selections('find')
+ self.sig_flags_changed.emit()
+
+ def __text_has_changed(self):
+ """Text has changed, eventually clear found results highlighting"""
+ self.last_change_position = self.textCursor().position()
+ if self.found_results:
+ self.clear_found_results()
+
+ def get_linenumberarea_width(self):
+ """
+ Return current line number area width.
+
+ This method is left for backward compatibility (BaseEditMixin
+ define it), any changes should be in LineNumberArea class.
+ """
+ return self.linenumberarea.get_width()
+
+ def calculate_real_position(self, point):
+ """Add offset to a point, to take into account the panels."""
+ point.setX(point.x() + self.panels.margin_size(Panel.Position.LEFT))
+ point.setY(point.y() + self.panels.margin_size(Panel.Position.TOP))
+ return point
+
+ def calculate_real_position_from_global(self, point):
+ """Add offset to a point, to take into account the panels."""
+ point.setX(point.x() - self.panels.margin_size(Panel.Position.LEFT))
+ point.setY(point.y() + self.panels.margin_size(Panel.Position.TOP))
+ return point
+
+ def get_linenumber_from_mouse_event(self, event):
+ """Return line number from mouse event"""
+ block = self.firstVisibleBlock()
+ line_number = block.blockNumber()
+ top = self.blockBoundingGeometry(block).translated(
+ self.contentOffset()).top()
+ bottom = top + self.blockBoundingRect(block).height()
+
+ while block.isValid() and top < event.pos().y():
+ block = block.next()
+ if block.isVisible(): # skip collapsed blocks
+ top = bottom
+ bottom = top + self.blockBoundingRect(block).height()
+ line_number += 1
+
+ return line_number
+
+ def select_lines(self, linenumber_pressed, linenumber_released):
+ """Select line(s) after a mouse press/mouse press drag event"""
+ find_block_by_line_number = self.document().findBlockByLineNumber
+ move_n_blocks = (linenumber_released - linenumber_pressed)
+ start_line = linenumber_pressed
+ start_block = find_block_by_line_number(start_line - 1)
+
+ cursor = self.textCursor()
+ cursor.setPosition(start_block.position())
+
+ # Select/drag downwards
+ if move_n_blocks > 0:
+ for n in range(abs(move_n_blocks) + 1):
+ cursor.movePosition(cursor.NextBlock, cursor.KeepAnchor)
+ # Select/drag upwards or select single line
+ else:
+ cursor.movePosition(cursor.NextBlock)
+ for n in range(abs(move_n_blocks) + 1):
+ cursor.movePosition(cursor.PreviousBlock, cursor.KeepAnchor)
+
+ # Account for last line case
+ if linenumber_released == self.blockCount():
+ cursor.movePosition(cursor.EndOfBlock, cursor.KeepAnchor)
+ else:
+ cursor.movePosition(cursor.StartOfBlock, cursor.KeepAnchor)
+
+ self.setTextCursor(cursor)
+
+ # ----- Code bookmarks
+ def add_bookmark(self, slot_num, line=None, column=None):
+ """Add bookmark to current block's userData."""
+ if line is None:
+ # Triggered by shortcut, else by spyder start
+ line, column = self.get_cursor_line_column()
+ block = self.document().findBlockByNumber(line)
+ data = block.userData()
+ if not data:
+ data = BlockUserData(self)
+ if slot_num not in data.bookmarks:
+ data.bookmarks.append((slot_num, column))
+ block.setUserData(data)
+ self.sig_bookmarks_changed.emit()
+
+ def get_bookmarks(self):
+ """Get bookmarks by going over all blocks."""
+ bookmarks = {}
+ block = self.document().firstBlock()
+ for line_number in range(0, self.document().blockCount()):
+ data = block.userData()
+ if data and data.bookmarks:
+ for slot_num, column in data.bookmarks:
+ bookmarks[slot_num] = [line_number, column]
+ block = block.next()
+ return bookmarks
+
+ def clear_bookmarks(self):
+ """Clear bookmarks for all blocks."""
+ self.bookmarks = {}
+ for data in self.blockuserdata_list():
+ data.bookmarks = []
+
+ def set_bookmarks(self, bookmarks):
+ """Set bookmarks when opening file."""
+ self.clear_bookmarks()
+ for slot_num, bookmark in bookmarks.items():
+ self.add_bookmark(slot_num, bookmark[1], bookmark[2])
+
+ def update_bookmarks(self):
+ """Emit signal to update bookmarks."""
+ self.sig_bookmarks_changed.emit()
+
+ #-----Code introspection
+ def show_object_info(self, position):
+ """Trigger a calltip"""
+ self.sig_show_object_info.emit(position)
+
+ # -----blank spaces
+ def set_blanks_enabled(self, state):
+ """Toggle blanks visibility"""
+ self.blanks_enabled = state
+ option = self.document().defaultTextOption()
+ option.setFlags(option.flags() | \
+ QTextOption.AddSpaceForLineAndParagraphSeparators)
+ if self.blanks_enabled:
+ option.setFlags(option.flags() | QTextOption.ShowTabsAndSpaces)
+ else:
+ option.setFlags(option.flags() & ~QTextOption.ShowTabsAndSpaces)
+ self.document().setDefaultTextOption(option)
+ # Rehighlight to make the spaces less apparent.
+ self.rehighlight()
+
+ def set_scrollpastend_enabled(self, state):
+ """
+ Allow user to scroll past the end of the document to have the last
+ line on top of the screen
+ """
+ self.scrollpastend_enabled = state
+ self.setCenterOnScroll(state)
+ self.setDocument(self.document())
+
+ def resizeEvent(self, event):
+ """Reimplemented Qt method to handle p resizing"""
+ TextEditBaseWidget.resizeEvent(self, event)
+ self.panels.resize()
+
+ def showEvent(self, event):
+ """Overrides showEvent to update the viewport margins."""
+ super(CodeEditor, self).showEvent(event)
+ self.panels.refresh()
+
+
+ #-----Misc.
+ def _apply_highlighter_color_scheme(self):
+ """Apply color scheme from syntax highlighter to the editor"""
+ hl = self.highlighter
+ if hl is not None:
+ self.set_palette(background=hl.get_background_color(),
+ foreground=hl.get_foreground_color())
+ self.currentline_color = hl.get_currentline_color()
+ self.currentcell_color = hl.get_currentcell_color()
+ self.occurrence_color = hl.get_occurrence_color()
+ self.ctrl_click_color = hl.get_ctrlclick_color()
+ self.sideareas_color = hl.get_sideareas_color()
+ self.comment_color = hl.get_comment_color()
+ self.normal_color = hl.get_foreground_color()
+ self.matched_p_color = hl.get_matched_p_color()
+ self.unmatched_p_color = hl.get_unmatched_p_color()
+
+ self.edge_line.update_color()
+ self.indent_guides.update_color()
+
+ def apply_highlighter_settings(self, color_scheme=None):
+ """Apply syntax highlighter settings"""
+ if self.highlighter is not None:
+ # Updating highlighter settings (font and color scheme)
+ self.highlighter.setup_formats(self.font())
+ if color_scheme is not None:
+ self.set_color_scheme(color_scheme)
+ else:
+ self.highlighter.rehighlight()
+
+ def set_font(self, font, color_scheme=None):
+ """Set font"""
+ # Note: why using this method to set color scheme instead of
+ # 'set_color_scheme'? To avoid rehighlighting the document twice
+ # at startup.
+ if color_scheme is not None:
+ self.color_scheme = color_scheme
+ self.setFont(font)
+ self.panels.refresh()
+ self.apply_highlighter_settings(color_scheme)
+
+ def set_color_scheme(self, color_scheme):
+ """Set color scheme for syntax highlighting"""
+ self.color_scheme = color_scheme
+ if self.highlighter is not None:
+ # this calls self.highlighter.rehighlight()
+ self.highlighter.set_color_scheme(color_scheme)
+ self._apply_highlighter_color_scheme()
+ if self.highlight_current_cell_enabled:
+ self.highlight_current_cell()
+ else:
+ self.unhighlight_current_cell()
+ if self.highlight_current_line_enabled:
+ self.highlight_current_line()
+ else:
+ self.unhighlight_current_line()
+
+ def set_text(self, text):
+ """Set the text of the editor"""
+ self.setPlainText(text)
+ self.set_eol_chars(text)
+ self.document_did_change(text)
+
+ if (isinstance(self.highlighter, sh.PygmentsSH)
+ and not running_under_pytest()):
+ self.highlighter.make_charlist()
+
+ def set_text_from_file(self, filename, language=None):
+ """Set the text of the editor from file *fname*"""
+ self.filename = filename
+ text, _enc = encoding.read(filename)
+ if language is None:
+ language = get_file_language(filename, text)
+ self.set_language(language, filename)
+ self.set_text(text)
+
+ def append(self, text):
+ """Append text to the end of the text widget"""
+ cursor = self.textCursor()
+ cursor.movePosition(QTextCursor.End)
+ cursor.insertText(text)
+ self.document_did_change()
+
+ @Slot()
+ def paste(self):
+ """
+ Insert text or file/folder path copied from clipboard.
+
+ Reimplement QPlainTextEdit's method to fix the following issue:
+ on Windows, pasted text has only 'LF' EOL chars even if the original
+ text has 'CRLF' EOL chars.
+ The function also changes the clipboard data if they are copied as
+ files/folders but does not change normal text data except if they are
+ multiple lines. Since we are changing clipboard data we cannot use
+ paste, which directly pastes from clipboard instead we use
+ insertPlainText and pass the formatted/changed text without modifying
+ clipboard content.
+ """
+ clipboard = QApplication.clipboard()
+ text = to_text_string(clipboard.text())
+ if clipboard.mimeData().hasUrls():
+ # Have copied file and folder urls pasted as text paths.
+ # See PR: #8644 for details.
+ urls = clipboard.mimeData().urls()
+ if all([url.isLocalFile() for url in urls]):
+ if len(urls) > 1:
+ sep_chars = ',' + self.get_line_separator()
+ text = sep_chars.join('"' + url.toLocalFile().
+ replace(osp.os.sep, '/')
+ + '"' for url in urls)
+ else:
+ text = urls[0].toLocalFile().replace(osp.os.sep, '/')
+ if len(text.splitlines()) > 1:
+ eol_chars = self.get_line_separator()
+ text = eol_chars.join((text + eol_chars).splitlines())
+ self.skip_rstrip = True
+ TextEditBaseWidget.insertPlainText(self, text)
+ self.document_did_change(text)
+ self.skip_rstrip = False
+
+ @Slot()
+ def undo(self):
+ """Reimplement undo to decrease text version number."""
+ if self.document().isUndoAvailable():
+ self.text_version -= 1
+ self.skip_rstrip = True
+ TextEditBaseWidget.undo(self)
+ self.document_did_change('')
+ self.skip_rstrip = False
+
+ @Slot()
+ def redo(self):
+ """Reimplement redo to increase text version number."""
+ if self.document().isRedoAvailable():
+ self.text_version += 1
+ self.skip_rstrip = True
+ TextEditBaseWidget.redo(self)
+ self.document_did_change('text')
+ self.skip_rstrip = False
+
+ def get_block_data(self, block):
+ """Return block data (from syntax highlighter)"""
+ return self.highlighter.block_data.get(block)
+
+ def get_fold_level(self, block_nb):
+ """Is it a fold header line?
+ If so, return fold level
+ If not, return None"""
+ block = self.document().findBlockByNumber(block_nb)
+ return self.get_block_data(block).fold_level
+
+# =============================================================================
+# High-level editor features
+# =============================================================================
+ @Slot()
+ def center_cursor_on_next_focus(self):
+ """QPlainTextEdit's "centerCursor" requires the widget to be visible"""
+ self.centerCursor()
+ self.focus_in.disconnect(self.center_cursor_on_next_focus)
+
+ def go_to_line(self, line, start_column=0, end_column=0, word=''):
+ """Go to line number *line* and eventually highlight it"""
+ self.text_helper.goto_line(line, column=start_column,
+ end_column=end_column, move=True,
+ word=word)
+
+ def exec_gotolinedialog(self):
+ """Execute the GoToLineDialog dialog box"""
+ dlg = GoToLineDialog(self)
+ if dlg.exec_():
+ self.go_to_line(dlg.get_line_number())
+
+ def cleanup_code_analysis(self):
+ """Remove all code analysis markers"""
+ self.setUpdatesEnabled(False)
+ self.clear_extra_selections('code_analysis')
+ for data in self.blockuserdata_list():
+ data.code_analysis = []
+
+ self.setUpdatesEnabled(True)
+ # When the new code analysis results are empty, it is necessary
+ # to update manually the scrollflag and linenumber areas (otherwise,
+ # the old flags will still be displayed):
+ self.sig_flags_changed.emit()
+ self.linenumberarea.update()
+
+ def process_code_analysis(self, results):
+ """Process all linting results."""
+ self.cleanup_code_analysis()
+ self.setUpdatesEnabled(False)
+ cursor = self.textCursor()
+ document = self.document()
+
+ for diagnostic in results:
+ source = diagnostic.get('source', '')
+ msg_range = diagnostic['range']
+ start = msg_range['start']
+ end = msg_range['end']
+ code = diagnostic.get('code', 'E')
+ message = diagnostic['message']
+ severity = diagnostic.get(
+ 'severity', DiagnosticSeverity.ERROR)
+
+ block = document.findBlockByNumber(start['line'])
+ error = severity == DiagnosticSeverity.ERROR
+ color = self.error_color if error else self.warning_color
+ cursor.setPosition(block.position())
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ cursor.movePosition(
+ QTextCursor.NextCharacter, n=start['character'])
+ block2 = document.findBlockByNumber(end['line'])
+ cursor.setPosition(block2.position(), QTextCursor.KeepAnchor)
+ cursor.movePosition(
+ QTextCursor.StartOfBlock, mode=QTextCursor.KeepAnchor)
+ cursor.movePosition(
+ QTextCursor.NextCharacter, n=end['character'],
+ mode=QTextCursor.KeepAnchor)
+ color = QColor(color)
+ color.setAlpha(50)
+
+ data = block.userData()
+ if not data:
+ data = BlockUserData(
+ self, cursor=QTextCursor(cursor), color=color)
+ data.code_analysis.append((source, code, severity, message))
+ block.setUserData(data)
+ block.selection = QTextCursor(cursor)
+ block.color = color
+
+ self.sig_process_code_analysis.emit()
+ self.update_extra_selections()
+ self.setUpdatesEnabled(True)
+ self.linenumberarea.update()
+ self.classfuncdropdown.update()
+
+ def hide_tooltip(self):
+ """
+ Hide the tooltip widget.
+
+ The tooltip widget is a special QLabel that looks like a tooltip,
+ this method is here so it can be hidden as necessary. For example,
+ when the user leaves the Linenumber area when hovering over lint
+ warnings and errors.
+ """
+ self._last_hover_word = None
+ self.tooltip_widget.hide()
+
+ def show_code_analysis_results(self, line_number, block_data):
+ """Show warning/error messages."""
+ from spyder.config.base import get_image_path
+ # Diagnostic severity
+ icons = {
+ DiagnosticSeverity.ERROR: 'error',
+ DiagnosticSeverity.WARNING: 'warning',
+ DiagnosticSeverity.INFORMATION: 'information',
+ DiagnosticSeverity.HINT: 'hint',
+ }
+
+ code_analysis = block_data.code_analysis
+
+ # Size must be adapted from font
+ fm = self.fontMetrics()
+ size = fm.height()
+ template = (
+ '
'
+ '{} ({} {})'
+ )
+
+ msglist = []
+ sorted_code_analysis = sorted(code_analysis, key=lambda i: i[2])
+ for src, code, sev, msg in sorted_code_analysis:
+ if '[' in msg and ']' in msg:
+ # Remove extra redundant info from pyling messages
+ msg = msg.split(']')[-1]
+
+ msg = msg.strip()
+ # Avoid messing TODO, FIXME
+ msg = msg[0].upper() + msg[1:]
+ base_64 = ima.base64_from_icon(icons[sev], size, size)
+ msglist.append(template.format(base_64, msg, src,
+ code, size=size))
+
+ if msglist:
+ self.show_tooltip(
+ title=_("Code analysis"),
+ text='\n'.join(msglist),
+ title_color='#129625',
+ at_line=line_number,
+ )
+ self.highlight_line_warning(block_data)
+
+ def highlight_line_warning(self, block_data):
+ self.clear_extra_selections('code_analysis')
+ self.__highlight_selection('code_analysis', block_data.selection,
+ background_color=block_data.color)
+ self.update_extra_selections()
+ self.linenumberarea.update()
+ QTimer.singleShot(
+ 5000, lambda: self.clear_extra_selections('code_analysis'))
+
+ def get_current_warnings(self):
+ """
+ Get all warnings for the current editor and return
+ a list with the message and line number.
+ """
+ block = self.document().firstBlock()
+ line_count = self.document().blockCount()
+ warnings = []
+ while True:
+ if block.blockNumber() + 1 == line_count:
+ break
+ data = block.userData()
+ if data and data.code_analysis:
+ for warning in data.code_analysis:
+ warnings.append([warning[-1], block.blockNumber() + 1])
+ block = block.next()
+ return warnings
+
+ def go_to_next_warning(self):
+ """Go to next code analysis warning message
+ and return new cursor position"""
+ block = self.textCursor().block()
+ line_count = self.document().blockCount()
+ while True:
+ if block.blockNumber()+1 < line_count:
+ block = block.next()
+ else:
+ block = self.document().firstBlock()
+ data = block.userData()
+ if data and data.code_analysis:
+ break
+ line_number = block.blockNumber()+1
+ self.go_to_line(line_number)
+ self.show_code_analysis_results(line_number, data)
+ return self.get_position('cursor')
+
+ def go_to_previous_warning(self):
+ """Go to previous code analysis warning message
+ and return new cursor position"""
+ block = self.textCursor().block()
+ while True:
+ if block.blockNumber() > 0:
+ block = block.previous()
+ else:
+ block = self.document().lastBlock()
+ data = block.userData()
+ if data and data.code_analysis:
+ break
+ line_number = block.blockNumber()+1
+ self.go_to_line(line_number)
+ self.show_code_analysis_results(line_number, data)
+ return self.get_position('cursor')
+
+
+ #------Tasks management
+ def go_to_next_todo(self):
+ """Go to next todo and return new cursor position"""
+ block = self.textCursor().block()
+ line_count = self.document().blockCount()
+ while True:
+ if block.blockNumber()+1 < line_count:
+ block = block.next()
+ else:
+ block = self.document().firstBlock()
+ data = block.userData()
+ if data and data.todo:
+ break
+ line_number = block.blockNumber()+1
+ self.go_to_line(line_number)
+ self.show_tooltip(
+ title=_("To do"),
+ text=data.todo,
+ title_color='#3096FC',
+ at_line=line_number,
+ )
+
+ return self.get_position('cursor')
+
+ def process_todo(self, todo_results):
+ """Process todo finder results"""
+ for data in self.blockuserdata_list():
+ data.todo = ''
+
+ for message, line_number in todo_results:
+ block = self.document().findBlockByNumber(line_number-1)
+ data = block.userData()
+ if not data:
+ data = BlockUserData(self)
+ data.todo = message
+ block.setUserData(data)
+ self.sig_flags_changed.emit()
+
+
+ #------Comments/Indentation
+ def add_prefix(self, prefix):
+ """Add prefix to current line or selected line(s)"""
+ cursor = self.textCursor()
+ if self.has_selected_text():
+ # Add prefix to selected line(s)
+ start_pos, end_pos = cursor.selectionStart(), cursor.selectionEnd()
+
+ # Let's see if selection begins at a block start
+ first_pos = min([start_pos, end_pos])
+ first_cursor = self.textCursor()
+ first_cursor.setPosition(first_pos)
+
+ cursor.beginEditBlock()
+ cursor.setPosition(end_pos)
+ # Check if end_pos is at the start of a block: if so, starting
+ # changes from the previous block
+ if cursor.atBlockStart():
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ if cursor.position() < start_pos:
+ cursor.setPosition(start_pos)
+ move_number = self.__spaces_for_prefix()
+
+ while cursor.position() >= start_pos:
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ line_text = to_text_string(cursor.block().text())
+ if (self.get_character(cursor.position()) == ' '
+ and '#' in prefix and not line_text.isspace()
+ or (not line_text.startswith(' ')
+ and line_text != '')):
+ cursor.movePosition(QTextCursor.Right,
+ QTextCursor.MoveAnchor,
+ move_number)
+ cursor.insertText(prefix)
+ elif '#' not in prefix:
+ cursor.insertText(prefix)
+ if start_pos == 0 and cursor.blockNumber() == 0:
+ # Avoid infinite loop when indenting the very first line
+ break
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ cursor.movePosition(QTextCursor.EndOfBlock)
+ cursor.endEditBlock()
+ else:
+ # Add prefix to current line
+ cursor.beginEditBlock()
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ if self.get_character(cursor.position()) == ' ' and '#' in prefix:
+ cursor.movePosition(QTextCursor.NextWord)
+ cursor.insertText(prefix)
+ cursor.endEditBlock()
+ self.document_did_change()
+
+ def __spaces_for_prefix(self):
+ """Find the less indented level of text."""
+ cursor = self.textCursor()
+ if self.has_selected_text():
+ # Add prefix to selected line(s)
+ start_pos, end_pos = cursor.selectionStart(), cursor.selectionEnd()
+
+ # Let's see if selection begins at a block start
+ first_pos = min([start_pos, end_pos])
+ first_cursor = self.textCursor()
+ first_cursor.setPosition(first_pos)
+
+ cursor.beginEditBlock()
+ cursor.setPosition(end_pos)
+ # Check if end_pos is at the start of a block: if so, starting
+ # changes from the previous block
+ if cursor.atBlockStart():
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ if cursor.position() < start_pos:
+ cursor.setPosition(start_pos)
+
+ number_spaces = -1
+ while cursor.position() >= start_pos:
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ line_text = to_text_string(cursor.block().text())
+ start_with_space = line_text.startswith(' ')
+ left_number_spaces = self.__number_of_spaces(line_text)
+ if not start_with_space:
+ left_number_spaces = 0
+ if ((number_spaces == -1
+ or number_spaces > left_number_spaces)
+ and not line_text.isspace() and line_text != ''):
+ number_spaces = left_number_spaces
+ if start_pos == 0 and cursor.blockNumber() == 0:
+ # Avoid infinite loop when indenting the very first line
+ break
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ cursor.movePosition(QTextCursor.EndOfBlock)
+ cursor.endEditBlock()
+ return number_spaces
+
+ def __is_cursor_at_start_of_block(self, cursor):
+ cursor.movePosition(QTextCursor.StartOfBlock)
+
+ def remove_suffix(self, suffix):
+ """
+ Remove suffix from current line (there should not be any selection)
+ """
+ cursor = self.textCursor()
+ cursor.setPosition(cursor.position()-len(suffix),
+ QTextCursor.KeepAnchor)
+ if to_text_string(cursor.selectedText()) == suffix:
+ cursor.removeSelectedText()
+
+ def remove_prefix(self, prefix):
+ """Remove prefix from current line or selected line(s)"""
+ cursor = self.textCursor()
+ if self.has_selected_text():
+ # Remove prefix from selected line(s)
+ start_pos, end_pos = sorted([cursor.selectionStart(),
+ cursor.selectionEnd()])
+ cursor.setPosition(start_pos)
+ if not cursor.atBlockStart():
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ start_pos = cursor.position()
+ cursor.beginEditBlock()
+ cursor.setPosition(end_pos)
+ # Check if end_pos is at the start of a block: if so, starting
+ # changes from the previous block
+ if cursor.atBlockStart():
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ if cursor.position() < start_pos:
+ cursor.setPosition(start_pos)
+
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ old_pos = None
+ while cursor.position() >= start_pos:
+ new_pos = cursor.position()
+ if old_pos == new_pos:
+ break
+ else:
+ old_pos = new_pos
+ line_text = to_text_string(cursor.block().text())
+ self.__remove_prefix(prefix, cursor, line_text)
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ cursor.endEditBlock()
+ else:
+ # Remove prefix from current line
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ line_text = to_text_string(cursor.block().text())
+ self.__remove_prefix(prefix, cursor, line_text)
+ self.document_did_change()
+
+ def __remove_prefix(self, prefix, cursor, line_text):
+ """Handle the removal of the prefix for a single line."""
+ start_with_space = line_text.startswith(' ')
+ if start_with_space:
+ left_spaces = self.__even_number_of_spaces(line_text)
+ else:
+ left_spaces = False
+ if start_with_space:
+ right_number_spaces = self.__number_of_spaces(line_text, group=1)
+ else:
+ right_number_spaces = self.__number_of_spaces(line_text)
+ # Handle prefix remove for comments with spaces
+ if (prefix.strip() and line_text.lstrip().startswith(prefix + ' ')
+ or line_text.startswith(prefix + ' ') and '#' in prefix):
+ cursor.movePosition(QTextCursor.Right,
+ QTextCursor.MoveAnchor,
+ line_text.find(prefix))
+ if (right_number_spaces == 1
+ and (left_spaces or not start_with_space)
+ or (not start_with_space and right_number_spaces % 2 != 0)
+ or (left_spaces and right_number_spaces % 2 != 0)):
+ # Handle inserted '# ' with the count of the number of spaces
+ # at the right and left of the prefix.
+ cursor.movePosition(QTextCursor.Right,
+ QTextCursor.KeepAnchor, len(prefix + ' '))
+ else:
+ # Handle manual insertion of '#'
+ cursor.movePosition(QTextCursor.Right,
+ QTextCursor.KeepAnchor, len(prefix))
+ cursor.removeSelectedText()
+ # Check for prefix without space
+ elif (prefix.strip() and line_text.lstrip().startswith(prefix)
+ or line_text.startswith(prefix)):
+ cursor.movePosition(QTextCursor.Right,
+ QTextCursor.MoveAnchor,
+ line_text.find(prefix))
+ cursor.movePosition(QTextCursor.Right,
+ QTextCursor.KeepAnchor, len(prefix))
+ cursor.removeSelectedText()
+ self.document_did_change()
+
+ def __even_number_of_spaces(self, line_text, group=0):
+ """
+ Get if there is a correct indentation from a group of spaces of a line.
+ """
+ spaces = re.findall('\s+', line_text)
+ if len(spaces) - 1 >= group:
+ return len(spaces[group]) % len(self.indent_chars) == 0
+
+ def __number_of_spaces(self, line_text, group=0):
+ """Get the number of spaces from a group of spaces in a line."""
+ spaces = re.findall('\s+', line_text)
+ if len(spaces) - 1 >= group:
+ return len(spaces[group])
+
+ def fix_indent(self, *args, **kwargs):
+ """Indent line according to the preferences"""
+ if self.is_python_like():
+ ret = self.fix_indent_smart(*args, **kwargs)
+ else:
+ ret = self.simple_indentation(*args, **kwargs)
+ self.document_did_change()
+ return ret
+
+ def simple_indentation(self, forward=True, **kwargs):
+ """
+ Simply preserve the indentation-level of the previous line.
+ """
+ cursor = self.textCursor()
+ block_nb = cursor.blockNumber()
+ prev_block = self.document().findBlockByLineNumber(block_nb-1)
+ prevline = to_text_string(prev_block.text())
+
+ indentation = re.match(r"\s*", prevline).group()
+ # Unident
+ if not forward:
+ indentation = indentation[len(self.indent_chars):]
+
+ cursor.insertText(indentation)
+ return False # simple indentation don't fix indentation
+
+ def fix_indent_smart(self, forward=True, comment_or_string=False):
+ """
+ Fix indentation (Python only, no text selection)
+ forward=True: fix indent only if text is not enough indented
+ (otherwise force indent)
+ forward=False: fix indent only if text is too much indented
+ (otherwise force unindent)
+
+ Returns True if indent needed to be fixed
+ """
+ cursor = self.textCursor()
+ block_nb = cursor.blockNumber()
+ # find the line that contains our scope
+ diff_paren = 0
+ diff_brack = 0
+ diff_curly = 0
+ add_indent = False
+ prevline = None
+ prevtext = ""
+ for prevline in range(block_nb-1, -1, -1):
+ cursor.movePosition(QTextCursor.PreviousBlock)
+ prevtext = to_text_string(cursor.block().text()).rstrip()
+
+ # Remove inline comment
+ inline_comment = prevtext.find('#')
+ if inline_comment != -1:
+ prevtext = prevtext[:inline_comment]
+
+ if ((self.is_python_like() and
+ not prevtext.strip().startswith('#') and prevtext) or
+ prevtext):
+
+ if not "return" in prevtext.strip().split()[:1] and \
+ (prevtext.strip().endswith(')') or
+ prevtext.strip().endswith(']') or
+ prevtext.strip().endswith('}')):
+
+ comment_or_string = True # prevent further parsing
+
+ elif prevtext.strip().endswith(':') and self.is_python_like():
+ add_indent = True
+ comment_or_string = True
+ if (prevtext.count(')') > prevtext.count('(')):
+ diff_paren = prevtext.count(')') - prevtext.count('(')
+ elif (prevtext.count(']') > prevtext.count('[')):
+ diff_brack = prevtext.count(']') - prevtext.count('[')
+ elif (prevtext.count('}') > prevtext.count('{')):
+ diff_curly = prevtext.count('}') - prevtext.count('{')
+ elif diff_paren or diff_brack or diff_curly:
+ diff_paren += prevtext.count(')') - prevtext.count('(')
+ diff_brack += prevtext.count(']') - prevtext.count('[')
+ diff_curly += prevtext.count('}') - prevtext.count('{')
+ if not (diff_paren or diff_brack or diff_curly):
+ break
+ else:
+ break
+
+ if prevline:
+ correct_indent = self.get_block_indentation(prevline)
+ else:
+ correct_indent = 0
+
+ indent = self.get_block_indentation(block_nb)
+
+ if add_indent:
+ if self.indent_chars == '\t':
+ correct_indent += self.tab_stop_width_spaces
+ else:
+ correct_indent += len(self.indent_chars)
+
+ if not comment_or_string:
+ if prevtext.endswith(':') and self.is_python_like():
+ # Indent
+ if self.indent_chars == '\t':
+ correct_indent += self.tab_stop_width_spaces
+ else:
+ correct_indent += len(self.indent_chars)
+ elif self.is_python_like() and \
+ (prevtext.endswith('continue') or
+ prevtext.endswith('break') or
+ prevtext.endswith('pass') or
+ ("return" in prevtext.strip().split()[:1] and
+ len(re.split(r'\(|\{|\[', prevtext)) ==
+ len(re.split(r'\)|\}|\]', prevtext)))):
+ # Unindent
+ if self.indent_chars == '\t':
+ correct_indent -= self.tab_stop_width_spaces
+ else:
+ correct_indent -= len(self.indent_chars)
+ elif len(re.split(r'\(|\{|\[', prevtext)) > 1:
+
+ # Check if all braces are matching using a stack
+ stack = ['dummy'] # Dummy elemet to avoid index errors
+ deactivate = None
+ for c in prevtext:
+ if deactivate is not None:
+ if c == deactivate:
+ deactivate = None
+ elif c in ["'", '"']:
+ deactivate = c
+ elif c in ['(', '[','{']:
+ stack.append(c)
+ elif c == ')' and stack[-1] == '(':
+ stack.pop()
+ elif c == ']' and stack[-1] == '[':
+ stack.pop()
+ elif c == '}' and stack[-1] == '{':
+ stack.pop()
+
+ if len(stack) == 1: # all braces matching
+ pass
+
+ # Hanging indent
+ # find out if the last one is (, {, or []})
+ # only if prevtext is long that the hanging indentation
+ elif (re.search(r'[\(|\{|\[]\s*$', prevtext) is not None and
+ ((self.indent_chars == '\t' and
+ self.tab_stop_width_spaces * 2 < len(prevtext)) or
+ (self.indent_chars.startswith(' ') and
+ len(self.indent_chars) * 2 < len(prevtext)))):
+ if self.indent_chars == '\t':
+ correct_indent += self.tab_stop_width_spaces * 2
+ else:
+ correct_indent += len(self.indent_chars) * 2
+ else:
+ rlmap = {")":"(", "]":"[", "}":"{"}
+ for par in rlmap:
+ i_right = prevtext.rfind(par)
+ if i_right != -1:
+ prevtext = prevtext[:i_right]
+ for _i in range(len(prevtext.split(par))):
+ i_left = prevtext.rfind(rlmap[par])
+ if i_left != -1:
+ prevtext = prevtext[:i_left]
+ else:
+ break
+ else:
+ if prevtext.strip():
+ if len(re.split(r'\(|\{|\[', prevtext)) > 1:
+ #correct indent only if there are still opening brackets
+ prevexpr = re.split(r'\(|\{|\[', prevtext)[-1]
+ correct_indent = len(prevtext)-len(prevexpr)
+ else:
+ correct_indent = len(prevtext)
+
+ if not (diff_paren or diff_brack or diff_curly) and \
+ not prevtext.endswith(':') and prevline:
+ cur_indent = self.get_block_indentation(block_nb - 1)
+ is_blank = not self.get_text_line(block_nb - 1).strip()
+ prevline_indent = self.get_block_indentation(prevline)
+ trailing_text = self.get_text_line(block_nb).strip()
+
+ if cur_indent < prevline_indent and \
+ (trailing_text or is_blank):
+ if cur_indent % len(self.indent_chars) == 0:
+ correct_indent = cur_indent
+ else:
+ correct_indent = cur_indent \
+ + (len(self.indent_chars) -
+ cur_indent % len(self.indent_chars))
+
+ if (forward and indent >= correct_indent) or \
+ (not forward and indent <= correct_indent):
+ # No indentation fix is necessary
+ return False
+
+ if correct_indent >= 0:
+ cursor = self.textCursor()
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ if self.indent_chars == '\t':
+ indent = indent // self.tab_stop_width_spaces
+ cursor.setPosition(cursor.position()+indent, QTextCursor.KeepAnchor)
+ cursor.removeSelectedText()
+ if self.indent_chars == '\t':
+ indent_text = '\t' * (correct_indent // self.tab_stop_width_spaces) \
+ + ' ' * (correct_indent % self.tab_stop_width_spaces)
+ else:
+ indent_text = ' '*correct_indent
+ cursor.insertText(indent_text)
+ return True
+
+ @Slot()
+ def clear_all_output(self):
+ """Removes all ouput in the ipynb format (Json only)"""
+ try:
+ nb = nbformat.reads(self.toPlainText(), as_version=4)
+ if nb.cells:
+ for cell in nb.cells:
+ if 'outputs' in cell:
+ cell['outputs'] = []
+ if 'prompt_number' in cell:
+ cell['prompt_number'] = None
+ # We do the following rather than using self.setPlainText
+ # to benefit from QTextEdit's undo/redo feature.
+ self.selectAll()
+ self.skip_rstrip = True
+ self.insertPlainText(nbformat.writes(nb))
+ self.skip_rstrip = False
+ except Exception as e:
+ QMessageBox.critical(self, _('Removal error'),
+ _("It was not possible to remove outputs from "
+ "this notebook. The error is:\n\n") + \
+ to_text_string(e))
+ return
+
+ @Slot()
+ def convert_notebook(self):
+ """Convert an IPython notebook to a Python script in editor"""
+ try:
+ nb = nbformat.reads(self.toPlainText(), as_version=4)
+ script = nbexporter().from_notebook_node(nb)[0]
+ except Exception as e:
+ QMessageBox.critical(self, _('Conversion error'),
+ _("It was not possible to convert this "
+ "notebook. The error is:\n\n") + \
+ to_text_string(e))
+ return
+ self.sig_new_file.emit(script)
+
+ def indent(self, force=False):
+ """
+ Indent current line or selection
+
+ force=True: indent even if cursor is not a the beginning of the line
+ """
+ leading_text = self.get_text('sol', 'cursor')
+ if self.has_selected_text():
+ self.add_prefix(self.indent_chars)
+ elif force or not leading_text.strip() \
+ or (self.tab_indents and self.tab_mode):
+ if self.is_python_like():
+ if not self.fix_indent(forward=True):
+ self.add_prefix(self.indent_chars)
+ else:
+ self.add_prefix(self.indent_chars)
+ else:
+ if len(self.indent_chars) > 1:
+ length = len(self.indent_chars)
+ self.insert_text(" "*(length-(len(leading_text) % length)))
+ else:
+ self.insert_text(self.indent_chars)
+ self.document_did_change()
+
+ def indent_or_replace(self):
+ """Indent or replace by 4 spaces depending on selection and tab mode"""
+ if (self.tab_indents and self.tab_mode) or not self.has_selected_text():
+ self.indent()
+ else:
+ cursor = self.textCursor()
+ if self.get_selected_text() == \
+ to_text_string(cursor.block().text()):
+ self.indent()
+ else:
+ cursor1 = self.textCursor()
+ cursor1.setPosition(cursor.selectionStart())
+ cursor2 = self.textCursor()
+ cursor2.setPosition(cursor.selectionEnd())
+ if cursor1.blockNumber() != cursor2.blockNumber():
+ self.indent()
+ else:
+ self.replace(self.indent_chars)
+
+ def unindent(self, force=False):
+ """
+ Unindent current line or selection
+
+ force=True: unindent even if cursor is not a the beginning of the line
+ """
+ if self.has_selected_text():
+ self.remove_prefix(self.indent_chars)
+ else:
+ leading_text = self.get_text('sol', 'cursor')
+ if force or not leading_text.strip() \
+ or (self.tab_indents and self.tab_mode):
+ if self.is_python_like():
+ if not self.fix_indent(forward=False):
+ self.remove_prefix(self.indent_chars)
+ elif leading_text.endswith('\t'):
+ self.remove_prefix('\t')
+ else:
+ self.remove_prefix(self.indent_chars)
+
+ @Slot()
+ def toggle_comment(self):
+ """Toggle comment on current line or selection"""
+ cursor = self.textCursor()
+ start_pos, end_pos = sorted([cursor.selectionStart(),
+ cursor.selectionEnd()])
+ cursor.setPosition(end_pos)
+ last_line = cursor.block().blockNumber()
+ if cursor.atBlockStart() and start_pos != end_pos:
+ last_line -= 1
+ cursor.setPosition(start_pos)
+ first_line = cursor.block().blockNumber()
+ # If the selection contains only commented lines and surrounding
+ # whitespace, uncomment. Otherwise, comment.
+ is_comment_or_whitespace = True
+ at_least_one_comment = False
+ for _line_nb in range(first_line, last_line+1):
+ text = to_text_string(cursor.block().text()).lstrip()
+ is_comment = text.startswith(self.comment_string)
+ is_whitespace = (text == '')
+ is_comment_or_whitespace *= (is_comment or is_whitespace)
+ if is_comment:
+ at_least_one_comment = True
+ cursor.movePosition(QTextCursor.NextBlock)
+ if is_comment_or_whitespace and at_least_one_comment:
+ self.uncomment()
+ else:
+ self.comment()
+
+ def is_comment(self, block):
+ """Detect inline comments.
+
+ Return True if the block is an inline comment.
+ """
+ if block is None:
+ return False
+ text = to_text_string(block.text()).lstrip()
+ return text.startswith(self.comment_string)
+
+ def comment(self):
+ """Comment current line or selection."""
+ self.add_prefix(self.comment_string + ' ')
+
+ def uncomment(self):
+ """Uncomment current line or selection."""
+ blockcomment = self.unblockcomment()
+ if not blockcomment:
+ self.remove_prefix(self.comment_string)
+
+ def __blockcomment_bar(self, compatibility=False):
+ """Handle versions of blockcomment bar for backwards compatibility."""
+ # Blockcomment bar in Spyder version >= 4
+ blockcomment_bar = self.comment_string + ' ' + '=' * (
+ 79 - len(self.comment_string + ' '))
+ if compatibility:
+ # Blockcomment bar in Spyder version < 4
+ blockcomment_bar = self.comment_string + '=' * (
+ 79 - len(self.comment_string))
+ return blockcomment_bar
+
+ def transform_to_uppercase(self):
+ """Change to uppercase current line or selection."""
+ cursor = self.textCursor()
+ prev_pos = cursor.position()
+ selected_text = to_text_string(cursor.selectedText())
+
+ if len(selected_text) == 0:
+ prev_pos = cursor.position()
+ cursor.select(QTextCursor.WordUnderCursor)
+ selected_text = to_text_string(cursor.selectedText())
+
+ s = selected_text.upper()
+ cursor.insertText(s)
+ self.set_cursor_position(prev_pos)
+ self.document_did_change()
+
+ def transform_to_lowercase(self):
+ """Change to lowercase current line or selection."""
+ cursor = self.textCursor()
+ prev_pos = cursor.position()
+ selected_text = to_text_string(cursor.selectedText())
+
+ if len(selected_text) == 0:
+ prev_pos = cursor.position()
+ cursor.select(QTextCursor.WordUnderCursor)
+ selected_text = to_text_string(cursor.selectedText())
+
+ s = selected_text.lower()
+ cursor.insertText(s)
+ self.set_cursor_position(prev_pos)
+ self.document_did_change()
+
+ def blockcomment(self):
+ """Block comment current line or selection."""
+ comline = self.__blockcomment_bar() + self.get_line_separator()
+ cursor = self.textCursor()
+ if self.has_selected_text():
+ self.extend_selection_to_complete_lines()
+ start_pos, end_pos = cursor.selectionStart(), cursor.selectionEnd()
+ else:
+ start_pos = end_pos = cursor.position()
+ cursor.beginEditBlock()
+ cursor.setPosition(start_pos)
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ while cursor.position() <= end_pos:
+ cursor.insertText(self.comment_string + " ")
+ cursor.movePosition(QTextCursor.EndOfBlock)
+ if cursor.atEnd():
+ break
+ cursor.movePosition(QTextCursor.NextBlock)
+ end_pos += len(self.comment_string + " ")
+ cursor.setPosition(end_pos)
+ cursor.movePosition(QTextCursor.EndOfBlock)
+ if cursor.atEnd():
+ cursor.insertText(self.get_line_separator())
+ else:
+ cursor.movePosition(QTextCursor.NextBlock)
+ cursor.insertText(comline)
+ cursor.setPosition(start_pos)
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ cursor.insertText(comline)
+ cursor.endEditBlock()
+ self.document_did_change()
+
+ def unblockcomment(self):
+ """Un-block comment current line or selection."""
+ # Needed for backward compatibility with Spyder previous blockcomments.
+ # See issue 2845
+ unblockcomment = self.__unblockcomment()
+ if not unblockcomment:
+ unblockcomment = self.__unblockcomment(compatibility=True)
+ else:
+ return unblockcomment
+ self.document_did_change()
+
+ def __unblockcomment(self, compatibility=False):
+ """Un-block comment current line or selection helper."""
+ def __is_comment_bar(cursor):
+ return to_text_string(cursor.block().text()
+ ).startswith(
+ self.__blockcomment_bar(compatibility=compatibility))
+ # Finding first comment bar
+ cursor1 = self.textCursor()
+ if __is_comment_bar(cursor1):
+ return
+ while not __is_comment_bar(cursor1):
+ cursor1.movePosition(QTextCursor.PreviousBlock)
+ if cursor1.atStart():
+ break
+ if not __is_comment_bar(cursor1):
+ return False
+ def __in_block_comment(cursor):
+ cs = self.comment_string
+ return to_text_string(cursor.block().text()).startswith(cs)
+ # Finding second comment bar
+ cursor2 = QTextCursor(cursor1)
+ cursor2.movePosition(QTextCursor.NextBlock)
+ while not __is_comment_bar(cursor2) and __in_block_comment(cursor2):
+ cursor2.movePosition(QTextCursor.NextBlock)
+ if cursor2.block() == self.document().lastBlock():
+ break
+ if not __is_comment_bar(cursor2):
+ return False
+ # Removing block comment
+ cursor3 = self.textCursor()
+ cursor3.beginEditBlock()
+ cursor3.setPosition(cursor1.position())
+ cursor3.movePosition(QTextCursor.NextBlock)
+ while cursor3.position() < cursor2.position():
+ cursor3.movePosition(QTextCursor.NextCharacter,
+ QTextCursor.KeepAnchor)
+ if not cursor3.atBlockEnd():
+ # standard commenting inserts '# ' but a trailing space on an
+ # empty line might be stripped.
+ if not compatibility:
+ cursor3.movePosition(QTextCursor.NextCharacter,
+ QTextCursor.KeepAnchor)
+ cursor3.removeSelectedText()
+ cursor3.movePosition(QTextCursor.NextBlock)
+ for cursor in (cursor2, cursor1):
+ cursor3.setPosition(cursor.position())
+ cursor3.select(QTextCursor.BlockUnderCursor)
+ cursor3.removeSelectedText()
+ cursor3.endEditBlock()
+ return True
+
+ #------Kill ring handlers
+ # Taken from Jupyter's QtConsole
+ # Copyright (c) 2001-2015, IPython Development Team
+ # Copyright (c) 2015-, Jupyter Development Team
+ def kill_line_end(self):
+ """Kill the text on the current line from the cursor forward"""
+ cursor = self.textCursor()
+ cursor.clearSelection()
+ cursor.movePosition(QTextCursor.EndOfLine, QTextCursor.KeepAnchor)
+ if not cursor.hasSelection():
+ # Line deletion
+ cursor.movePosition(QTextCursor.NextBlock,
+ QTextCursor.KeepAnchor)
+ self._kill_ring.kill_cursor(cursor)
+ self.setTextCursor(cursor)
+ self.document_did_change()
+
+ def kill_line_start(self):
+ """Kill the text on the current line from the cursor backward"""
+ cursor = self.textCursor()
+ cursor.clearSelection()
+ cursor.movePosition(QTextCursor.StartOfBlock,
+ QTextCursor.KeepAnchor)
+ self._kill_ring.kill_cursor(cursor)
+ self.setTextCursor(cursor)
+ self.document_did_change()
+
+ def _get_word_start_cursor(self, position):
+ """Find the start of the word to the left of the given position. If a
+ sequence of non-word characters precedes the first word, skip over
+ them. (This emulates the behavior of bash, emacs, etc.)
+ """
+ document = self.document()
+ position -= 1
+ while (position and not
+ is_letter_or_number(document.characterAt(position))):
+ position -= 1
+ while position and is_letter_or_number(document.characterAt(position)):
+ position -= 1
+ cursor = self.textCursor()
+ cursor.setPosition(position + 1)
+ return cursor
+
+ def _get_word_end_cursor(self, position):
+ """Find the end of the word to the right of the given position. If a
+ sequence of non-word characters precedes the first word, skip over
+ them. (This emulates the behavior of bash, emacs, etc.)
+ """
+ document = self.document()
+ cursor = self.textCursor()
+ position = cursor.position()
+ cursor.movePosition(QTextCursor.End)
+ end = cursor.position()
+ while (position < end and
+ not is_letter_or_number(document.characterAt(position))):
+ position += 1
+ while (position < end and
+ is_letter_or_number(document.characterAt(position))):
+ position += 1
+ cursor.setPosition(position)
+ return cursor
+
+ def kill_prev_word(self):
+ """Kill the previous word"""
+ position = self.textCursor().position()
+ cursor = self._get_word_start_cursor(position)
+ cursor.setPosition(position, QTextCursor.KeepAnchor)
+ self._kill_ring.kill_cursor(cursor)
+ self.setTextCursor(cursor)
+ self.document_did_change()
+
+ def kill_next_word(self):
+ """Kill the next word"""
+ position = self.textCursor().position()
+ cursor = self._get_word_end_cursor(position)
+ cursor.setPosition(position, QTextCursor.KeepAnchor)
+ self._kill_ring.kill_cursor(cursor)
+ self.setTextCursor(cursor)
+ self.document_did_change()
+
+ #------Autoinsertion of quotes/colons
+ def __get_current_color(self, cursor=None):
+ """Get the syntax highlighting color for the current cursor position"""
+ if cursor is None:
+ cursor = self.textCursor()
+
+ block = cursor.block()
+ pos = cursor.position() - block.position() # relative pos within block
+ layout = block.layout()
+ block_formats = layout.additionalFormats()
+
+ if block_formats:
+ # To easily grab current format for autoinsert_colons
+ if cursor.atBlockEnd():
+ current_format = block_formats[-1].format
+ else:
+ current_format = None
+ for fmt in block_formats:
+ if (pos >= fmt.start) and (pos < fmt.start + fmt.length):
+ current_format = fmt.format
+ if current_format is None:
+ return None
+ color = current_format.foreground().color().name()
+ return color
+ else:
+ return None
+
+ def in_comment_or_string(self, cursor=None):
+ """Is the cursor inside or next to a comment or string?"""
+ if self.highlighter:
+ if cursor is None:
+ current_color = self.__get_current_color()
+ else:
+ current_color = self.__get_current_color(cursor=cursor)
+
+ comment_color = self.highlighter.get_color_name('comment')
+ string_color = self.highlighter.get_color_name('string')
+ if (current_color == comment_color) or (current_color == string_color):
+ return True
+ else:
+ return False
+ else:
+ return False
+
+ def __colon_keyword(self, text):
+ stmt_kws = ['def', 'for', 'if', 'while', 'with', 'class', 'elif',
+ 'except']
+ whole_kws = ['else', 'try', 'except', 'finally']
+ text = text.lstrip()
+ words = text.split()
+ if any([text == wk for wk in whole_kws]):
+ return True
+ elif len(words) < 2:
+ return False
+ elif any([words[0] == sk for sk in stmt_kws]):
+ return True
+ else:
+ return False
+
+ def __forbidden_colon_end_char(self, text):
+ end_chars = [':', '\\', '[', '{', '(', ',']
+ text = text.rstrip()
+ if any([text.endswith(c) for c in end_chars]):
+ return True
+ else:
+ return False
+
+ def __has_colon_not_in_brackets(self, text):
+ """
+ Return whether a string has a colon which is not between brackets.
+ This function returns True if the given string has a colon which is
+ not between a pair of (round, square or curly) brackets. It assumes
+ that the brackets in the string are balanced.
+ """
+ bracket_ext = self.editor_extensions.get(CloseBracketsExtension)
+ for pos, char in enumerate(text):
+ if (char == ':' and
+ not bracket_ext.unmatched_brackets_in_line(text[:pos])):
+ return True
+ return False
+
+ def autoinsert_colons(self):
+ """Decide if we want to autoinsert colons"""
+ bracket_ext = self.editor_extensions.get(CloseBracketsExtension)
+ self.completion_widget.hide()
+ line_text = self.get_text('sol', 'cursor')
+ if not self.textCursor().atBlockEnd():
+ return False
+ elif self.in_comment_or_string():
+ return False
+ elif not self.__colon_keyword(line_text):
+ return False
+ elif self.__forbidden_colon_end_char(line_text):
+ return False
+ elif bracket_ext.unmatched_brackets_in_line(line_text):
+ return False
+ elif self.__has_colon_not_in_brackets(line_text):
+ return False
+ else:
+ return True
+
+ def next_char(self):
+ cursor = self.textCursor()
+ cursor.movePosition(QTextCursor.NextCharacter,
+ QTextCursor.KeepAnchor)
+ next_char = to_text_string(cursor.selectedText())
+ return next_char
+
+ def in_comment(self, cursor=None):
+ if self.highlighter:
+ current_color = self.__get_current_color(cursor)
+ comment_color = self.highlighter.get_color_name('comment')
+ if current_color == comment_color:
+ return True
+ else:
+ return False
+ else:
+ return False
+
+ def in_string(self, cursor=None):
+ if self.highlighter:
+ current_color = self.__get_current_color(cursor)
+ string_color = self.highlighter.get_color_name('string')
+ if current_color == string_color:
+ return True
+ else:
+ return False
+ else:
+ return False
+
+ # ------ Qt Event handlers
+ def setup_context_menu(self):
+ """Setup context menu"""
+ self.undo_action = create_action(
+ self, _("Undo"), icon=ima.icon('undo'),
+ shortcut=get_shortcut('editor', 'undo'), triggered=self.undo)
+ self.redo_action = create_action(
+ self, _("Redo"), icon=ima.icon('redo'),
+ shortcut=get_shortcut('editor', 'redo'), triggered=self.redo)
+ self.cut_action = create_action(
+ self, _("Cut"), icon=ima.icon('editcut'),
+ shortcut=get_shortcut('editor', 'cut'), triggered=self.cut)
+ self.copy_action = create_action(
+ self, _("Copy"), icon=ima.icon('editcopy'),
+ shortcut=get_shortcut('editor', 'copy'), triggered=self.copy)
+ self.paste_action = create_action(
+ self, _("Paste"), icon=ima.icon('editpaste'),
+ shortcut=get_shortcut('editor', 'paste'), triggered=self.paste)
+ selectall_action = create_action(
+ self, _("Select All"), icon=ima.icon('selectall'),
+ shortcut=get_shortcut('editor', 'select all'),
+ triggered=self.selectAll)
+ toggle_comment_action = create_action(
+ self, _("Comment")+"/"+_("Uncomment"), icon=ima.icon('comment'),
+ shortcut=get_shortcut('editor', 'toggle comment'),
+ triggered=self.toggle_comment)
+ self.clear_all_output_action = create_action(
+ self, _("Clear all ouput"), icon=ima.icon('ipython_console'),
+ triggered=self.clear_all_output)
+ self.ipynb_convert_action = create_action(
+ self, _("Convert to Python script"), icon=ima.icon('python'),
+ triggered=self.convert_notebook)
+ self.gotodef_action = create_action(
+ self, _("Go to definition"),
+ shortcut=get_shortcut('editor', 'go to definition'),
+ triggered=self.go_to_definition_from_cursor)
+
+ # Run actions
+ self.run_cell_action = create_action(
+ self, _("Run cell"), icon=ima.icon('run_cell'),
+ shortcut=get_shortcut('editor', 'run cell'),
+ triggered=self.sig_run_cell.emit)
+ self.run_cell_and_advance_action = create_action(
+ self, _("Run cell and advance"), icon=ima.icon('run_cell'),
+ shortcut=get_shortcut('editor', 'run cell and advance'),
+ triggered=self.sig_run_cell_and_advance.emit)
+ self.re_run_last_cell_action = create_action(
+ self, _("Re-run last cell"), icon=ima.icon('run_cell'),
+ shortcut=get_shortcut('editor', 're-run last cell'),
+ triggered=self.sig_re_run_last_cell.emit)
+ self.run_selection_action = create_action(
+ self, _("Run &selection or current line"),
+ icon=ima.icon('run_selection'),
+ shortcut=get_shortcut('editor', 'run selection'),
+ triggered=self.sig_run_selection.emit)
+
+ # Zoom actions
+ zoom_in_action = create_action(
+ self, _("Zoom in"), icon=ima.icon('zoom_in'),
+ shortcut=QKeySequence(QKeySequence.ZoomIn),
+ triggered=self.zoom_in.emit)
+ zoom_out_action = create_action(
+ self, _("Zoom out"), icon=ima.icon('zoom_out'),
+ shortcut=QKeySequence(QKeySequence.ZoomOut),
+ triggered=self.zoom_out.emit)
+ zoom_reset_action = create_action(
+ self, _("Zoom reset"), shortcut=QKeySequence("Ctrl+0"),
+ triggered=self.zoom_reset.emit)
+
+ # Docstring
+ writer = self.writer_docstring
+ self.docstring_action = create_action(
+ self, _("Generate docstring"),
+ shortcut=get_shortcut('editor', 'docstring'),
+ triggered=writer.write_docstring_at_first_line_of_function)
+
+ # Build menu
+ self.menu = QMenu(self)
+ actions_1 = [self.run_cell_action, self.run_cell_and_advance_action,
+ self.re_run_last_cell_action, self.run_selection_action,
+ self.gotodef_action, None, self.undo_action,
+ self.redo_action, None, self.cut_action,
+ self.copy_action, self.paste_action, selectall_action]
+ actions_2 = [None, zoom_in_action, zoom_out_action, zoom_reset_action,
+ None, toggle_comment_action, self.docstring_action]
+ if nbformat is not None:
+ nb_actions = [self.clear_all_output_action,
+ self.ipynb_convert_action, None]
+ actions = actions_1 + nb_actions + actions_2
+ add_actions(self.menu, actions)
+ else:
+ actions = actions_1 + actions_2
+ add_actions(self.menu, actions)
+
+ # Read-only context-menu
+ self.readonly_menu = QMenu(self)
+ add_actions(self.readonly_menu,
+ (self.copy_action, None, selectall_action,
+ self.gotodef_action))
+
+ def keyReleaseEvent(self, event):
+ """Override Qt method."""
+ self.sig_key_released.emit(event)
+ self.timer_syntax_highlight.start()
+ self.clear_extra_selections('ctrl_click')
+ self._last_hover_uri = None
+ super(CodeEditor, self).keyReleaseEvent(event)
+ event.ignore()
+
+ def event(self, event):
+ """Qt method override."""
+ if event.type() == QEvent.ShortcutOverride:
+ event.ignore()
+ return False
+ else:
+ return super(CodeEditor, self).event(event)
+
+ def keyPressEvent(self, event):
+ """Reimplement Qt method"""
+ # Send the signal to the editor's extension.
+ event.ignore()
+ self.sig_key_pressed.emit(event)
+
+ key = event.key()
+ text = to_text_string(event.text())
+ has_selection = self.has_selected_text()
+ ctrl = event.modifiers() & Qt.ControlModifier
+ shift = event.modifiers() & Qt.ShiftModifier
+
+ if text:
+ self.__clear_occurrences()
+ if QToolTip.isVisible():
+ self.hide_tooltip_if_necessary(key)
+
+ if event.isAccepted():
+ # The event was handled by one of the editor extension.
+ return
+
+ if key in [Qt.Key_Control, Qt.Key_Shift, Qt.Key_Alt,
+ Qt.Key_Meta, Qt.KeypadModifier]:
+ # The user pressed only a modifier key.
+ if ctrl:
+ pos = self.mapFromGlobal(QCursor.pos())
+ pos = self.calculate_real_position_from_global(pos)
+ if self._handle_goto_uri_event(pos):
+ event.accept()
+ return
+
+ if self._handle_goto_definition_event(pos):
+ event.accept()
+ return
+ return
+
+ # ---- Handle hard coded and builtin actions
+ operators = {'+', '-', '*', '**', '/', '//', '%', '@', '<<', '>>',
+ '&', '|', '^', '~', '<', '>', '<=', '>=', '==', '!='}
+ delimiters = {',', ':', ';', '@', '=', '->', '+=', '-=', '*=', '/=',
+ '//=', '%=', '@=', '&=', '|=', '^=', '>>=', '<<=', '**='}
+
+ if not shift and not ctrl:
+ self.hide_tooltip()
+
+ if text in operators or text in delimiters:
+ self.completion_widget.hide()
+ if key in (Qt.Key_Enter, Qt.Key_Return):
+ if not shift and not ctrl:
+ if self.add_colons_enabled and self.is_python_like() and \
+ self.autoinsert_colons():
+ self.textCursor().beginEditBlock()
+ self.insert_text(':' + self.get_line_separator())
+ self.fix_and_strip_indent()
+ self.textCursor().endEditBlock()
+ elif self.is_completion_widget_visible():
+ self.select_completion_list()
+ else:
+ # Check if we're in a comment or a string at the
+ # current position
+ cmt_or_str_cursor = self.in_comment_or_string()
+
+ # Check if the line start with a comment or string
+ cursor = self.textCursor()
+ cursor.setPosition(cursor.block().position(),
+ QTextCursor.KeepAnchor)
+ cmt_or_str_line_begin = self.in_comment_or_string(
+ cursor=cursor)
+
+ # Check if we are in a comment or a string
+ cmt_or_str = cmt_or_str_cursor and cmt_or_str_line_begin
+
+ self.textCursor().beginEditBlock()
+ TextEditBaseWidget.keyPressEvent(self, event)
+ self.fix_and_strip_indent(comment_or_string=cmt_or_str)
+ self.textCursor().endEditBlock()
+ elif key == Qt.Key_Insert and not shift and not ctrl:
+ self.setOverwriteMode(not self.overwriteMode())
+ elif key == Qt.Key_Backspace and not shift and not ctrl:
+ leading_text = self.get_text('sol', 'cursor')
+ leading_length = len(leading_text)
+ trailing_spaces = leading_length-len(leading_text.rstrip())
+ if has_selection or not self.intelligent_backspace:
+ TextEditBaseWidget.keyPressEvent(self, event)
+ else:
+ trailing_text = self.get_text('cursor', 'eol')
+ if not leading_text.strip() \
+ and leading_length > len(self.indent_chars):
+ if leading_length % len(self.indent_chars) == 0:
+ self.unindent()
+ else:
+ TextEditBaseWidget.keyPressEvent(self, event)
+ elif trailing_spaces and not trailing_text.strip():
+ self.remove_suffix(leading_text[-trailing_spaces:])
+ elif leading_text and trailing_text and \
+ leading_text[-1]+trailing_text[0] in ('()', '[]', '{}',
+ '\'\'', '""'):
+ cursor = self.textCursor()
+ cursor.movePosition(QTextCursor.PreviousCharacter)
+ cursor.movePosition(QTextCursor.NextCharacter,
+ QTextCursor.KeepAnchor, 2)
+ cursor.removeSelectedText()
+ else:
+ TextEditBaseWidget.keyPressEvent(self, event)
+ elif key == Qt.Key_Home:
+ self.stdkey_home(shift, ctrl)
+ elif key == Qt.Key_End:
+ # See Issue 495: on MacOS X, it is necessary to redefine this
+ # basic action which should have been implemented natively
+ self.stdkey_end(shift, ctrl)
+ elif text in self.auto_completion_characters:
+ self.insert_text(text)
+ if not self.in_comment_or_string():
+ last_obj = getobj(self.get_text('sol', 'cursor'))
+ if last_obj and not last_obj.isdigit():
+ self.do_completion(automatic=True)
+ elif (text != '(' and text in self.signature_completion_characters and
+ not self.has_selected_text()):
+ self.insert_text(text)
+ self.request_signature()
+ elif key == Qt.Key_Colon and not has_selection \
+ and self.auto_unindent_enabled:
+ leading_text = self.get_text('sol', 'cursor')
+ if leading_text.lstrip() in ('else', 'finally'):
+ ind = lambda txt: len(txt)-len(txt.lstrip())
+ prevtxt = to_text_string(self.textCursor(
+ ).block().previous().text())
+ if ind(leading_text) == ind(prevtxt):
+ self.unindent(force=True)
+ TextEditBaseWidget.keyPressEvent(self, event)
+ elif key == Qt.Key_Space and not shift and not ctrl \
+ and not has_selection and self.auto_unindent_enabled:
+ self.completion_widget.hide()
+ leading_text = self.get_text('sol', 'cursor')
+ if leading_text.lstrip() in ('elif', 'except'):
+ ind = lambda txt: len(txt)-len(txt.lstrip())
+ prevtxt = to_text_string(self.textCursor(
+ ).block().previous().text())
+ if ind(leading_text) == ind(prevtxt):
+ self.unindent(force=True)
+ TextEditBaseWidget.keyPressEvent(self, event)
+ elif key == Qt.Key_Tab:
+ # Important note: can't be called with a QShortcut because
+ # of its singular role with respect to widget focus management
+ if not has_selection and not self.tab_mode:
+ self.intelligent_tab()
+ else:
+ # indent the selected text
+ self.indent_or_replace()
+ elif key == Qt.Key_Backtab:
+ # Backtab, i.e. Shift+, could be treated as a QShortcut but
+ # there is no point since can't (see above)
+ if not has_selection and not self.tab_mode:
+ self.intelligent_backtab()
+ else:
+ # indent the selected text
+ self.unindent()
+ event.accept()
+ elif not event.isAccepted():
+ TextEditBaseWidget.keyPressEvent(self, event)
+ if len(text) > 0:
+ self.document_did_change(text)
+ # self.do_completion(automatic=True)
+ if not event.modifiers():
+ # Accept event to avoid it being handled by the parent
+ # Modifiers should be passed to the parent because they
+ # could be shortcuts
+ event.accept()
+
+ def fix_and_strip_indent(self, comment_or_string=False):
+ """Automatically fix indent and strip previous automatic indent."""
+ # Fix indent
+ cursor_before = self.textCursor().position()
+ # A change just occured on the last line (return was pressed)
+ if cursor_before > 0:
+ self.last_change_position = cursor_before - 1
+ self.fix_indent(comment_or_string=comment_or_string)
+ cursor_after = self.textCursor().position()
+ # Remove previous spaces and update last_auto_indent
+ nspaces_removed = self.strip_trailing_spaces()
+ self.last_auto_indent = (cursor_before - nspaces_removed,
+ cursor_after - nspaces_removed)
+ self.document_did_change()
+
+ def run_pygments_highlighter(self):
+ """Run pygments highlighter."""
+ if isinstance(self.highlighter, sh.PygmentsSH):
+ self.highlighter.make_charlist()
+
+ def get_uri_at(self, coordinates):
+ """Return uri and cursor for if uri found at coordinates."""
+ return self.get_pattern_cursor_at(sh.URI_PATTERNS, coordinates)
+
+ def get_pattern_cursor_at(self, pattern, coordinates):
+ """
+ Find pattern located at the line where the coordinate is located.
+
+ This returns the actual match and the cursor that selects the text.
+ """
+ # Check if the pattern is in line
+ line = self.get_line_at(coordinates)
+ match = pattern.search(line)
+ uri = None
+ cursor = None
+
+ while match:
+ start, end = match.span()
+
+ # Get cursor selection if pattern found
+ cursor = self.cursorForPosition(coordinates)
+ cursor.movePosition(QTextCursor.StartOfBlock)
+ line_start_position = cursor.position()
+
+ cursor.setPosition(line_start_position + start, cursor.MoveAnchor)
+ start_rect = self.cursorRect(cursor)
+ cursor.setPosition(line_start_position + end, cursor.MoveAnchor)
+ end_rect = self.cursorRect(cursor)
+ bounding_rect = start_rect.united(end_rect)
+
+ # Check if coordinates are located within the selection rect
+ if bounding_rect.contains(coordinates):
+ uri = line[start:end]
+ cursor.setPosition(line_start_position + start,
+ cursor.KeepAnchor)
+ break
+ else:
+ match = pattern.search(line, end)
+
+ return uri, cursor
+
+ def _preprocess_file_uri(self, uri):
+ """Format uri to conform to absolute or relative file paths."""
+ fname = uri.replace('file://', '')
+ if fname[-1] == '/':
+ fname = fname[:-1]
+ dirname = osp.dirname(osp.abspath(self.filename))
+ if osp.isdir(dirname):
+ if not osp.isfile(fname):
+ # Maybe relative
+ fname = osp.join(dirname, fname)
+ return fname
+
+ def _handle_goto_definition_event(self, pos):
+ """Check if goto definition can be applied and apply highlight."""
+ text = self.get_word_at(pos)
+ if text and not sourcecode.is_keyword(to_text_string(text)):
+ if not self.__cursor_changed:
+ QApplication.setOverrideCursor(QCursor(Qt.PointingHandCursor))
+ self.__cursor_changed = True
+ cursor = self.cursorForPosition(pos)
+ cursor.select(QTextCursor.WordUnderCursor)
+ self.clear_extra_selections('ctrl_click')
+ self.__highlight_selection(
+ 'ctrl_click', cursor, update=True,
+ foreground_color=self.ctrl_click_color,
+ underline_color=self.ctrl_click_color,
+ underline_style=QTextCharFormat.SingleUnderline)
+ return True
+ else:
+ return False
+
+ def _handle_goto_uri_event(self, pos):
+ """Check if go to uri can be applied and apply highlight."""
+ uri, cursor = self.get_uri_at(pos)
+ if uri and cursor:
+ color = self.ctrl_click_color
+
+ if uri.startswith('file://'):
+ fname = self._preprocess_file_uri(uri)
+ if not osp.isfile(fname):
+ color = QColor(255, 80, 80)
+
+ self.clear_extra_selections('ctrl_click')
+ self.__highlight_selection(
+ 'ctrl_click', cursor, update=True,
+ foreground_color=color,
+ underline_color=color,
+ underline_style=QTextCharFormat.SingleUnderline)
+ if not self.__cursor_changed:
+ QApplication.setOverrideCursor(
+ QCursor(Qt.PointingHandCursor))
+ self.__cursor_changed = True
+ self._last_hover_uri = uri
+ self.sig_uri_found.emit(uri)
+ return True
+ else:
+ self._last_hover_uri = uri
+ return False
+
+ def line_range(self, position):
+ """
+ Get line range from position.
+ """
+ if position is None:
+ return None
+ if position >= self.document().characterCount():
+ return None
+ # Check if still on the line
+ cursor = self.textCursor()
+ cursor.setPosition(position)
+ line_range = (cursor.block().position(),
+ cursor.block().position()
+ + cursor.block().length() - 1)
+ return line_range
+
+ def strip_trailing_spaces(self):
+ """
+ Strip trailing spaces if needed.
+
+ Remove trailing whitespace on leaving a non-string line containing it.
+ Return the number of removed spaces.
+ """
+ # Update current position
+ current_position = self.textCursor().position()
+ last_position = self.last_position
+ self.last_position = current_position
+
+ if self.skip_rstrip:
+ return 0
+
+ line_range = self.line_range(last_position)
+ if line_range is None:
+ # Doesn't apply
+ return 0
+
+ def pos_in_line(pos):
+ """Check if pos is in last line."""
+ if pos is None:
+ return False
+ return line_range[0] <= pos <= line_range[1]
+
+ if pos_in_line(current_position):
+ # Check if still on the line
+ return 0
+
+ if not self.strip_trailing_spaces_on_modify:
+ if self.last_auto_indent is None:
+ return 0
+ elif (self.last_auto_indent !=
+ self.line_range(self.last_auto_indent[0])):
+ # line not empty
+ self.last_auto_indent = None
+ return 0
+ line_range = self.last_auto_indent
+ self.last_auto_indent = None
+ elif not pos_in_line(self.last_change_position):
+ # Should process if pressed return or made a change on the line:
+ return 0
+
+ # Check if end of line in string
+ cursor = self.textCursor()
+ cursor.setPosition(line_range[1])
+ if self.in_string(cursor=cursor):
+ return 0
+
+ cursor.setPosition(line_range[0])
+ cursor.setPosition(line_range[1],
+ QTextCursor.KeepAnchor)
+ # remove spaces on the right
+ text = cursor.selectedText()
+ strip = text.rstrip()
+
+ if line_range[0] + len(strip) < line_range[1]:
+ # Select text to remove
+ cursor.setPosition(line_range[0] + len(strip))
+ cursor.setPosition(line_range[1],
+ QTextCursor.KeepAnchor)
+ cursor.removeSelectedText()
+ self.document_did_change()
+ # Correct last change position
+ self.last_change_position = line_range[1]
+ return line_range[1] - (line_range[0] + len(strip))
+ return 0
+
+
+ def mouseMoveEvent(self, event):
+ """Underline words when pressing """
+ # Restart timer every time the mouse is moved
+ # This is needed to correctly handle hover hints with a delay
+ self._timer_mouse_moving.start()
+
+ pos = event.pos()
+ self._last_point = pos
+ alt = event.modifiers() & Qt.AltModifier
+ ctrl = event.modifiers() & Qt.ControlModifier
+ shift = event.modifiers() & Qt.ShiftModifier
+
+ if alt:
+ self.sig_alt_mouse_moved.emit(event)
+ event.accept()
+ return
+
+ if ctrl:
+ if self._handle_goto_uri_event(pos):
+ event.accept()
+ return
+
+ if self.has_selected_text():
+ TextEditBaseWidget.mouseMoveEvent(self, event)
+ return
+
+ if self.go_to_definition_enabled and ctrl:
+ if self._handle_goto_definition_event(pos):
+ event.accept()
+ return
+
+ if self.__cursor_changed:
+ QApplication.restoreOverrideCursor()
+ self.__cursor_changed = False
+ self.clear_extra_selections('ctrl_click')
+ else:
+ if not self._should_display_hover(pos):
+ self.hide_tooltip()
+
+ TextEditBaseWidget.mouseMoveEvent(self, event)
+
+ def setPlainText(self, txt):
+ """
+ Extends setPlainText to emit the new_text_set signal.
+
+ :param txt: The new text to set.
+ :param mime_type: Associated mimetype. Setting the mime will update the
+ pygments lexer.
+ :param encoding: text encoding
+ """
+ super(CodeEditor, self).setPlainText(txt)
+ self.new_text_set.emit()
+
+ def focusOutEvent(self, event):
+ """Reimplement Qt method"""
+ self.sig_focus_changed.emit()
+ super(CodeEditor, self).focusOutEvent(event)
+
+ def leaveEvent(self, event):
+ """If cursor has not been restored yet, do it now"""
+ self.sig_leave_out.emit()
+ if self.__cursor_changed:
+ QApplication.restoreOverrideCursor()
+ self.__cursor_changed = False
+ self.clear_extra_selections('ctrl_click')
+ self._last_hover_uri = None
+ TextEditBaseWidget.leaveEvent(self, event)
+
+ def mousePressEvent(self, event):
+ """Override Qt method."""
+ ctrl = event.modifiers() & Qt.ControlModifier
+ alt = event.modifiers() & Qt.AltModifier
+ pos = event.pos()
+ if event.button() == Qt.LeftButton and ctrl:
+ TextEditBaseWidget.mousePressEvent(self, event)
+ cursor = self.cursorForPosition(pos)
+
+ if self._last_hover_uri:
+ uri = self._last_hover_uri
+ if uri.startswith('file://'):
+ fname = self._preprocess_file_uri(uri)
+
+ if osp.isfile(fname) and encoding.is_text_file(fname):
+ # Open in editor
+ self.go_to_definition.emit(fname, 0, 0)
+ else:
+ # Use external program
+ fname = file_uri(fname)
+ programs.start_file(fname)
+ elif uri.startswith(('http', 'mailto:')):
+ quri = QUrl(uri)
+ QDesktopServices.openUrl(quri)
+ else:
+ # Issue URI
+ service = 'https://github.com/'
+ uri = uri.replace('#', '/issues/')
+
+ if uri.startswith('gh:') or ':' not in uri:
+ # Github
+ if uri.startswith('gh:'):
+ uri = uri[3:]
+ service = 'https://github.com/'
+ elif uri.startswith('gl:'):
+ # Gitlab
+ uri = uri[3:]
+ service = 'https://gitlab.com/'
+ elif uri.startswith('bb:'):
+ # Bitbucket
+ uri = uri[3:]
+ service = 'https://bitbucket.org/'
+
+ quri = QUrl(service + uri)
+ QDesktopServices.openUrl(quri)
+
+ self.sig_go_to_uri.emit(uri)
+ else:
+ self.go_to_definition_from_cursor(cursor)
+ elif event.button() == Qt.LeftButton and alt:
+ self.sig_alt_left_mouse_pressed.emit(event)
+ else:
+ TextEditBaseWidget.mousePressEvent(self, event)
+
+ def contextMenuEvent(self, event):
+ """Reimplement Qt method"""
+ nonempty_selection = self.has_selected_text()
+ self.copy_action.setEnabled(nonempty_selection)
+ self.cut_action.setEnabled(nonempty_selection)
+ self.clear_all_output_action.setVisible(self.is_json() and
+ nbformat is not None)
+ self.ipynb_convert_action.setVisible(self.is_json() and
+ nbformat is not None)
+ self.run_cell_action.setVisible(self.is_python())
+ self.run_cell_and_advance_action.setVisible(self.is_python())
+ self.run_selection_action.setVisible(self.is_python())
+ self.re_run_last_cell_action.setVisible(self.is_python())
+ self.gotodef_action.setVisible(self.go_to_definition_enabled)
+
+ # Check if a docstring is writable
+ writer = self.writer_docstring
+ writer.line_number_cursor = self.get_line_number_at(event.pos())
+ result = writer.get_function_definition_from_first_line()
+
+ if result:
+ self.docstring_action.setEnabled(True)
+ else:
+ self.docstring_action.setEnabled(False)
+
+ # Code duplication go_to_definition_from_cursor and mouse_move_event
+ cursor = self.textCursor()
+ text = to_text_string(cursor.selectedText())
+ if len(text) == 0:
+ cursor.select(QTextCursor.WordUnderCursor)
+ text = to_text_string(cursor.selectedText())
+
+ self.undo_action.setEnabled(self.document().isUndoAvailable())
+ self.redo_action.setEnabled(self.document().isRedoAvailable())
+ menu = self.menu
+ if self.isReadOnly():
+ menu = self.readonly_menu
+ menu.popup(event.globalPos())
+ event.accept()
+
+ #------ Drag and drop
+ def dragEnterEvent(self, event):
+ """Reimplement Qt method
+ Inform Qt about the types of data that the widget accepts"""
+ if mimedata2url(event.mimeData()):
+ # Let the parent widget handle this
+ event.ignore()
+ else:
+ TextEditBaseWidget.dragEnterEvent(self, event)
+
+ def dropEvent(self, event):
+ """Reimplement Qt method
+ Unpack dropped data and handle it"""
+ if mimedata2url(event.mimeData()):
+ # Let the parent widget handle this
+ event.ignore()
+ else:
+ TextEditBaseWidget.dropEvent(self, event)
+
+ #------ Paint event
+ def paintEvent(self, event):
+ """Overrides paint event to update the list of visible blocks"""
+ self.update_visible_blocks(event)
+ TextEditBaseWidget.paintEvent(self, event)
+ self.painted.emit(event)
+
+ def update_visible_blocks(self, event):
+ """Update the list of visible blocks/lines position"""
+ self.__visible_blocks[:] = []
+ block = self.firstVisibleBlock()
+ blockNumber = block.blockNumber()
+ top = int(self.blockBoundingGeometry(block).translated(
+ self.contentOffset()).top())
+ bottom = top + int(self.blockBoundingRect(block).height())
+ ebottom_top = 0
+ ebottom_bottom = self.height()
+
+ while block.isValid():
+ visible = bottom <= ebottom_bottom
+ if not visible:
+ break
+ if block.isVisible():
+ self.__visible_blocks.append((top, blockNumber+1, block))
+ block = block.next()
+ top = bottom
+ bottom = top + int(self.blockBoundingRect(block).height())
+ blockNumber = block.blockNumber()
+
+ def _draw_editor_cell_divider(self):
+ """Draw a line on top of a define cell"""
+ if self.supported_cell_language:
+ cell_line_color = self.comment_color
+ painter = QPainter(self.viewport())
+ pen = painter.pen()
+ pen.setStyle(Qt.SolidLine)
+ pen.setBrush(cell_line_color)
+ painter.setPen(pen)
+
+ for top, line_number, block in self.visible_blocks:
+ if self.is_cell_separator(block):
+ painter.drawLine(4, top, self.width(), top)
+
+ @property
+ def visible_blocks(self):
+ """
+ Returns the list of visible blocks.
+
+ Each element in the list is a tuple made up of the line top position,
+ the line number (already 1 based), and the QTextBlock itself.
+
+ :return: A list of tuple(top position, line number, block)
+ :rtype: List of tuple(int, int, QtGui.QTextBlock)
+ """
+ return self.__visible_blocks
+
+ def is_editor(self):
+ return True
+
+ def popup_docstring(self, prev_text, prev_pos):
+ """Show the menu for generating docstring."""
+ line_text = self.textCursor().block().text()
+ if line_text != prev_text:
+ return
+
+ if prev_pos != self.textCursor().position():
+ return
+
+ writer = self.writer_docstring
+ if writer.get_function_definition_from_below_last_line():
+ point = self.cursorRect().bottomRight()
+ point = self.calculate_real_position(point)
+ point = self.mapToGlobal(point)
+
+ self.menu_docstring = QMenuOnlyForEnter(self)
+ self.docstring_action = create_action(
+ self, _("Generate docstring"), icon=ima.icon('TextFileIcon'),
+ triggered=writer.write_docstring)
+ self.menu_docstring.addAction(self.docstring_action)
+ self.menu_docstring.setActiveAction(self.docstring_action)
+ self.menu_docstring.popup(point)
+
+ def delayed_popup_docstring(self):
+ """Show context menu for docstring.
+
+ This method is called after typing '''. After typing ''', this function
+ waits 300ms. If there was no input for 300ms, show the context menu.
+ """
+ line_text = self.textCursor().block().text()
+ pos = self.textCursor().position()
+
+ timer = QTimer()
+ timer.singleShot(300, lambda: self.popup_docstring(line_text, pos))
+
+
+#===============================================================================
+# CodeEditor's Printer
+#===============================================================================
+
+#TODO: Implement the header and footer support
+class Printer(QPrinter):
+ def __init__(self, mode=QPrinter.ScreenResolution, header_font=None):
+ QPrinter.__init__(self, mode)
+ self.setColorMode(QPrinter.Color)
+ self.setPageOrder(QPrinter.FirstPageFirst)
+ self.date = time.ctime()
+ if header_font is not None:
+ self.header_font = header_font
+
+ # The following method is simply ignored by QPlainTextEdit
+ # (this is a copy from QsciEditor's Printer)
+ def formatPage(self, painter, drawing, area, pagenr):
+ header = '%s - %s - Page %s' % (self.docName(), self.date, pagenr)
+ painter.save()
+ painter.setFont(self.header_font)
+ painter.setPen(QColor(Qt.black))
+ if drawing:
+ painter.drawText(area.right()-painter.fontMetrics().width(header),
+ area.top()+painter.fontMetrics().ascent(), header)
+ area.setTop(area.top()+painter.fontMetrics().height()+5)
+ painter.restore()
+
+
+#===============================================================================
+# Editor + Class browser test
+#===============================================================================
+class TestWidget(QSplitter):
+ def __init__(self, parent):
+ QSplitter.__init__(self, parent)
+ self.editor = CodeEditor(self)
+ self.editor.setup_editor(linenumbers=True, markers=True, tab_mode=False,
+ font=QFont("Courier New", 10),
+ show_blanks=True, color_scheme='Zenburn')
+ self.addWidget(self.editor)
+ from spyder.plugins.outlineexplorer.widgets import OutlineExplorerWidget
+ self.classtree = OutlineExplorerWidget(self)
+ self.addWidget(self.classtree)
+ self.classtree.edit_goto.connect(
+ lambda _fn, line, word: self.editor.go_to_line(line, word))
+ self.setStretchFactor(0, 4)
+ self.setStretchFactor(1, 1)
+ self.setWindowIcon(ima.icon('spyder'))
+
+ def load(self, filename):
+ from spyder.plugins.outlineexplorer.editor import OutlineExplorerProxyEditor
+ self.editor.set_text_from_file(filename)
+ self.setWindowTitle("%s - %s (%s)" % (_("Editor"),
+ osp.basename(filename),
+ osp.dirname(filename)))
+ oe_proxy = OutlineExplorerProxyEditor(self.editor, filename)
+ self.classtree.set_current_editor(oe_proxy, False, False)
+
+
+def test(fname):
+ from spyder.utils.qthelpers import qapplication
+ app = qapplication(test_time=5)
+ win = TestWidget(None)
+ win.show()
+ win.load(fname)
+ win.resize(900, 700)
+ sys.exit(app.exec_())
+
+
+if __name__ == '__main__':
+ if len(sys.argv) > 1:
+ fname = sys.argv[1]
+ else:
+ fname = __file__
+ test(fname)
diff --git a/spyder/plugins/editor/widgets/editor.py b/spyder/plugins/editor/widgets/editor.py
new file mode 100644
index 00000000000..62f78cff0b4
--- /dev/null
+++ b/spyder/plugins/editor/widgets/editor.py
@@ -0,0 +1,3229 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Editor Widget"""
+
+# pylint: disable=C0103
+# pylint: disable=R0903
+# pylint: disable=R0911
+# pylint: disable=R0201
+
+# Standard library imports
+from __future__ import print_function
+import logging
+import os
+import os.path as osp
+import sys
+from collections import MutableSequence
+import unicodedata
+
+# Third party imports
+import qdarkstyle
+from qtpy.compat import getsavefilename
+from qtpy.QtCore import (QByteArray, QFileInfo, QObject, QPoint, QSize, Qt,
+ QThread, QTimer, Signal, Slot, QCoreApplication)
+from qtpy.QtGui import QFont
+from qtpy.QtWidgets import (QAction, QApplication, QFileDialog, QHBoxLayout,
+ QLabel, QMainWindow, QMessageBox, QMenu,
+ QSplitter, QVBoxLayout, QWidget, QListWidget,
+ QListWidgetItem)
+
+# Local imports
+from spyder.config.base import _, running_under_pytest
+from spyder.config.gui import config_shortcut, is_dark_interface, get_shortcut
+from spyder.config.utils import (get_edit_filetypes, get_edit_filters,
+ get_filter, is_kde_desktop, is_anaconda)
+from spyder.py3compat import qbytearray_to_str, to_text_string
+from spyder.utils import icon_manager as ima
+from spyder.utils import encoding, sourcecode, syntaxhighlighters
+from spyder.utils.qthelpers import (add_actions, create_action,
+ create_toolbutton, MENU_SEPARATOR,
+ mimedata2url)
+from spyder.plugins.outlineexplorer.widgets import OutlineExplorerWidget
+from spyder.plugins.outlineexplorer.editor import OutlineExplorerProxyEditor
+from spyder.widgets.fileswitcher import FileSwitcher
+from spyder.widgets.findreplace import FindReplace
+from spyder.plugins.editor.utils.autosave import AutosaveForStack
+from spyder.plugins.editor.widgets import codeeditor
+from spyder.plugins.editor.widgets.base import TextEditBaseWidget # analysis:ignore
+from spyder.plugins.editor.widgets.codeeditor import Printer # analysis:ignore
+from spyder.plugins.editor.widgets.codeeditor import get_file_language
+from spyder.plugins.editor.widgets.status import (CursorPositionStatus,
+ EncodingStatus, EOLStatus,
+ ReadWriteStatus, VCSStatus)
+from spyder.plugins.editor.utils.findtasks import find_tasks
+from spyder.widgets.tabs import BaseTabs
+from spyder.config.main import CONF
+from spyder.plugins.explorer.widgets import show_in_external_file_explorer
+
+
+logger = logging.getLogger(__name__)
+
+
+class AnalysisThread(QThread):
+ """Analysis thread"""
+
+ def __init__(self, parent, checker, source_code):
+
+ super(AnalysisThread, self).__init__(parent)
+ self.checker = checker
+ self.results = None
+ self.source_code = source_code
+
+ def run(self):
+ """Run analysis"""
+ try:
+ self.results = self.checker(self.source_code)
+ except Exception as e:
+ logger.error(e, exc_info=True)
+
+
+class ThreadManager(QObject):
+ """Analysis thread manager"""
+ def __init__(self, parent, max_simultaneous_threads=2):
+ super(ThreadManager, self).__init__(parent)
+ self.max_simultaneous_threads = max_simultaneous_threads
+ self.started_threads = {}
+ self.pending_threads = []
+ self.end_callbacks = {}
+
+ def close_threads(self, parent):
+ """Close threads associated to parent_id"""
+ logger.debug("Call ThreadManager's 'close_threads'")
+ if parent is None:
+ # Closing all threads
+ self.pending_threads = []
+ threadlist = []
+ for threads in list(self.started_threads.values()):
+ threadlist += threads
+ else:
+ parent_id = id(parent)
+ self.pending_threads = [(_th, _id) for (_th, _id)
+ in self.pending_threads
+ if _id != parent_id]
+ threadlist = self.started_threads.get(parent_id, [])
+ for thread in threadlist:
+ logger.debug("Waiting for thread %r to finish" % thread)
+ while thread.isRunning():
+ # We can't terminate thread safely, so we simply wait...
+ QApplication.processEvents()
+
+ def close_all_threads(self):
+ """Close all threads"""
+ logger.debug("Call ThreadManager's 'close_all_threads'")
+ self.close_threads(None)
+
+ def add_thread(self, checker, end_callback, source_code, parent):
+ """Add thread to queue"""
+ parent_id = id(parent)
+ thread = AnalysisThread(self, checker, source_code)
+ self.end_callbacks[id(thread)] = end_callback
+ self.pending_threads.append((thread, parent_id))
+ logger.debug("Added thread %r to queue" % thread)
+ QTimer.singleShot(50, self.update_queue)
+
+ def update_queue(self):
+ """Update queue"""
+ started = 0
+ for parent_id, threadlist in list(self.started_threads.items()):
+ still_running = []
+ for thread in threadlist:
+ if thread.isFinished():
+ end_callback = self.end_callbacks.pop(id(thread))
+ if thread.results is not None:
+ # The thread was executed successfully
+ end_callback(thread.results)
+ thread.setParent(None)
+ thread = None
+ else:
+ still_running.append(thread)
+ started += 1
+ threadlist = None
+ if still_running:
+ self.started_threads[parent_id] = still_running
+ else:
+ self.started_threads.pop(parent_id)
+ logger.debug("Updating queue:")
+ logger.debug(" started: %d" % started)
+ logger.debug(" pending: %d" % len(self.pending_threads))
+ if self.pending_threads and started < self.max_simultaneous_threads:
+ thread, parent_id = self.pending_threads.pop(0)
+ thread.finished.connect(self.update_queue)
+ threadlist = self.started_threads.get(parent_id, [])
+ self.started_threads[parent_id] = threadlist+[thread]
+ logger.debug("===>starting: %r" % thread)
+ thread.start()
+
+
+class FileInfo(QObject):
+ """File properties"""
+ todo_results_changed = Signal()
+ sig_save_bookmarks = Signal(str, str)
+ text_changed_at = Signal(str, int)
+ edit_goto = Signal(str, int, str)
+ send_to_help = Signal(str, str, str, str, bool)
+ sig_filename_changed = Signal(str)
+ sig_show_object_info = Signal(int)
+
+ def __init__(self, filename, encoding, editor, new, threadmanager):
+ QObject.__init__(self)
+ self.threadmanager = threadmanager
+ self._filename = filename
+ self.newly_created = new
+ self.default = False # Default untitled file
+ self.encoding = encoding
+ self.editor = editor
+ self.path = []
+
+ self.classes = (filename, None, None)
+ self.todo_results = []
+ self.lastmodified = QFileInfo(filename).lastModified()
+
+ self.editor.textChanged.connect(self.text_changed)
+ self.editor.sig_bookmarks_changed.connect(self.bookmarks_changed)
+ self.editor.sig_show_object_info.connect(self.sig_show_object_info)
+ self.sig_filename_changed.connect(self.editor.sig_filename_changed)
+
+ @property
+ def filename(self):
+ return self._filename
+
+ @filename.setter
+ def filename(self, value):
+ self._filename = value
+ self.sig_filename_changed.emit(value)
+
+ def text_changed(self):
+ """Editor's text has changed"""
+ self.default = False
+ self.editor.document().changed_since_autosave = True
+ self.text_changed_at.emit(self.filename,
+ self.editor.get_position('cursor'))
+
+ def get_source_code(self):
+ """Return associated editor source code"""
+ return to_text_string(self.editor.toPlainText())
+
+ def run_todo_finder(self):
+ """Run TODO finder"""
+ if self.editor.is_python():
+ self.threadmanager.add_thread(find_tasks,
+ self.todo_finished,
+ self.get_source_code(), self)
+
+ def todo_finished(self, results):
+ """Code analysis thread has finished"""
+ self.set_todo_results(results)
+ self.todo_results_changed.emit()
+
+ def set_todo_results(self, results):
+ """Set TODO results and update markers in editor"""
+ self.todo_results = results
+ self.editor.process_todo(results)
+
+ def cleanup_todo_results(self):
+ """Clean-up TODO finder results"""
+ self.todo_results = []
+
+ def bookmarks_changed(self):
+ """Bookmarks list has changed."""
+ bookmarks = self.editor.get_bookmarks()
+ if self.editor.bookmarks != bookmarks:
+ self.editor.bookmarks = bookmarks
+ self.sig_save_bookmarks.emit(self.filename, repr(bookmarks))
+
+
+class StackHistory(MutableSequence):
+ """Handles editor stack history.
+
+ Works as a list of numbers corresponding to tab indexes.
+ Internally elements are saved using objects id's.
+ """
+
+ def __init__(self, editor):
+ self.history = list()
+ self.id_list = list()
+ self.editor = editor
+
+ def _update_id_list(self):
+ """Update list of corresponpding ids and tabs."""
+ self.id_list = [id(self.editor.tabs.widget(_i))
+ for _i in range(self.editor.tabs.count())]
+
+ def refresh(self):
+ """Remove editors that are not longer open."""
+ self._update_id_list()
+ for _id in self.history[:]:
+ if _id not in self.id_list:
+ self.history.remove(_id)
+
+ def __len__(self):
+ return len(self.history)
+
+ def __getitem__(self, i):
+ self._update_id_list()
+ try:
+ return self.id_list.index(self.history[i])
+ except ValueError:
+ self.refresh()
+ raise IndexError
+
+ def __delitem__(self, i):
+ del self.history[i]
+
+ def __setitem__(self, i, v):
+ _id = id(self.editor.tabs.widget(v))
+ self.history[i] = _id
+
+ def __str__(self):
+ return str(list(self))
+
+ def insert(self, i, tab_index):
+ """Insert the widget (at tab index) in the position i (index)."""
+ _id = id(self.editor.tabs.widget(tab_index))
+ self.history.insert(i, _id)
+
+ def remove(self, tab_index):
+ """Remove the widget at the corresponding tab_index."""
+ _id = id(self.editor.tabs.widget(tab_index))
+ if _id in self.history:
+ self.history.remove(_id)
+
+ def remove_and_append(self, index):
+ """Remove previous entrances of a tab, and add it as the latest."""
+ while index in self:
+ self.remove(index)
+ self.append(index)
+
+
+class TabSwitcherWidget(QListWidget):
+ """Show tabs in mru order and change between them."""
+
+ def __init__(self, parent, stack_history, tabs):
+ QListWidget.__init__(self, parent)
+ self.setWindowFlags(Qt.FramelessWindowHint | Qt.Dialog)
+
+ self.editor = parent
+ self.stack_history = stack_history
+ self.tabs = tabs
+
+ self.setSelectionMode(QListWidget.SingleSelection)
+ self.itemActivated.connect(self.item_selected)
+
+ self.id_list = []
+ self.load_data()
+ size = CONF.get('main', 'completion/size')
+ self.resize(*size)
+ self.set_dialog_position()
+ self.setCurrentRow(0)
+
+ config_shortcut(lambda: self.select_row(-1), context='Editor',
+ name='Go to previous file', parent=self)
+ config_shortcut(lambda: self.select_row(1), context='Editor',
+ name='Go to next file', parent=self)
+
+ def load_data(self):
+ """Fill ListWidget with the tabs texts.
+
+ Add elements in inverse order of stack_history.
+ """
+
+ for index in reversed(self.stack_history):
+ text = self.tabs.tabText(index)
+ text = text.replace('&', '')
+ item = QListWidgetItem(ima.icon('TextFileIcon'), text)
+ self.addItem(item)
+
+ def item_selected(self, item=None):
+ """Change to the selected document and hide this widget."""
+ if item is None:
+ item = self.currentItem()
+
+ # stack history is in inverse order
+ try:
+ index = self.stack_history[-(self.currentRow()+1)]
+ except IndexError:
+ pass
+ else:
+ self.editor.set_stack_index(index)
+ self.editor.current_changed(index)
+ self.hide()
+
+ def select_row(self, steps):
+ """Move selected row a number of steps.
+
+ Iterates in a cyclic behaviour.
+ """
+ row = (self.currentRow() + steps) % self.count()
+ self.setCurrentRow(row)
+
+ def set_dialog_position(self):
+ """Positions the tab switcher in the top-center of the editor."""
+ left = self.editor.geometry().width()/2 - self.width()/2
+ top = self.editor.tabs.tabBar().geometry().height()
+
+ self.move(self.editor.mapToGlobal(QPoint(left, top)))
+
+ def keyReleaseEvent(self, event):
+ """Reimplement Qt method.
+
+ Handle "most recent used" tab behavior,
+ When ctrl is released and tab_switcher is visible, tab will be changed.
+ """
+ if self.isVisible():
+ qsc = get_shortcut(context='Editor', name='Go to next file')
+
+ for key in qsc.split('+'):
+ key = key.lower()
+ if ((key == 'ctrl' and event.key() == Qt.Key_Control) or
+ (key == 'alt' and event.key() == Qt.Key_Alt)):
+ self.item_selected()
+ event.accept()
+
+ def keyPressEvent(self, event):
+ """Reimplement Qt method to allow cyclic behavior."""
+ if event.key() == Qt.Key_Down:
+ self.select_row(1)
+ elif event.key() == Qt.Key_Up:
+ self.select_row(-1)
+
+ def focusOutEvent(self, event):
+ """Reimplement Qt method to close the widget when loosing focus."""
+ event.ignore()
+ # Inspired from CompletionWidget.focusOutEvent() in file
+ # widgets/sourcecode/base.py line 212
+ if sys.platform == "darwin":
+ if event.reason() != Qt.ActiveWindowFocusReason:
+ self.close()
+ else:
+ self.close()
+
+
+class EditorStack(QWidget):
+ reset_statusbar = Signal()
+ readonly_changed = Signal(bool)
+ encoding_changed = Signal(str)
+ sig_editor_cursor_position_changed = Signal(int, int)
+ sig_refresh_eol_chars = Signal(str)
+ starting_long_process = Signal(str)
+ ending_long_process = Signal(str)
+ redirect_stdio = Signal(bool)
+ exec_in_extconsole = Signal(str, bool)
+ run_cell_in_ipyclient = Signal(str, str, str, bool)
+ update_plugin_title = Signal()
+ editor_focus_changed = Signal()
+ zoom_in = Signal()
+ zoom_out = Signal()
+ zoom_reset = Signal()
+ sig_open_file = Signal(dict)
+ sig_close_file = Signal(str, str)
+ file_saved = Signal(str, str, str)
+ file_renamed_in_data = Signal(str, str, str)
+ opened_files_list_changed = Signal()
+ active_languages_stats = Signal(set)
+ todo_results_changed = Signal()
+ update_code_analysis_actions = Signal()
+ refresh_file_dependent_actions = Signal()
+ refresh_save_all_action = Signal()
+ sig_breakpoints_saved = Signal()
+ text_changed_at = Signal(str, int)
+ current_file_changed = Signal(str, int)
+ plugin_load = Signal((str,), ())
+ edit_goto = Signal(str, int, str)
+ sig_split_vertically = Signal()
+ sig_split_horizontally = Signal()
+ sig_new_file = Signal((str,), ())
+ sig_save_as = Signal()
+ sig_prev_edit_pos = Signal()
+ sig_prev_cursor = Signal()
+ sig_next_cursor = Signal()
+ sig_prev_warning = Signal()
+ sig_next_warning = Signal()
+ sig_go_to_definition = Signal(str, int, int)
+ perform_lsp_request = Signal(str, str, dict)
+ sig_option_changed = Signal(str, object) # config option needs changing
+ sig_save_bookmark = Signal(int)
+ sig_load_bookmark = Signal(int)
+ sig_save_bookmarks = Signal(str, str)
+
+ def __init__(self, parent, actions):
+ QWidget.__init__(self, parent)
+
+ self.setAttribute(Qt.WA_DeleteOnClose)
+
+ self.threadmanager = ThreadManager(self)
+ self.new_window = False
+ self.horsplit_action = None
+ self.versplit_action = None
+ self.close_action = None
+ self.__get_split_actions()
+
+ layout = QVBoxLayout()
+ layout.setContentsMargins(0, 0, 0, 0)
+ self.setLayout(layout)
+
+ self.menu = None
+ self.fileswitcher_dlg = None
+# self.filelist_btn = None
+# self.previous_btn = None
+# self.next_btn = None
+ self.tabs = None
+ self.tabs_switcher = None
+
+ self.stack_history = StackHistory(self)
+
+ self.setup_editorstack(parent, layout)
+
+ self.find_widget = None
+
+ self.data = []
+ fileswitcher_action = create_action(self, _("File switcher..."),
+ icon=ima.icon('filelist'),
+ triggered=self.open_fileswitcher_dlg)
+ symbolfinder_action = create_action(self,
+ _("Find symbols in file..."),
+ icon=ima.icon('symbol_find'),
+ triggered=self.open_symbolfinder_dlg)
+ copy_to_cb_action = create_action(self, _("Copy path to clipboard"),
+ icon=ima.icon('editcopy'),
+ triggered=lambda:
+ QApplication.clipboard().setText(self.get_current_filename()))
+ close_right = create_action(self, _("Close all to the right"),
+ triggered=self.close_all_right)
+ close_all_but_this = create_action(self, _("Close all but this"),
+ triggered=self.close_all_but_this)
+
+ sort_tabs = create_action(self, _("Sort tabs alphabetically"),
+ triggered=self.sort_file_tabs_alphabetically)
+
+ if sys.platform == 'darwin':
+ text=_("Show in Finder")
+ else:
+ text= _("Show in external file explorer")
+ external_fileexp_action = create_action(self, text,
+ triggered=self.show_in_external_file_explorer)
+
+ self.menu_actions = actions + [external_fileexp_action,
+ None, fileswitcher_action,
+ symbolfinder_action,
+ copy_to_cb_action, None, close_right,
+ close_all_but_this, sort_tabs]
+ self.outlineexplorer = None
+ self.help = None
+ self.unregister_callback = None
+ self.is_closable = False
+ self.new_action = None
+ self.open_action = None
+ self.save_action = None
+ self.revert_action = None
+ self.tempfile_path = None
+ self.title = _("Editor")
+ self.todolist_enabled = True
+ self.is_analysis_done = False
+ self.linenumbers_enabled = True
+ self.blanks_enabled = False
+ self.scrollpastend_enabled = False
+ self.edgeline_enabled = True
+ self.edgeline_columns = (79,)
+ self.close_parentheses_enabled = True
+ self.close_quotes_enabled = True
+ self.add_colons_enabled = True
+ self.auto_unindent_enabled = True
+ self.indent_chars = " "*4
+ self.tab_stop_width_spaces = 4
+ self.show_class_func_dropdown = False
+ self.help_enabled = False
+ self.default_font = None
+ self.wrap_enabled = False
+ self.tabmode_enabled = False
+ self.stripmode_enabled = False
+ self.intelligent_backspace_enabled = True
+ self.highlight_current_line_enabled = False
+ self.highlight_current_cell_enabled = False
+ self.occurrence_highlighting_enabled = True
+ self.occurrence_highlighting_timeout=1500
+ self.checkeolchars_enabled = True
+ self.always_remove_trailing_spaces = False
+ self.convert_eol_on_save = False
+ self.convert_eol_on_save_to = 'LF'
+ self.focus_to_editor = True
+ self.run_cell_copy = False
+ self.create_new_file_if_empty = True
+ self.indent_guides = False
+ ccs = 'Spyder'
+ if ccs not in syntaxhighlighters.COLOR_SCHEME_NAMES:
+ ccs = syntaxhighlighters.COLOR_SCHEME_NAMES[0]
+ self.color_scheme = ccs
+ self.__file_status_flag = False
+
+ # Real-time code analysis
+ self.analysis_timer = QTimer(self)
+ self.analysis_timer.setSingleShot(True)
+ self.analysis_timer.setInterval(1000)
+ self.analysis_timer.timeout.connect(self.analyze_script)
+
+ # Update filename label
+ self.editor_focus_changed.connect(self.update_fname_label)
+
+ # Accepting drops
+ self.setAcceptDrops(True)
+
+ # Local shortcuts
+ self.shortcuts = self.create_shortcuts()
+
+ #For opening last closed tabs
+ self.last_closed_files = []
+
+ # Reference to save msgbox and avoid memory to be freed.
+ self.msgbox = None
+
+ # File types and filters used by the Save As dialog
+ self.edit_filetypes = None
+ self.edit_filters = None
+
+ # For testing
+ self.save_dialog_on_tests = not running_under_pytest()
+
+ # Autusave component
+ self.autosave = AutosaveForStack(self)
+
+ @Slot()
+ def show_in_external_file_explorer(self, fnames=None):
+ """Show file in external file explorer"""
+ if fnames is None:
+ fnames = self.get_current_filename()
+ show_in_external_file_explorer(fnames)
+
+ def create_shortcuts(self):
+ """Create local shortcuts"""
+ # --- Configurable shortcuts
+ inspect = config_shortcut(self.inspect_current_object, context='Editor',
+ name='Inspect current object', parent=self)
+ # TODO: Cleaner way to do this?
+ app = QCoreApplication.instance()
+ set_breakpoint = config_shortcut(self.set_or_clear_breakpoint,
+ context='Editor', name='Breakpoint',
+ parent=self)
+ set_cond_breakpoint = config_shortcut(
+ self.set_or_edit_conditional_breakpoint,
+ context='Editor',
+ name='Conditional breakpoint',
+ parent=self)
+ gotoline = config_shortcut(self.go_to_line, context='Editor',
+ name='Go to line', parent=self)
+ tab = config_shortcut(lambda: self.tab_navigation_mru(forward=False),
+ context='Editor',
+ name='Go to previous file', parent=self)
+ tabshift = config_shortcut(self.tab_navigation_mru, context='Editor',
+ name='Go to next file', parent=self)
+ prevtab = config_shortcut(lambda: self.tabs.tab_navigate(-1),
+ context='Editor',
+ name='Cycle to previous file', parent=self)
+ nexttab = config_shortcut(lambda: self.tabs.tab_navigate(1),
+ context='Editor',
+ name='Cycle to next file', parent=self)
+ run_selection = config_shortcut(self.run_selection, context='Editor',
+ name='Run selection', parent=self)
+ new_file = config_shortcut(lambda : self.sig_new_file[()].emit(),
+ context='Editor', name='New file',
+ parent=self)
+ open_file = config_shortcut(lambda : self.plugin_load[()].emit(),
+ context='Editor', name='Open file',
+ parent=self)
+ save_file = config_shortcut(self.save, context='Editor',
+ name='Save file', parent=self)
+ save_all = config_shortcut(self.save_all, context='Editor',
+ name='Save all', parent=self)
+ save_as = config_shortcut(lambda : self.sig_save_as.emit(),
+ context='Editor', name='Save As',
+ parent=self)
+ close_all = config_shortcut(self.close_all_files, context='Editor',
+ name='Close all', parent=self)
+ prev_edit_pos = config_shortcut(lambda : self.sig_prev_edit_pos.emit(),
+ context="Editor",
+ name="Last edit location",
+ parent=self)
+ prev_cursor = config_shortcut(lambda : self.sig_prev_cursor.emit(),
+ context="Editor",
+ name="Previous cursor position",
+ parent=self)
+ next_cursor = config_shortcut(lambda : self.sig_next_cursor.emit(),
+ context="Editor",
+ name="Next cursor position",
+ parent=self)
+ zoom_in_1 = config_shortcut(lambda : self.zoom_in.emit(),
+ context="Editor",
+ name="zoom in 1",
+ parent=self)
+ zoom_in_2 = config_shortcut(lambda : self.zoom_in.emit(),
+ context="Editor",
+ name="zoom in 2",
+ parent=self)
+ zoom_out = config_shortcut(lambda : self.zoom_out.emit(),
+ context="Editor",
+ name="zoom out",
+ parent=self)
+ zoom_reset = config_shortcut(lambda: self.zoom_reset.emit(),
+ context="Editor",
+ name="zoom reset",
+ parent=self)
+ close_file_1 = config_shortcut(self.close_file,
+ context="Editor",
+ name="close file 1",
+ parent=self)
+ close_file_2 = config_shortcut(self.close_file,
+ context="Editor",
+ name="close file 2",
+ parent=self)
+ run_cell = config_shortcut(self.run_cell,
+ context="Editor",
+ name="run cell",
+ parent=self)
+ run_cell_and_advance = config_shortcut(self.run_cell_and_advance,
+ context="Editor",
+ name="run cell and advance",
+ parent=self)
+ go_to_next_cell = config_shortcut(self.advance_cell,
+ context="Editor",
+ name="go to next cell",
+ parent=self)
+ go_to_previous_cell = config_shortcut(lambda: self.advance_cell(reverse=True),
+ context="Editor",
+ name="go to previous cell",
+ parent=self)
+ re_run_last_cell = config_shortcut(self.re_run_last_cell,
+ context="Editor",
+ name="re-run last cell",
+ parent=self)
+ prev_warning = config_shortcut(lambda: self.sig_prev_warning.emit(),
+ context="Editor",
+ name="Previous warning",
+ parent=self)
+ next_warning = config_shortcut(lambda: self.sig_next_warning.emit(),
+ context="Editor",
+ name="Next warning",
+ parent=self)
+ split_vertically = config_shortcut(lambda: self.sig_split_vertically.emit(),
+ context="Editor",
+ name="split vertically",
+ parent=self)
+ split_horizontally = config_shortcut(lambda: self.sig_split_horizontally.emit(),
+ context="Editor",
+ name="split horizontally",
+ parent=self)
+ close_split = config_shortcut(self.close_split,
+ context="Editor",
+ name="close split panel",
+ parent=self)
+
+ # Return configurable ones
+ return [inspect, set_breakpoint, set_cond_breakpoint, gotoline, tab,
+ tabshift, run_selection, new_file, open_file, save_file,
+ save_all, save_as, close_all, prev_edit_pos, prev_cursor,
+ next_cursor, zoom_in_1, zoom_in_2, zoom_out, zoom_reset,
+ close_file_1, close_file_2, run_cell, run_cell_and_advance,
+ go_to_next_cell, go_to_previous_cell, re_run_last_cell,
+ prev_warning, next_warning, split_vertically,
+ split_horizontally, close_split,
+ prevtab, nexttab]
+
+ def get_shortcut_data(self):
+ """
+ Returns shortcut data, a list of tuples (shortcut, text, default)
+ shortcut (QShortcut or QAction instance)
+ text (string): action/shortcut description
+ default (string): default key sequence
+ """
+ return [sc.data for sc in self.shortcuts]
+
+ def setup_editorstack(self, parent, layout):
+ """Setup editorstack's layout"""
+ layout.setSpacing(1)
+
+ self.fname_label = QLabel()
+ self.fname_label.setStyleSheet(
+ "QLabel {margin: 0px; padding: 3px;}")
+ layout.addWidget(self.fname_label)
+
+ menu_btn = create_toolbutton(self, icon=ima.icon('tooloptions'),
+ tip=_('Options'))
+ # Don't show menu arrow and remove padding
+ if is_dark_interface():
+ menu_btn.setStyleSheet(
+ ("QToolButton::menu-indicator{image: none;}\n"
+ "QToolButton{margin: 1px; padding: 3px;}"))
+ else:
+ menu_btn.setStyleSheet(
+ "QToolButton::menu-indicator{image: none;}")
+ self.menu = QMenu(self)
+ menu_btn.setMenu(self.menu)
+ menu_btn.setPopupMode(menu_btn.InstantPopup)
+ self.menu.aboutToShow.connect(self.__setup_menu)
+
+ corner_widgets = {Qt.TopRightCorner: [menu_btn]}
+ self.tabs = BaseTabs(self, menu=self.menu, menu_use_tooltips=True,
+ corner_widgets=corner_widgets)
+ self.tabs.tabBar().setObjectName('plugin-tab')
+ self.tabs.set_close_function(self.close_file)
+ self.tabs.tabBar().tabMoved.connect(self.move_editorstack_data)
+ self.tabs.setMovable(True)
+
+ self.stack_history.refresh()
+
+ if hasattr(self.tabs, 'setDocumentMode') \
+ and not sys.platform == 'darwin':
+ # Don't set document mode to true on OSX because it generates
+ # a crash when the editor is detached from the main window
+ # Fixes Issue 561
+ self.tabs.setDocumentMode(True)
+ self.tabs.currentChanged.connect(self.current_changed)
+
+ if sys.platform == 'darwin':
+ tab_container = QWidget()
+ tab_container.setObjectName('tab-container')
+ tab_layout = QHBoxLayout(tab_container)
+ tab_layout.setContentsMargins(0, 0, 0, 0)
+ tab_layout.addWidget(self.tabs)
+ layout.addWidget(tab_container)
+ else:
+ layout.addWidget(self.tabs)
+
+ @Slot()
+ def update_fname_label(self):
+ """Upadte file name label."""
+ filename = to_text_string(self.get_current_filename())
+ if len(filename) > 100:
+ shorten_filename = u'...' + filename[-100:]
+ else:
+ shorten_filename = filename
+ self.fname_label.setText(shorten_filename)
+
+ def add_corner_widgets_to_tabbar(self, widgets):
+ self.tabs.add_corner_widgets(widgets)
+
+ @Slot()
+ def close_split(self):
+ """Closes the editorstack if it is not the last one opened."""
+ if self.is_closable:
+ self.close()
+
+ def closeEvent(self, event):
+ """Overrides QWidget closeEvent()."""
+ self.threadmanager.close_all_threads()
+ self.analysis_timer.timeout.disconnect(self.analyze_script)
+
+ # Remove editor references from the outline explorer settings
+ if self.outlineexplorer is not None:
+ for finfo in self.data:
+ self.outlineexplorer.remove_editor(finfo.editor.oe_proxy)
+
+ for finfo in self.data:
+ finfo.editor.notify_close()
+ QWidget.closeEvent(self, event)
+
+ def clone_editor_from(self, other_finfo, set_current):
+ fname = other_finfo.filename
+ enc = other_finfo.encoding
+ new = other_finfo.newly_created
+ finfo = self.create_new_editor(fname, enc, "",
+ set_current=set_current, new=new,
+ cloned_from=other_finfo.editor)
+ finfo.set_todo_results(other_finfo.todo_results)
+ return finfo.editor
+
+ def clone_from(self, other):
+ """Clone EditorStack from other instance"""
+ for other_finfo in other.data:
+ self.clone_editor_from(other_finfo, set_current=True)
+ self.set_stack_index(other.get_stack_index())
+
+ @Slot()
+ def open_fileswitcher_dlg(self):
+ """Open file list management dialog box"""
+ if not self.tabs.count():
+ return
+ if self.fileswitcher_dlg is not None and \
+ self.fileswitcher_dlg.is_visible:
+ self.fileswitcher_dlg.hide()
+ self.fileswitcher_dlg.is_visible = False
+ return
+ self.fileswitcher_dlg = FileSwitcher(self, self, self.tabs, self.data,
+ ima.icon('TextFileIcon'))
+ self.fileswitcher_dlg.sig_goto_file.connect(self.set_stack_index)
+ self.fileswitcher_dlg.show()
+ self.fileswitcher_dlg.is_visible = True
+
+ @Slot()
+ def open_symbolfinder_dlg(self):
+ self.open_fileswitcher_dlg()
+ self.fileswitcher_dlg.set_search_text('@')
+
+ def get_current_tab_manager(self):
+ """Get the widget with the TabWidget attribute."""
+ return self
+
+ def go_to_line(self, line=None):
+ """Go to line dialog"""
+ if line is not None:
+ # When this method is called from the flileswitcher, a line
+ # number is specified, so there is no need for the dialog.
+ self.get_current_editor().go_to_line(line)
+ else:
+ if self.data:
+ self.get_current_editor().exec_gotolinedialog()
+
+ def set_or_clear_breakpoint(self):
+ """Set/clear breakpoint"""
+ if self.data:
+ editor = self.get_current_editor()
+ editor.debugger.toogle_breakpoint()
+
+ def set_or_edit_conditional_breakpoint(self):
+ """Set conditional breakpoint"""
+ if self.data:
+ editor = self.get_current_editor()
+ editor.debugger.toogle_breakpoint(edit_condition=True)
+
+ def set_bookmark(self, slot_num):
+ """Bookmark current position to given slot."""
+ if self.data:
+ editor = self.get_current_editor()
+ editor.add_bookmark(slot_num)
+
+ def inspect_current_object(self, pos=None):
+ """Inspect current object in the Help plugin"""
+ editor = self.get_current_editor()
+ editor.sig_display_object_info.connect(self.display_help)
+ cursor = None
+ if pos:
+ cursor = editor.get_last_hover_cursor()
+ line, col = editor.get_cursor_line_column(cursor)
+ editor.request_hover(line, col, show_hint=False, clicked=bool(pos))
+
+ @Slot(str, bool)
+ def display_help(self, help_text, clicked):
+ editor = self.get_current_editor()
+ if clicked:
+ name = editor.get_last_hover_word()
+ else:
+ name = editor.get_current_word()
+
+ editor.sig_display_object_info.disconnect(self.display_help)
+ self.help.switch_to_editor_source()
+ self.send_to_help(name, help_text, force=True)
+
+ #------ Editor Widget Settings
+ def set_closable(self, state):
+ """Parent widget must handle the closable state"""
+ self.is_closable = state
+
+ def set_io_actions(self, new_action, open_action,
+ save_action, revert_action):
+ self.new_action = new_action
+ self.open_action = open_action
+ self.save_action = save_action
+ self.revert_action = revert_action
+
+ def set_find_widget(self, find_widget):
+ self.find_widget = find_widget
+
+ def set_outlineexplorer(self, outlineexplorer):
+ self.outlineexplorer = outlineexplorer
+ self.outlineexplorer.is_visible.connect(self._refresh_outlineexplorer)
+
+ def initialize_outlineexplorer(self):
+ """This method is called separately from 'set_oulineexplorer' to avoid
+ doing unnecessary updates when there are multiple editor windows"""
+ for index in range(self.get_stack_count()):
+ if index != self.get_stack_index():
+ self._refresh_outlineexplorer(index=index)
+
+ def add_outlineexplorer_button(self, editor_plugin):
+ oe_btn = create_toolbutton(editor_plugin)
+ oe_btn.setDefaultAction(self.outlineexplorer.visibility_action)
+ self.add_corner_widgets_to_tabbar([5, oe_btn])
+
+ def set_help(self, help_plugin):
+ self.help = help_plugin
+
+ def set_tempfile_path(self, path):
+ self.tempfile_path = path
+
+ def set_title(self, text):
+ self.title = text
+
+ def set_classfunc_dropdown_visible(self, state):
+ self.show_class_func_dropdown = state
+ if self.data:
+ for finfo in self.data:
+ if finfo.editor.is_python_like():
+ finfo.editor.classfuncdropdown.setVisible(state)
+
+ def __update_editor_margins(self, editor):
+ editor.linenumberarea.setup_margins(linenumbers=self.linenumbers_enabled,
+ markers=self.has_markers())
+
+ def __codeanalysis_settings_changed(self, current_finfo):
+ if self.data:
+ for finfo in self.data:
+ self.__update_editor_margins(finfo.editor)
+
+ def has_markers(self):
+ """Return True if this editorstack has a marker margin for TODOs or
+ code analysis"""
+ return self.todolist_enabled
+
+ def set_todolist_enabled(self, state, current_finfo=None):
+ # CONF.get(self.CONF_SECTION, 'todo_list')
+ self.todolist_enabled = state
+ if self.data:
+ for finfo in self.data:
+ self.__update_editor_margins(finfo.editor)
+ finfo.cleanup_todo_results()
+ if state and current_finfo is not None:
+ if current_finfo is not finfo:
+ finfo.run_todo_finder()
+
+ def set_linenumbers_enabled(self, state, current_finfo=None):
+ # CONF.get(self.CONF_SECTION, 'line_numbers')
+ self.linenumbers_enabled = state
+ if self.data:
+ for finfo in self.data:
+ self.__update_editor_margins(finfo.editor)
+
+ def set_blanks_enabled(self, state):
+ self.blanks_enabled = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_blanks_enabled(state)
+
+ def set_scrollpastend_enabled(self, state):
+ self.scrollpastend_enabled = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_scrollpastend_enabled(state)
+
+ def set_edgeline_enabled(self, state):
+ # CONF.get(self.CONF_SECTION, 'edge_line')
+ self.edgeline_enabled = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.edge_line.set_enabled(state)
+
+ def set_edgeline_columns(self, columns):
+ # CONF.get(self.CONF_SECTION, 'edge_line_column')
+ self.edgeline_columns = columns
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.edge_line.set_columns(columns)
+
+ def set_indent_guides(self, state):
+ self.indent_guides = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.indent_guides.set_enabled(state)
+
+ def set_close_parentheses_enabled(self, state):
+ # CONF.get(self.CONF_SECTION, 'close_parentheses')
+ self.close_parentheses_enabled = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_close_parentheses_enabled(state)
+
+ def set_close_quotes_enabled(self, state):
+ # CONF.get(self.CONF_SECTION, 'close_quotes')
+ self.close_quotes_enabled = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_close_quotes_enabled(state)
+
+ def set_add_colons_enabled(self, state):
+ # CONF.get(self.CONF_SECTION, 'add_colons')
+ self.add_colons_enabled = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_add_colons_enabled(state)
+
+ def set_auto_unindent_enabled(self, state):
+ # CONF.get(self.CONF_SECTION, 'auto_unindent')
+ self.auto_unindent_enabled = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_auto_unindent_enabled(state)
+
+ def set_indent_chars(self, indent_chars):
+ # CONF.get(self.CONF_SECTION, 'indent_chars')
+ indent_chars = indent_chars[1:-1] # removing the leading/ending '*'
+ self.indent_chars = indent_chars
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_indent_chars(indent_chars)
+
+ def set_tab_stop_width_spaces(self, tab_stop_width_spaces):
+ # CONF.get(self.CONF_SECTION, 'tab_stop_width')
+ self.tab_stop_width_spaces = tab_stop_width_spaces
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.tab_stop_width_spaces = tab_stop_width_spaces
+ finfo.editor.update_tab_stop_width_spaces()
+
+ def set_help_enabled(self, state):
+ self.help_enabled = state
+
+ def set_default_font(self, font, color_scheme=None):
+ self.default_font = font
+ if color_scheme is not None:
+ self.color_scheme = color_scheme
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_font(font, color_scheme)
+
+ def set_color_scheme(self, color_scheme):
+ self.color_scheme = color_scheme
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_color_scheme(color_scheme)
+
+ def set_wrap_enabled(self, state):
+ # CONF.get(self.CONF_SECTION, 'wrap')
+ self.wrap_enabled = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.toggle_wrap_mode(state)
+
+ def set_tabmode_enabled(self, state):
+ # CONF.get(self.CONF_SECTION, 'tab_always_indent')
+ self.tabmode_enabled = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_tab_mode(state)
+
+ def set_stripmode_enabled(self, state):
+ # CONF.get(self.CONF_SECTION, 'strip_trailing_spaces_on_modify')
+ self.stripmode_enabled = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_strip_mode(state)
+
+ def set_intelligent_backspace_enabled(self, state):
+ # CONF.get(self.CONF_SECTION, 'intelligent_backspace')
+ self.intelligent_backspace_enabled = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.toggle_intelligent_backspace(state)
+
+ def set_occurrence_highlighting_enabled(self, state):
+ # CONF.get(self.CONF_SECTION, 'occurrence_highlighting')
+ self.occurrence_highlighting_enabled = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_occurrence_highlighting(state)
+
+ def set_occurrence_highlighting_timeout(self, timeout):
+ # CONF.get(self.CONF_SECTION, 'occurrence_highlighting/timeout')
+ self.occurrence_highlighting_timeout = timeout
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_occurrence_timeout(timeout)
+
+ def set_highlight_current_line_enabled(self, state):
+ self.highlight_current_line_enabled = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_highlight_current_line(state)
+
+ def set_highlight_current_cell_enabled(self, state):
+ self.highlight_current_cell_enabled = state
+ if self.data:
+ for finfo in self.data:
+ finfo.editor.set_highlight_current_cell(state)
+
+ def set_checkeolchars_enabled(self, state):
+ # CONF.get(self.CONF_SECTION, 'check_eol_chars')
+ self.checkeolchars_enabled = state
+
+ def set_always_remove_trailing_spaces(self, state):
+ # CONF.get(self.CONF_SECTION, 'always_remove_trailing_spaces')
+ self.always_remove_trailing_spaces = state
+
+ def set_convert_eol_on_save(self, state):
+ """If `state` is `True`, saving files will convert line endings."""
+ # CONF.get(self.CONF_SECTION, 'convert_eol_on_save')
+ self.convert_eol_on_save = state
+
+ def set_convert_eol_on_save_to(self, state):
+ """`state` can be one of ('LF', 'CRLF', 'CR')"""
+ # CONF.get(self.CONF_SECTION, 'convert_eol_on_save_to')
+ self.convert_eol_on_save_to = state
+
+ def set_focus_to_editor(self, state):
+ self.focus_to_editor = state
+
+ def set_run_cell_copy(self, state):
+ """If `state` is ``True``, code cells will be copied to the console."""
+ self.run_cell_copy = state
+
+ #------ Stacked widget management
+ def get_stack_index(self):
+ return self.tabs.currentIndex()
+
+ def get_current_finfo(self):
+ if self.data:
+ return self.data[self.get_stack_index()]
+
+ def get_current_editor(self):
+ return self.tabs.currentWidget()
+
+ def get_stack_count(self):
+ return self.tabs.count()
+
+ def set_stack_index(self, index, instance=None):
+ if instance == self or instance == None:
+ self.tabs.setCurrentIndex(index)
+
+ def set_tabbar_visible(self, state):
+ self.tabs.tabBar().setVisible(state)
+
+ def remove_from_data(self, index):
+ self.tabs.blockSignals(True)
+ self.tabs.removeTab(index)
+ self.data.pop(index)
+ self.tabs.blockSignals(False)
+ self.update_actions()
+
+ def __modified_readonly_title(self, title, is_modified, is_readonly):
+ if is_modified is not None and is_modified:
+ title += "*"
+ if is_readonly is not None and is_readonly:
+ title = "(%s)" % title
+ return title
+
+ def get_tab_text(self, index, is_modified=None, is_readonly=None):
+ """Return tab title."""
+ files_path_list = [finfo.filename for finfo in self.data]
+ fname = self.data[index].filename
+ fname = sourcecode.disambiguate_fname(files_path_list, fname)
+ return self.__modified_readonly_title(fname,
+ is_modified, is_readonly)
+
+ def get_tab_tip(self, filename, is_modified=None, is_readonly=None):
+ """Return tab menu title"""
+ text = u"%s — %s"
+ text = self.__modified_readonly_title(text,
+ is_modified, is_readonly)
+ if self.tempfile_path is not None\
+ and filename == encoding.to_unicode_from_fs(self.tempfile_path):
+ temp_file_str = to_text_string(_("Temporary file"))
+ return text % (temp_file_str, self.tempfile_path)
+ else:
+ return text % (osp.basename(filename), osp.dirname(filename))
+
+ def add_to_data(self, finfo, set_current, add_where='end'):
+ finfo.editor.oe_proxy = None
+ index = 0 if add_where == 'start' else len(self.data)
+ self.data.insert(index, finfo)
+ index = self.data.index(finfo)
+ editor = finfo.editor
+ self.tabs.insertTab(index, editor, self.get_tab_text(index))
+ self.set_stack_title(index, False)
+ if set_current:
+ self.set_stack_index(index)
+ self.current_changed(index)
+ self.update_actions()
+
+ def __repopulate_stack(self):
+ self.tabs.blockSignals(True)
+ self.tabs.clear()
+ for finfo in self.data:
+ if finfo.newly_created:
+ is_modified = True
+ else:
+ is_modified = None
+ index = self.data.index(finfo)
+ tab_text = self.get_tab_text(index, is_modified)
+ tab_tip = self.get_tab_tip(finfo.filename)
+ index = self.tabs.addTab(finfo.editor, tab_text)
+ self.tabs.setTabToolTip(index, tab_tip)
+ self.tabs.blockSignals(False)
+
+ def rename_in_data(self, original_filename, new_filename):
+ index = self.has_filename(original_filename)
+ if index is None:
+ return
+ finfo = self.data[index]
+ if osp.splitext(finfo.filename)[1] != osp.splitext(new_filename)[1]:
+ # File type has changed!
+ txt = to_text_string(finfo.editor.get_text_with_eol())
+ language = get_file_language(new_filename, txt)
+ finfo.editor.set_language(language)
+ set_new_index = index == self.get_stack_index()
+ current_fname = self.get_current_filename()
+ finfo.filename = new_filename
+ new_index = self.data.index(finfo)
+ self.__repopulate_stack()
+ if set_new_index:
+ self.set_stack_index(new_index)
+ else:
+ # Fixes Issue 1287
+ self.set_current_filename(current_fname)
+ if self.outlineexplorer is not None:
+ self.outlineexplorer.file_renamed(
+ finfo.editor.oe_proxy, finfo.filename)
+ return new_index
+
+ def set_stack_title(self, index, is_modified):
+ finfo = self.data[index]
+ fname = finfo.filename
+ is_modified = (is_modified or finfo.newly_created) and not finfo.default
+ is_readonly = finfo.editor.isReadOnly()
+ tab_text = self.get_tab_text(index, is_modified, is_readonly)
+ tab_tip = self.get_tab_tip(fname, is_modified, is_readonly)
+
+ # Only update tab text if have changed, otherwise an unwanted scrolling
+ # will happen when changing tabs. See Issue #1170.
+ if tab_text != self.tabs.tabText(index):
+ self.tabs.setTabText(index, tab_text)
+ self.tabs.setTabToolTip(index, tab_tip)
+
+
+ #------ Context menu
+ def __setup_menu(self):
+ """Setup tab context menu before showing it"""
+ self.menu.clear()
+ if self.data:
+ actions = self.menu_actions
+ else:
+ actions = (self.new_action, self.open_action)
+ self.setFocus() # --> Editor.__get_focus_editortabwidget
+ add_actions(self.menu, list(actions) + self.__get_split_actions())
+ self.close_action.setEnabled(self.is_closable)
+
+
+ #------ Hor/Ver splitting
+ def __get_split_actions(self):
+ if self.parent() is not None:
+ plugin = self.parent().plugin
+ else:
+ plugin = None
+
+ # New window
+ if plugin is not None:
+ self.new_window_action = create_action(
+ self, _("New window"),
+ icon=ima.icon('newwindow'),
+ tip=_("Create a new editor window"),
+ triggered=plugin.create_new_window)
+
+ # Splitting
+ self.versplit_action = create_action(self, _("Split vertically"),
+ icon=ima.icon('versplit'),
+ tip=_("Split vertically this editor window"),
+ triggered=lambda: self.sig_split_vertically.emit(),
+ shortcut=get_shortcut(context='Editor', name='split vertically'),
+ context=Qt.WidgetShortcut)
+ self.horsplit_action = create_action(self, _("Split horizontally"),
+ icon=ima.icon('horsplit'),
+ tip=_("Split horizontally this editor window"),
+ triggered=lambda: self.sig_split_horizontally.emit(),
+ shortcut=get_shortcut(context='Editor', name='split horizontally'),
+ context=Qt.WidgetShortcut)
+ self.close_action = create_action(self, _("Close this panel"),
+ icon=ima.icon('close_panel'),
+ triggered=self.close_split,
+ shortcut=get_shortcut(context='Editor', name='close split panel'),
+ context=Qt.WidgetShortcut)
+
+ # Regular actions
+ actions = [MENU_SEPARATOR, self.versplit_action,
+ self.horsplit_action, self.close_action]
+
+ if self.new_window:
+ window = self.window()
+ close_window_action = create_action(
+ self, _("Close window"),
+ icon=ima.icon('close_pane'),
+ triggered=window.close)
+ actions += [MENU_SEPARATOR, self.new_window_action,
+ close_window_action]
+ elif plugin is not None:
+ if plugin.undocked_window is not None:
+ actions += [MENU_SEPARATOR, plugin.dock_action]
+ else:
+ actions += [MENU_SEPARATOR, self.new_window_action,
+ plugin.undock_action, plugin.close_plugin_action]
+
+ return actions
+
+ def reset_orientation(self):
+ self.horsplit_action.setEnabled(True)
+ self.versplit_action.setEnabled(True)
+
+ def set_orientation(self, orientation):
+ self.horsplit_action.setEnabled(orientation == Qt.Horizontal)
+ self.versplit_action.setEnabled(orientation == Qt.Vertical)
+
+ def update_actions(self):
+ state = self.get_stack_count() > 0
+ self.horsplit_action.setEnabled(state)
+ self.versplit_action.setEnabled(state)
+
+ # ------ Accessors
+ def get_current_filename(self):
+ if self.data:
+ return self.data[self.get_stack_index()].filename
+
+ def get_filenames(self):
+ """
+ Return a list with the names of all the files currently opened in
+ the editorstack.
+ """
+ return [finfo.filename for finfo in self.data]
+
+ def has_filename(self, filename):
+ """Return the self.data index position for the filename.
+
+ Args:
+ filename: Name of the file to search for in self.data.
+
+ Returns:
+ The self.data index for the filename. Returns None
+ if the filename is not found in self.data.
+ """
+ fixpath = lambda path: osp.normcase(osp.realpath(path))
+ for index, finfo in enumerate(self.data):
+ if fixpath(filename) == fixpath(finfo.filename):
+ return index
+ return None
+
+ def set_current_filename(self, filename, focus=True):
+ """Set current filename and return the associated editor instance."""
+ index = self.has_filename(filename)
+ if index is not None:
+ if focus:
+ self.set_stack_index(index)
+ editor = self.data[index].editor
+ if focus:
+ editor.setFocus()
+ else:
+ self.stack_history.remove_and_append(index)
+
+ return editor
+
+ def is_file_opened(self, filename=None):
+ """Return if filename is in the editor stack.
+
+ Args:
+ filename: Name of the file to search for. If filename is None,
+ then checks if any file is open.
+
+ Returns:
+ True: If filename is None and a file is open.
+ False: If filename is None and no files are open.
+ None: If filename is not None and the file isn't found.
+ integer: Index of file name in editor stack.
+ """
+ if filename is None:
+ # Is there any file opened?
+ return len(self.data) > 0
+ else:
+ return self.has_filename(filename)
+
+ def get_index_from_filename(self, filename):
+ """
+ Return the position index of a file in the tab bar of the editorstack
+ from its name.
+ """
+ filenames = [d.filename for d in self.data]
+ return filenames.index(filename)
+
+ @Slot(int, int)
+ def move_editorstack_data(self, start, end):
+ """Reorder editorstack.data so it is synchronized with the tab bar when
+ tabs are moved."""
+ if start < 0 or end < 0:
+ return
+ else:
+ steps = abs(end - start)
+ direction = (end-start) // steps # +1 for right, -1 for left
+
+ data = self.data
+ self.blockSignals(True)
+
+ for i in range(start, end, direction):
+ data[i], data[i+direction] = data[i+direction], data[i]
+
+ self.blockSignals(False)
+ self.refresh()
+
+
+ #------ Close file, tabwidget...
+ def close_file(self, index=None, force=False):
+ """Close file (index=None -> close current file)
+ Keep current file index unchanged (if current file
+ that is being closed)"""
+ current_index = self.get_stack_index()
+ count = self.get_stack_count()
+
+ if index is None:
+ if count > 0:
+ index = current_index
+ else:
+ self.find_widget.set_editor(None)
+ return
+
+ new_index = None
+ if count > 1:
+ if current_index == index:
+ new_index = self._get_previous_file_index()
+ else:
+ new_index = current_index
+
+ is_ok = force or self.save_if_changed(cancelable=True, index=index)
+ if is_ok:
+ finfo = self.data[index]
+ self.threadmanager.close_threads(finfo)
+ # Removing editor reference from outline explorer settings:
+ if self.outlineexplorer is not None:
+ self.outlineexplorer.remove_editor(finfo.editor.oe_proxy)
+
+ filename = self.data[index].filename
+ self.remove_from_data(index)
+ finfo.editor.notify_close()
+
+ # We pass self object ID as a QString, because otherwise it would
+ # depend on the platform: long for 64bit, int for 32bit. Replacing
+ # by long all the time is not working on some 32bit platforms
+ # (see Issue 1094, Issue 1098)
+ self.sig_close_file.emit(str(id(self)), filename)
+
+ self.opened_files_list_changed.emit()
+ self.update_code_analysis_actions.emit()
+ self._refresh_outlineexplorer()
+ self.refresh_file_dependent_actions.emit()
+ self.update_plugin_title.emit()
+
+ editor = self.get_current_editor()
+ if editor:
+ editor.setFocus()
+
+ if new_index is not None:
+ if index < new_index:
+ new_index -= 1
+ self.set_stack_index(new_index)
+
+ self.add_last_closed_file(finfo.filename)
+
+ # Remove autosave on successful close to work around issue #9265.
+ # Probably a good idea in general to mitigate any other bugs.
+ self.autosave.remove_autosave_file(finfo.filename)
+
+ if self.get_stack_count() == 0 and self.create_new_file_if_empty:
+ self.sig_new_file[()].emit()
+ return False
+ self.__modify_stack_title()
+ return is_ok
+
+ def poll_open_file_languages(self):
+ """Get list of current opened files' languages"""
+ languages = []
+ for index in range(self.get_stack_count()):
+ languages.append(
+ self.tabs.widget(index).language.lower())
+ return set(languages)
+
+ def notify_server_ready(self, language, config):
+ """Notify language server availability to code editors."""
+ for index in range(self.get_stack_count()):
+ editor = self.tabs.widget(index)
+ if editor.language.lower() == language:
+ editor.start_lsp_services(config)
+
+ def notify_server_down(self, language):
+ """Notify language server unavailability to code editors."""
+ for index in range(self.get_stack_count()):
+ editor = self.tabs.widget(index)
+ if editor.language.lower() == language:
+ editor.stop_lsp_services()
+
+ def close_all_files(self):
+ """Close all opened scripts"""
+ while self.close_file():
+ pass
+
+ def close_all_right(self):
+ """ Close all files opened to the right """
+ num = self.get_stack_index()
+ n = self.get_stack_count()
+ for i in range(num, n-1):
+ self.close_file(num+1)
+
+ def close_all_but_this(self):
+ """Close all files but the current one"""
+ self.close_all_right()
+ for i in range(0, self.get_stack_count()-1 ):
+ self.close_file(0)
+
+ def sort_file_tabs_alphabetically(self):
+ """Sort open tabs alphabetically."""
+ while self.sorted() is False:
+ for i in range(0, self.tabs.tabBar().count()):
+ if(self.tabs.tabBar().tabText(i) >
+ self.tabs.tabBar().tabText(i + 1)):
+ self.tabs.tabBar().moveTab(i, i + 1)
+
+ def sorted(self):
+ """Utility function for sort_file_tabs_alphabetically()."""
+ for i in range(0, self.tabs.tabBar().count() - 1):
+ if (self.tabs.tabBar().tabText(i) >
+ self.tabs.tabBar().tabText(i + 1)):
+ return False
+ return True
+
+ def add_last_closed_file(self, fname):
+ """Add to last closed file list."""
+ if fname in self.last_closed_files:
+ self.last_closed_files.remove(fname)
+ self.last_closed_files.insert(0, fname)
+ if len(self.last_closed_files) > 10:
+ self.last_closed_files.pop(-1)
+
+ def get_last_closed_files(self):
+ return self.last_closed_files
+
+ def set_last_closed_files(self, fnames):
+ self.last_closed_files = fnames
+
+ #------ Save
+ def save_if_changed(self, cancelable=False, index=None):
+ """Ask user to save file if modified.
+
+ Args:
+ cancelable: Show Cancel button.
+ index: File to check for modification.
+
+ Returns:
+ False when save() fails or is cancelled.
+ True when save() is successful, there are no modifications,
+ or user selects No or NoToAll.
+
+ This function controls the message box prompt for saving
+ changed files. The actual save is performed in save() for
+ each index processed. This function also removes autosave files
+ corresponding to files the user chooses not to save.
+ """
+ if index is None:
+ indexes = list(range(self.get_stack_count()))
+ else:
+ indexes = [index]
+ buttons = QMessageBox.Yes | QMessageBox.No
+ if cancelable:
+ buttons |= QMessageBox.Cancel
+ unsaved_nb = 0
+ for index in indexes:
+ if self.data[index].editor.document().isModified():
+ unsaved_nb += 1
+ if not unsaved_nb:
+ # No file to save
+ return True
+ if unsaved_nb > 1:
+ buttons |= QMessageBox.YesToAll | QMessageBox.NoToAll
+ yes_all = no_all = False
+ for index in indexes:
+ self.set_stack_index(index)
+ finfo = self.data[index]
+ if finfo.filename == self.tempfile_path or yes_all:
+ if not self.save(index):
+ return False
+ elif no_all:
+ self.autosave.remove_autosave_file(finfo.filename)
+ elif (finfo.editor.document().isModified() and
+ self.save_dialog_on_tests):
+
+ self.msgbox = QMessageBox(
+ QMessageBox.Question,
+ self.title,
+ _("%s has been modified."
+ "
Do you want to save changes?"
+ ) % osp.basename(finfo.filename),
+ buttons,
+ parent=self)
+
+ answer = self.msgbox.exec_()
+ if answer == QMessageBox.Yes:
+ if not self.save(index):
+ return False
+ elif answer == QMessageBox.No:
+ self.autosave.remove_autosave_file(finfo.filename)
+ elif answer == QMessageBox.YesToAll:
+ if not self.save(index):
+ return False
+ yes_all = True
+ elif answer == QMessageBox.NoToAll:
+ self.autosave.remove_autosave_file(finfo.filename)
+ no_all = True
+ elif answer == QMessageBox.Cancel:
+ return False
+ return True
+
+ def _write_to_file(self, fileinfo, filename):
+ """Low-level function for writing text of editor to file.
+
+ Args:
+ fileinfo: FileInfo object associated to editor to be saved
+ filename: str with filename to save to
+
+ This is a low-level function that only saves the text to file in the
+ correct encoding without doing any error handling.
+ """
+ txt = to_text_string(fileinfo.editor.get_text_with_eol())
+ fileinfo.encoding = encoding.write(txt, filename, fileinfo.encoding)
+
+ def save(self, index=None, force=False):
+ """Write text of editor to a file.
+
+ Args:
+ index: self.data index to save. If None, defaults to
+ currentIndex().
+ force: Force save regardless of file state.
+
+ Returns:
+ True upon successful save or when file doesn't need to be saved.
+ False if save failed.
+
+ If the text isn't modified and it's not newly created, then the save
+ is aborted. If the file hasn't been saved before, then save_as()
+ is invoked. Otherwise, the file is written using the file name
+ currently in self.data. This function doesn't change the file name.
+ """
+ if index is None:
+ # Save the currently edited file
+ if not self.get_stack_count():
+ return
+ index = self.get_stack_index()
+
+ finfo = self.data[index]
+ if not (finfo.editor.document().isModified() or
+ finfo.newly_created) and not force:
+ return True
+ if not osp.isfile(finfo.filename) and not force:
+ # File has not been saved yet
+ return self.save_as(index=index)
+ if self.always_remove_trailing_spaces:
+ self.remove_trailing_spaces(index)
+ if self.convert_eol_on_save:
+ # hack to account for the fact that the config file saves
+ # CR/LF/CRLF while set_os_eol_chars wants the os.name value.
+ osname_lookup = {'LF': 'posix', 'CRLF': 'nt', 'CR': 'mac'}
+ osname = osname_lookup[self.convert_eol_on_save_to]
+ self.set_os_eol_chars(osname=osname)
+ try:
+ self._write_to_file(finfo, finfo.filename)
+ self.autosave.remove_autosave_file(finfo.filename)
+ finfo.newly_created = False
+ self.encoding_changed.emit(finfo.encoding)
+ finfo.lastmodified = QFileInfo(finfo.filename).lastModified()
+
+ # We pass self object ID as a QString, because otherwise it would
+ # depend on the platform: long for 64bit, int for 32bit. Replacing
+ # by long all the time is not working on some 32bit platforms
+ # (see Issue 1094, Issue 1098)
+ # The filename is passed instead of an index in case the tabs
+ # have been rearranged (see issue 5703).
+ self.file_saved.emit(str(id(self)),
+ finfo.filename, finfo.filename)
+
+ finfo.editor.document().setModified(False)
+ finfo.editor.document().changed_since_autosave = False
+ self.modification_changed(index=index)
+ self.analyze_script(index)
+
+ #XXX CodeEditor-only: re-scan the whole text to rebuild outline
+ # explorer data from scratch (could be optimized because
+ # rehighlighting text means searching for all syntax coloring
+ # patterns instead of only searching for class/def patterns which
+ # would be sufficient for outline explorer data.
+ finfo.editor.rehighlight()
+
+ self._refresh_outlineexplorer(index)
+
+ finfo.editor.notify_save()
+ return True
+ except EnvironmentError as error:
+ self.msgbox = QMessageBox(
+ QMessageBox.Critical,
+ _("Save Error"),
+ _("Unable to save file '%s'"
+ "
Error message:
%s"
+ ) % (osp.basename(finfo.filename),
+ str(error)),
+ parent=self)
+ self.msgbox.exec_()
+ return False
+
+ def file_saved_in_other_editorstack(self, original_filename, filename):
+ """
+ File was just saved in another editorstack, let's synchronize!
+ This avoids file being automatically reloaded.
+
+ The original filename is passed instead of an index in case the tabs
+ on the editor stacks were moved and are now in a different order - see
+ issue 5703.
+ Filename is passed in case file was just saved as another name.
+ """
+ index = self.has_filename(original_filename)
+ if index is None:
+ return
+ finfo = self.data[index]
+ finfo.newly_created = False
+ finfo.filename = to_text_string(filename)
+ finfo.lastmodified = QFileInfo(finfo.filename).lastModified()
+
+ def select_savename(self, original_filename):
+ """Select a name to save a file.
+
+ Args:
+ original_filename: Used in the dialog to display the current file
+ path and name.
+
+ Returns:
+ Normalized path for the selected file name or None if no name was
+ selected.
+ """
+ if self.edit_filetypes is None:
+ self.edit_filetypes = get_edit_filetypes()
+ if self.edit_filters is None:
+ self.edit_filters = get_edit_filters()
+
+ # Don't use filters on KDE to not make the dialog incredible
+ # slow
+ # Fixes issue 4156
+ if is_kde_desktop() and not is_anaconda():
+ filters = ''
+ selectedfilter = ''
+ else:
+ filters = self.edit_filters
+ selectedfilter = get_filter(self.edit_filetypes,
+ osp.splitext(original_filename)[1])
+
+ self.redirect_stdio.emit(False)
+ filename, _selfilter = getsavefilename(self, _("Save file"),
+ original_filename,
+ filters=filters,
+ selectedfilter=selectedfilter,
+ options=QFileDialog.HideNameFilterDetails)
+ self.redirect_stdio.emit(True)
+ if filename:
+ return osp.normpath(filename)
+ return None
+
+ def save_as(self, index=None):
+ """Save file as...
+
+ Args:
+ index: self.data index for the file to save.
+
+ Returns:
+ False if no file name was selected or if save() was unsuccessful.
+ True is save() was successful.
+
+ Gets the new file name from select_savename(). If no name is chosen,
+ then the save_as() aborts. Otherwise, the current stack is checked
+ to see if the selected name already exists and, if so, then the tab
+ with that name is closed.
+
+ The current stack (self.data) and current tabs are updated with the
+ new name and other file info. The text is written with the new
+ name using save() and the name change is propagated to the other stacks
+ via the file_renamed_in_data signal.
+ """
+ if index is None:
+ # Save the currently edited file
+ index = self.get_stack_index()
+ finfo = self.data[index]
+ # The next line is necessary to avoid checking if the file exists
+ # While running __check_file_status
+ # See issues 3678 and 3026
+ finfo.newly_created = True
+ original_filename = finfo.filename
+ filename = self.select_savename(original_filename)
+ if filename:
+ ao_index = self.has_filename(filename)
+ # Note: ao_index == index --> saving an untitled file
+ if ao_index is not None and ao_index != index:
+ if not self.close_file(ao_index):
+ return
+ if ao_index < index:
+ index -= 1
+
+ new_index = self.rename_in_data(original_filename,
+ new_filename=filename)
+
+ # We pass self object ID as a QString, because otherwise it would
+ # depend on the platform: long for 64bit, int for 32bit. Replacing
+ # by long all the time is not working on some 32bit platforms
+ # (see Issue 1094, Issue 1098)
+ self.file_renamed_in_data.emit(str(id(self)),
+ original_filename, filename)
+
+ ok = self.save(index=new_index, force=True)
+ self.refresh(new_index)
+ self.set_stack_index(new_index)
+ return ok
+ else:
+ return False
+
+ def save_copy_as(self, index=None):
+ """Save copy of file as...
+
+ Args:
+ index: self.data index for the file to save.
+
+ Returns:
+ False if no file name was selected or if save() was unsuccessful.
+ True is save() was successful.
+
+ Gets the new file name from select_savename(). If no name is chosen,
+ then the save_copy_as() aborts. Otherwise, the current stack is
+ checked to see if the selected name already exists and, if so, then the
+ tab with that name is closed.
+
+ Unlike save_as(), this calls write() directly instead of using save().
+ The current file and tab aren't changed at all. The copied file is
+ opened in a new tab.
+ """
+ if index is None:
+ # Save the currently edited file
+ index = self.get_stack_index()
+ finfo = self.data[index]
+ original_filename = finfo.filename
+ filename = self.select_savename(original_filename)
+ if filename:
+ ao_index = self.has_filename(filename)
+ # Note: ao_index == index --> saving an untitled file
+ if ao_index is not None and ao_index != index:
+ if not self.close_file(ao_index):
+ return
+ if ao_index < index:
+ index -= 1
+ try:
+ self._write_to_file(finfo, filename)
+ # open created copy file
+ self.plugin_load.emit(filename)
+ return True
+ except EnvironmentError as error:
+ self.msgbox = QMessageBox(
+ QMessageBox.Critical,
+ _("Save Error"),
+ _("Unable to save file '%s'"
+ "
Error message:
%s"
+ ) % (osp.basename(finfo.filename),
+ str(error)),
+ parent=self)
+ self.msgbox.exec_()
+ else:
+ return False
+
+ def save_all(self):
+ """Save all opened files.
+
+ Iterate through self.data and call save() on any modified files.
+ """
+ for index in range(self.get_stack_count()):
+ if self.data[index].editor.document().isModified():
+ self.save(index)
+
+ #------ Update UI
+ def start_stop_analysis_timer(self):
+ self.is_analysis_done = False
+ self.analysis_timer.stop()
+ self.analysis_timer.start()
+
+ def analyze_script(self, index=None):
+ """Analyze current script for TODOs."""
+ if self.is_analysis_done:
+ return
+ if index is None:
+ index = self.get_stack_index()
+ if self.data:
+ finfo = self.data[index]
+ if self.todolist_enabled:
+ finfo.run_todo_finder()
+ self.is_analysis_done = True
+
+ def set_todo_results(self, filename, todo_results):
+ """Synchronize todo results between editorstacks"""
+ index = self.has_filename(filename)
+ if index is None:
+ return
+ self.data[index].set_todo_results(todo_results)
+
+ def get_todo_results(self):
+ if self.data:
+ return self.data[self.get_stack_index()].todo_results
+
+ def current_changed(self, index):
+ """Stack index has changed"""
+# count = self.get_stack_count()
+# for btn in (self.filelist_btn, self.previous_btn, self.next_btn):
+# btn.setEnabled(count > 1)
+
+ editor = self.get_current_editor()
+ if editor.lsp_ready and not editor.document_opened:
+ editor.document_did_open()
+ if index != -1:
+ editor.setFocus()
+ logger.debug("Set focus to: %s" % editor.filename)
+ else:
+ self.reset_statusbar.emit()
+ self.opened_files_list_changed.emit()
+
+ self.stack_history.refresh()
+ self.stack_history.remove_and_append(index)
+
+ # Needed to avoid an error generated after moving/renaming
+ # files outside Spyder while in debug mode.
+ # See issue 8749.
+ try:
+ logger.debug("Current changed: %d - %s" %
+ (index, self.data[index].editor.filename))
+ except IndexError:
+ pass
+
+ self.update_plugin_title.emit()
+ if editor is not None:
+ # Needed in order to handle the close of files open in a directory
+ # that has been renamed. See issue 5157
+ try:
+ self.current_file_changed.emit(self.data[index].filename,
+ editor.get_position('cursor'))
+ except IndexError:
+ pass
+
+ def _get_previous_file_index(self):
+ """Return the penultimate element of the stack history."""
+ try:
+ return self.stack_history[-2]
+ except IndexError:
+ return None
+
+ def tab_navigation_mru(self, forward=True):
+ """
+ Tab navigation with "most recently used" behaviour.
+
+ It's fired when pressing 'go to previous file' or 'go to next file'
+ shortcuts.
+
+ forward:
+ True: move to next file
+ False: move to previous file
+ """
+ self.tabs_switcher = TabSwitcherWidget(self, self.stack_history,
+ self.tabs)
+ self.tabs_switcher.show()
+ self.tabs_switcher.select_row(1 if forward else -1)
+ self.tabs_switcher.setFocus()
+
+ def focus_changed(self):
+ """Editor focus has changed"""
+ fwidget = QApplication.focusWidget()
+ for finfo in self.data:
+ if fwidget is finfo.editor:
+ self.refresh()
+ self.editor_focus_changed.emit()
+
+ def _refresh_outlineexplorer(self, index=None, update=True, clear=False):
+ """Refresh outline explorer panel"""
+ oe = self.outlineexplorer
+ if oe is None:
+ return
+ if index is None:
+ index = self.get_stack_index()
+ if self.data:
+ finfo = self.data[index]
+ oe.setEnabled(True)
+ if finfo.editor.oe_proxy is None:
+ finfo.editor.oe_proxy = OutlineExplorerProxyEditor(
+ finfo.editor, finfo.filename)
+ oe.set_current_editor(finfo.editor.oe_proxy,
+ update=update, clear=clear)
+ if index != self.get_stack_index():
+ # The last file added to the outline explorer is not the
+ # currently focused one in the editor stack. Therefore,
+ # we need to force a refresh of the outline explorer to set
+ # the current editor to the currently focused one in the
+ # editor stack. See PR #8015.
+ self._refresh_outlineexplorer(update=False)
+ return
+ self._sync_outlineexplorer_file_order()
+
+ def _sync_outlineexplorer_file_order(self):
+ """
+ Order the root file items of the outline explorer as in the tabbar
+ of the current EditorStack.
+ """
+ if self.outlineexplorer is not None:
+ self.outlineexplorer.treewidget.set_editor_ids_order(
+ [finfo.editor.get_document_id() for finfo in self.data])
+
+ def __refresh_statusbar(self, index):
+ """Refreshing statusbar widgets"""
+ finfo = self.data[index]
+ self.encoding_changed.emit(finfo.encoding)
+ # Refresh cursor position status:
+ line, index = finfo.editor.get_cursor_line_column()
+ self.sig_editor_cursor_position_changed.emit(line, index)
+
+ def __refresh_readonly(self, index):
+ finfo = self.data[index]
+ read_only = not QFileInfo(finfo.filename).isWritable()
+ if not osp.isfile(finfo.filename):
+ # This is an 'untitledX.py' file (newly created)
+ read_only = False
+ finfo.editor.setReadOnly(read_only)
+ self.readonly_changed.emit(read_only)
+
+ def __check_file_status(self, index):
+ """Check if file has been changed in any way outside Spyder:
+ 1. removed, moved or renamed outside Spyder
+ 2. modified outside Spyder"""
+ if self.__file_status_flag:
+ # Avoid infinite loop: when the QMessageBox.question pops, it
+ # gets focus and then give it back to the CodeEditor instance,
+ # triggering a refresh cycle which calls this method
+ return
+ self.__file_status_flag = True
+
+ finfo = self.data[index]
+ name = osp.basename(finfo.filename)
+
+ if finfo.newly_created:
+ # File was just created (not yet saved): do nothing
+ # (do not return because of the clean-up at the end of the method)
+ pass
+
+ elif not osp.isfile(finfo.filename):
+ # File doesn't exist (removed, moved or offline):
+ self.msgbox = QMessageBox(
+ QMessageBox.Warning,
+ self.title,
+ _("%s is unavailable "
+ "(this file may have been removed, moved "
+ "or renamed outside Spyder)."
+ "
Do you want to close it?") % name,
+ QMessageBox.Yes | QMessageBox.No,
+ self)
+ answer = self.msgbox.exec_()
+ if answer == QMessageBox.Yes:
+ self.close_file(index)
+ else:
+ finfo.newly_created = True
+ finfo.editor.document().setModified(True)
+ self.modification_changed(index=index)
+
+ else:
+ # Else, testing if it has been modified elsewhere:
+ lastm = QFileInfo(finfo.filename).lastModified()
+ if to_text_string(lastm.toString()) \
+ != to_text_string(finfo.lastmodified.toString()):
+ if finfo.editor.document().isModified():
+ self.msgbox = QMessageBox(
+ QMessageBox.Question,
+ self.title,
+ _("%s has been modified outside Spyder."
+ "
Do you want to reload it and lose all "
+ "your changes?") % name,
+ QMessageBox.Yes | QMessageBox.No,
+ self)
+ answer = self.msgbox.exec_()
+ if answer == QMessageBox.Yes:
+ self.reload(index)
+ else:
+ finfo.lastmodified = lastm
+ else:
+ self.reload(index)
+
+ # Finally, resetting temporary flag:
+ self.__file_status_flag = False
+
+ def __modify_stack_title(self):
+ for index, finfo in enumerate(self.data):
+ state = finfo.editor.document().isModified()
+ self.set_stack_title(index, state)
+
+ def refresh(self, index=None):
+ """Refresh tabwidget"""
+ if index is None:
+ index = self.get_stack_index()
+ # Set current editor
+ if self.get_stack_count():
+ index = self.get_stack_index()
+ finfo = self.data[index]
+ editor = finfo.editor
+ editor.setFocus()
+ self._refresh_outlineexplorer(index, update=False)
+ self.update_code_analysis_actions.emit()
+ self.__refresh_statusbar(index)
+ self.__refresh_readonly(index)
+ self.__check_file_status(index)
+ self.__modify_stack_title()
+ self.update_plugin_title.emit()
+ else:
+ editor = None
+ # Update the modification-state-dependent parameters
+ self.modification_changed()
+ # Update FindReplace binding
+ self.find_widget.set_editor(editor, refresh=False)
+
+ def modification_changed(self, state=None, index=None, editor_id=None):
+ """
+ Current editor's modification state has changed
+ --> change tab title depending on new modification state
+ --> enable/disable save/save all actions
+ """
+ if editor_id is not None:
+ for index, _finfo in enumerate(self.data):
+ if id(_finfo.editor) == editor_id:
+ break
+ # This must be done before refreshing save/save all actions:
+ # (otherwise Save/Save all actions will always be enabled)
+ self.opened_files_list_changed.emit()
+ # --
+ if index is None:
+ index = self.get_stack_index()
+ if index == -1:
+ return
+ finfo = self.data[index]
+ if state is None:
+ state = finfo.editor.document().isModified() or finfo.newly_created
+ self.set_stack_title(index, state)
+ # Toggle save/save all actions state
+ self.save_action.setEnabled(state)
+ self.refresh_save_all_action.emit()
+ # Refreshing eol mode
+ eol_chars = finfo.editor.get_line_separator()
+ self.refresh_eol_chars(eol_chars)
+ self.stack_history.refresh()
+
+ def refresh_eol_chars(self, eol_chars):
+ os_name = sourcecode.get_os_name_from_eol_chars(eol_chars)
+ self.sig_refresh_eol_chars.emit(os_name)
+
+
+ #------ Load, reload
+ def reload(self, index):
+ """Reload file from disk"""
+ finfo = self.data[index]
+ txt, finfo.encoding = encoding.read(finfo.filename)
+ finfo.lastmodified = QFileInfo(finfo.filename).lastModified()
+ position = finfo.editor.get_position('cursor')
+ finfo.editor.set_text(txt)
+ finfo.editor.document().setModified(False)
+ finfo.editor.document().changed_since_autosave = False
+ finfo.editor.set_cursor_position(position)
+
+ #XXX CodeEditor-only: re-scan the whole text to rebuild outline
+ # explorer data from scratch (could be optimized because
+ # rehighlighting text means searching for all syntax coloring
+ # patterns instead of only searching for class/def patterns which
+ # would be sufficient for outline explorer data.
+ finfo.editor.rehighlight()
+
+ self._refresh_outlineexplorer(index)
+
+ def revert(self):
+ """Revert file from disk"""
+ index = self.get_stack_index()
+ finfo = self.data[index]
+ filename = finfo.filename
+ if finfo.editor.document().isModified():
+ self.msgbox = QMessageBox(
+ QMessageBox.Warning,
+ self.title,
+ _("All changes to %s will be lost."
+ "
Do you want to revert file from disk?"
+ ) % osp.basename(filename),
+ QMessageBox.Yes | QMessageBox.No,
+ self)
+ answer = self.msgbox.exec_()
+ if answer != QMessageBox.Yes:
+ return
+ self.reload(index)
+
+ def create_new_editor(self, fname, enc, txt, set_current, new=False,
+ cloned_from=None, add_where='end'):
+ """
+ Create a new editor instance
+ Returns finfo object (instead of editor as in previous releases)
+ """
+ editor = codeeditor.CodeEditor(self)
+ editor.go_to_definition.connect(
+ lambda fname, line, column: self.sig_go_to_definition.emit(
+ fname, line, column))
+
+ finfo = FileInfo(fname, enc, editor, new, self.threadmanager)
+
+ self.add_to_data(finfo, set_current, add_where)
+ finfo.send_to_help.connect(self.send_to_help)
+ finfo.sig_show_object_info.connect(self.inspect_current_object)
+ finfo.todo_results_changed.connect(
+ lambda: self.todo_results_changed.emit())
+ finfo.edit_goto.connect(lambda fname, lineno, name:
+ self.edit_goto.emit(fname, lineno, name))
+ finfo.sig_save_bookmarks.connect(lambda s1, s2:
+ self.sig_save_bookmarks.emit(s1, s2))
+ editor.sig_run_selection.connect(self.run_selection)
+ editor.sig_run_cell.connect(self.run_cell)
+ editor.sig_run_cell_and_advance.connect(self.run_cell_and_advance)
+ editor.sig_re_run_last_cell.connect(self.re_run_last_cell)
+ editor.sig_new_file.connect(self.sig_new_file.emit)
+ editor.sig_breakpoints_saved.connect(self.sig_breakpoints_saved)
+ editor.sig_process_code_analysis.connect(
+ lambda: self.update_code_analysis_actions.emit())
+ language = get_file_language(fname, txt)
+ editor.setup_editor(
+ linenumbers=self.linenumbers_enabled,
+ show_blanks=self.blanks_enabled,
+ scroll_past_end=self.scrollpastend_enabled,
+ edge_line=self.edgeline_enabled,
+ edge_line_columns=self.edgeline_columns, language=language,
+ markers=self.has_markers(), font=self.default_font,
+ color_scheme=self.color_scheme,
+ wrap=self.wrap_enabled, tab_mode=self.tabmode_enabled,
+ strip_mode=self.stripmode_enabled,
+ intelligent_backspace=self.intelligent_backspace_enabled,
+ highlight_current_line=self.highlight_current_line_enabled,
+ highlight_current_cell=self.highlight_current_cell_enabled,
+ occurrence_highlighting=self.occurrence_highlighting_enabled,
+ occurrence_timeout=self.occurrence_highlighting_timeout,
+ close_parentheses=self.close_parentheses_enabled,
+ close_quotes=self.close_quotes_enabled,
+ add_colons=self.add_colons_enabled,
+ auto_unindent=self.auto_unindent_enabled,
+ indent_chars=self.indent_chars,
+ tab_stop_width_spaces=self.tab_stop_width_spaces,
+ cloned_from=cloned_from,
+ filename=fname,
+ show_class_func_dropdown=self.show_class_func_dropdown,
+ indent_guides=self.indent_guides,
+ )
+ if cloned_from is None:
+ editor.set_text(txt)
+ editor.document().setModified(False)
+ editor.document().changed_since_autosave = False
+ finfo.text_changed_at.connect(
+ lambda fname, position:
+ self.text_changed_at.emit(fname, position))
+ editor.sig_cursor_position_changed.connect(
+ self.editor_cursor_position_changed)
+ editor.textChanged.connect(self.start_stop_analysis_timer)
+ editor.sig_perform_lsp_request.connect(
+ lambda lang, method, params: self.perform_lsp_request.emit(
+ lang, method, params))
+ editor.modificationChanged.connect(
+ lambda state: self.modification_changed(state,
+ editor_id=id(editor)))
+ editor.focus_in.connect(self.focus_changed)
+ editor.zoom_in.connect(lambda: self.zoom_in.emit())
+ editor.zoom_out.connect(lambda: self.zoom_out.emit())
+ editor.zoom_reset.connect(lambda: self.zoom_reset.emit())
+ editor.sig_eol_chars_changed.connect(
+ lambda eol_chars: self.refresh_eol_chars(eol_chars))
+
+ self.find_widget.set_editor(editor)
+
+ self.refresh_file_dependent_actions.emit()
+ self.modification_changed(index=self.data.index(finfo))
+
+ # Needs to reset the highlighting on startup in case the PygmentsSH
+ # is in use
+ editor.run_pygments_highlighter()
+ options = {
+ 'language': editor.language,
+ 'filename': editor.filename,
+ 'codeeditor': editor
+ }
+ self.sig_open_file.emit(options)
+ if self.get_stack_index() == 0:
+ self.current_changed(0)
+
+ return finfo
+
+ def editor_cursor_position_changed(self, line, index):
+ """Cursor position of one of the editor in the stack has changed"""
+ self.sig_editor_cursor_position_changed.emit(line, index)
+
+ def send_to_help(self, name, signature, force=False):
+ """qstr1: obj_text, qstr2: argpspec, qstr3: note, qstr4: doc_text"""
+ if not force and not self.help_enabled:
+ return
+ if self.help is not None \
+ and (force or self.help.dockwidget.isVisible()):
+ signature = to_text_string(signature)
+ signature = unicodedata.normalize("NFKD", signature)
+ parts = signature.split('\n\n')
+ definition = parts[0]
+ documentation = '\n\n'.join(parts[1:])
+ args = ''
+ if '(' in definition:
+ args = definition[definition.find('('):]
+
+ doc = {'obj_text': '', 'name': name,
+ 'argspec': args, 'note': '',
+ 'docstring': documentation}
+ self.help.set_editor_doc(doc, force_refresh=force)
+ editor = self.get_current_editor()
+ editor.setFocus()
+
+ def new(self, filename, encoding, text, default_content=False,
+ empty=False):
+ """
+ Create new filename with *encoding* and *text*
+ """
+ finfo = self.create_new_editor(filename, encoding, text,
+ set_current=False, new=True)
+ finfo.editor.set_cursor_position('eof')
+ if not empty:
+ finfo.editor.insert_text(os.linesep)
+ if default_content:
+ finfo.default = True
+ finfo.editor.document().setModified(False)
+ return finfo
+
+ def load(self, filename, set_current=True, add_where='end'):
+ """
+ Load filename, create an editor instance and return it
+ *Warning* This is loading file, creating editor but not executing
+ the source code analysis -- the analysis must be done by the editor
+ plugin (in case multiple editorstack instances are handled)
+ """
+ filename = osp.abspath(to_text_string(filename))
+ self.starting_long_process.emit(_("Loading %s...") % filename)
+ text, enc = encoding.read(filename)
+ finfo = self.create_new_editor(filename, enc, text, set_current,
+ add_where=add_where)
+ index = self.data.index(finfo)
+ self._refresh_outlineexplorer(index, update=True)
+ self.ending_long_process.emit("")
+ if self.isVisible() and self.checkeolchars_enabled \
+ and sourcecode.has_mixed_eol_chars(text):
+ name = osp.basename(filename)
+ self.msgbox = QMessageBox(
+ QMessageBox.Warning,
+ self.title,
+ _("%s contains mixed end-of-line "
+ "characters.
Spyder will fix this "
+ "automatically.") % name,
+ QMessageBox.Ok,
+ self)
+ self.msgbox.exec_()
+ self.set_os_eol_chars(index)
+ self.is_analysis_done = False
+ self.analyze_script(index)
+ return finfo
+
+ def set_os_eol_chars(self, index=None, osname=None):
+ """Sets the EOL character(s) based on the operating system.
+
+ If `osname` is None, then the default line endings for the current
+ operating system (`os.name` value) will be used.
+
+ `osname` can be one of:
+ ('posix', 'nt', 'java')
+ """
+ if osname is None:
+ osname = os.name
+ if index is None:
+ index = self.get_stack_index()
+ finfo = self.data[index]
+ eol_chars = sourcecode.get_eol_chars_from_os_name(osname)
+ finfo.editor.set_eol_chars(eol_chars)
+ finfo.editor.document().setModified(True)
+
+ def remove_trailing_spaces(self, index=None):
+ """Remove trailing spaces"""
+ if index is None:
+ index = self.get_stack_index()
+ finfo = self.data[index]
+ finfo.editor.remove_trailing_spaces()
+
+ def fix_indentation(self, index=None):
+ """Replace tab characters by spaces"""
+ if index is None:
+ index = self.get_stack_index()
+ finfo = self.data[index]
+ finfo.editor.fix_indentation()
+
+ #------ Run
+ def run_selection(self):
+ """
+ Run selected text or current line in console.
+
+ If some text is selected, then execute that text in console.
+
+ If no text is selected, then execute current line, unless current line
+ is empty. Then, advance cursor to next line. If cursor is on last line
+ and that line is not empty, then add a new blank line and move the
+ cursor there. If cursor is on last line and that line is empty, then do
+ not move cursor.
+ """
+ text = self.get_current_editor().get_selection_as_executable_code()
+ if text:
+ self.exec_in_extconsole.emit(text.rstrip(), self.focus_to_editor)
+ return
+ editor = self.get_current_editor()
+ line = editor.get_current_line()
+ text = line.lstrip()
+ if text:
+ self.exec_in_extconsole.emit(text, self.focus_to_editor)
+ if editor.is_cursor_on_last_line() and text:
+ editor.append(editor.get_line_separator())
+ editor.move_cursor_to_next('line', 'down')
+
+ def run_cell(self):
+ """Run current cell."""
+ text, block = self.get_current_editor().get_cell_as_executable_code()
+ self._run_cell_text(text, block)
+
+ def run_cell_and_advance(self):
+ """Run current cell and advance to the next one"""
+ self.run_cell()
+ self.advance_cell()
+
+ def advance_cell(self, reverse=False):
+ """Advance to the next cell.
+
+ reverse = True --> go to previous cell.
+ """
+ if not reverse:
+ move_func = self.get_current_editor().go_to_next_cell
+ else:
+ move_func = self.get_current_editor().go_to_previous_cell
+
+ if self.focus_to_editor:
+ move_func()
+ else:
+ term = QApplication.focusWidget()
+ move_func()
+ term.setFocus()
+ term = QApplication.focusWidget()
+ move_func()
+ term.setFocus()
+
+ def re_run_last_cell(self):
+ """Run the previous cell again."""
+ last_cell = (self.get_current_editor()
+ .get_last_cell_as_executable_code())
+ if not last_cell:
+ return
+ self._run_cell_text(*last_cell)
+
+ def _get_cell_name(self, block):
+ """Get the cell name from the block."""
+ oe_data = block.userData()
+ if oe_data and oe_data.oedata:
+ cell_name = oe_data.oedata.def_name
+ else:
+ if block.firstLineNumber() == 0:
+ cell_name = 'Cell at line 0'
+ else:
+ raise RuntimeError('Not a cell?')
+ return cell_name
+
+ def _run_cell_text(self, text, block):
+ """Run cell code in the console.
+
+ Cell code is run in the console by copying it to the console if
+ `self.run_cell_copy` is ``True`` otherwise by using the `run_cell`
+ function.
+
+ Parameters
+ ----------
+ text : str
+ The code in the cell as a string.
+ line : int
+ The starting line number of the cell in the file.
+ """
+ finfo = self.get_current_finfo()
+ editor = self.get_current_editor()
+ cell_name = self._get_cell_name(block)
+ if finfo.editor.is_python() and text:
+ self.run_cell_in_ipyclient.emit(text, cell_name,
+ finfo.filename,
+ self.run_cell_copy)
+ editor.setFocus()
+
+ #------ Drag and drop
+ def dragEnterEvent(self, event):
+ """Reimplement Qt method
+ Inform Qt about the types of data that the widget accepts"""
+ source = event.mimeData()
+ # The second check is necessary on Windows, where source.hasUrls()
+ # can return True but source.urls() is []
+ # The third check is needed since a file could be dropped from
+ # compressed files. In Windows mimedata2url(source) returns None
+ # Fixes issue 5218
+ if source.hasUrls() and source.urls() and mimedata2url(source):
+ all_urls = mimedata2url(source)
+ text = [encoding.is_text_file(url) for url in all_urls]
+ if any(text):
+ event.acceptProposedAction()
+ else:
+ event.ignore()
+ elif source.hasText():
+ event.acceptProposedAction()
+ elif os.name == 'nt':
+ # This covers cases like dragging from compressed files,
+ # which can be opened by the Editor if they are plain
+ # text, but doesn't come with url info.
+ # Fixes Issue 2032
+ event.acceptProposedAction()
+ else:
+ event.ignore()
+
+ def dropEvent(self, event):
+ """Reimplement Qt method
+ Unpack dropped data and handle it"""
+ source = event.mimeData()
+ # The second check is necessary when mimedata2url(source)
+ # returns None.
+ # Fixes issue 7742
+ if source.hasUrls() and mimedata2url(source):
+ files = mimedata2url(source)
+ files = [f for f in files if encoding.is_text_file(f)]
+ files = set(files or [])
+ for fname in files:
+ self.plugin_load.emit(fname)
+ elif source.hasText():
+ editor = self.get_current_editor()
+ if editor is not None:
+ editor.insert_text(source.text())
+ else:
+ event.ignore()
+ event.acceptProposedAction()
+
+
+class EditorSplitter(QSplitter):
+ """QSplitter for editor windows."""
+
+ def __init__(self, parent, plugin, menu_actions, first=False,
+ register_editorstack_cb=None, unregister_editorstack_cb=None):
+ """Create a splitter for dividing an editor window into panels.
+
+ Adds a new EditorStack instance to this splitter. If it's not
+ the first splitter, clones the current EditorStack from the plugin.
+
+ Args:
+ parent: Parent widget.
+ plugin: Plugin this widget belongs to.
+ menu_actions: QActions to include from the parent.
+ first: Boolean if this is the first splitter in the editor.
+ register_editorstack_cb: Callback to register the EditorStack.
+ Defaults to plugin.register_editorstack() to
+ register the EditorStack with the Editor plugin.
+ unregister_editorstack_cb: Callback to unregister the EditorStack.
+ Defaults to plugin.unregister_editorstack() to
+ unregister the EditorStack with the Editor plugin.
+ """
+ QSplitter.__init__(self, parent)
+ self.setAttribute(Qt.WA_DeleteOnClose)
+ self.setChildrenCollapsible(False)
+
+ self.toolbar_list = None
+ self.menu_list = None
+
+ self.plugin = plugin
+
+ if register_editorstack_cb is None:
+ register_editorstack_cb = self.plugin.register_editorstack
+ self.register_editorstack_cb = register_editorstack_cb
+ if unregister_editorstack_cb is None:
+ unregister_editorstack_cb = self.plugin.unregister_editorstack
+ self.unregister_editorstack_cb = unregister_editorstack_cb
+
+ self.menu_actions = menu_actions
+ self.editorstack = EditorStack(self, menu_actions)
+ self.register_editorstack_cb(self.editorstack)
+ if not first:
+ self.plugin.clone_editorstack(editorstack=self.editorstack)
+ self.editorstack.destroyed.connect(lambda: self.editorstack_closed())
+ self.editorstack.sig_split_vertically.connect(
+ lambda: self.split(orientation=Qt.Vertical))
+ self.editorstack.sig_split_horizontally.connect(
+ lambda: self.split(orientation=Qt.Horizontal))
+ self.addWidget(self.editorstack)
+
+ def closeEvent(self, event):
+ """Override QWidget closeEvent().
+
+ This event handler is called with the given event when Qt
+ receives a window close request from a top-level widget.
+ """
+ QSplitter.closeEvent(self, event)
+
+ def __give_focus_to_remaining_editor(self):
+ focus_widget = self.plugin.get_focus_widget()
+ if focus_widget is not None:
+ focus_widget.setFocus()
+
+ def editorstack_closed(self):
+ logger.debug("method 'editorstack_closed':")
+ logger.debug(" self : %r" % self)
+ try:
+ self.unregister_editorstack_cb(self.editorstack)
+ self.editorstack = None
+ close_splitter = self.count() == 1
+ except (RuntimeError, AttributeError):
+ # editorsplitter has been destroyed (happens when closing a
+ # EditorMainWindow instance)
+ return
+ if close_splitter:
+ # editorstack just closed was the last widget in this QSplitter
+ self.close()
+ return
+ self.__give_focus_to_remaining_editor()
+
+ def editorsplitter_closed(self):
+ logger.debug("method 'editorsplitter_closed':")
+ logger.debug(" self : %r" % self)
+ try:
+ close_splitter = self.count() == 1 and self.editorstack is None
+ except RuntimeError:
+ # editorsplitter has been destroyed (happens when closing a
+ # EditorMainWindow instance)
+ return
+ if close_splitter:
+ # editorsplitter just closed was the last widget in this QSplitter
+ self.close()
+ return
+ elif self.count() == 2 and self.editorstack:
+ # back to the initial state: a single editorstack instance,
+ # as a single widget in this QSplitter: orientation may be changed
+ self.editorstack.reset_orientation()
+ self.__give_focus_to_remaining_editor()
+
+ def split(self, orientation=Qt.Vertical):
+ """Create and attach a new EditorSplitter to the current EditorSplitter.
+
+ The new EditorSplitter widget will contain an EditorStack that
+ is a clone of the current EditorStack.
+
+ A single EditorSplitter instance can be split multiple times, but the
+ orientation will be the same for all the direct splits. If one of
+ the child splits is split, then that split can have a different
+ orientation.
+ """
+ self.setOrientation(orientation)
+ self.editorstack.set_orientation(orientation)
+ editorsplitter = EditorSplitter(self.parent(), self.plugin,
+ self.menu_actions,
+ register_editorstack_cb=self.register_editorstack_cb,
+ unregister_editorstack_cb=self.unregister_editorstack_cb)
+ self.addWidget(editorsplitter)
+ editorsplitter.destroyed.connect(lambda: self.editorsplitter_closed())
+ current_editor = editorsplitter.editorstack.get_current_editor()
+ if current_editor is not None:
+ current_editor.setFocus()
+
+ def iter_editorstacks(self):
+ """Return the editor stacks for this splitter and every first child.
+
+ Note: If a splitter contains more than one splitter as a direct
+ child, only the first child's editor stack is included.
+
+ Returns:
+ List of tuples containing (EditorStack instance, orientation).
+ """
+ editorstacks = [(self.widget(0), self.orientation())]
+ if self.count() > 1:
+ editorsplitter = self.widget(1)
+ editorstacks += editorsplitter.iter_editorstacks()
+ return editorstacks
+
+ def get_layout_settings(self):
+ """Return the layout state for this splitter and its children.
+
+ Record the current state, including file names and current line
+ numbers, of the splitter panels.
+
+ Returns:
+ A dictionary containing keys {hexstate, sizes, splitsettings}.
+ hexstate: String of saveState() for self.
+ sizes: List for size() for self.
+ splitsettings: List of tuples of the form
+ (orientation, cfname, clines) for each EditorSplitter
+ and its EditorStack.
+ orientation: orientation() for the editor
+ splitter (which may be a child of self).
+ cfname: EditorStack current file name.
+ clines: Current line number for each file in the
+ EditorStack.
+ """
+ splitsettings = []
+ for editorstack, orientation in self.iter_editorstacks():
+ clines = []
+ cfname = ''
+ # XXX - this overrides value from the loop to always be False?
+ orientation = False
+ if hasattr(editorstack, 'data'):
+ clines = [finfo.editor.get_cursor_line_number()
+ for finfo in editorstack.data]
+ cfname = editorstack.get_current_filename()
+ splitsettings.append((orientation == Qt.Vertical, cfname, clines))
+ return dict(hexstate=qbytearray_to_str(self.saveState()),
+ sizes=self.sizes(), splitsettings=splitsettings)
+
+ def set_layout_settings(self, settings, dont_goto=None):
+ """Restore layout state for the splitter panels.
+
+ Apply the settings to restore a saved layout within the editor. If
+ the splitsettings key doesn't exist, then return without restoring
+ any settings.
+
+ The current EditorSplitter (self) calls split() for each element
+ in split_settings, thus recreating the splitter panels from the saved
+ state. split() also clones the editorstack, which is then
+ iterated over to restore the saved line numbers on each file.
+
+ The size and positioning of each splitter panel is restored from
+ hexstate.
+
+ Args:
+ settings: A dictionary with keys {hexstate, sizes, orientation}
+ that define the layout for the EditorSplitter panels.
+ dont_goto: Defaults to None, which positions the cursor to the
+ end of the editor. If there's a value, positions the
+ cursor on the saved line number for each editor.
+ """
+ splitsettings = settings.get('splitsettings')
+ if splitsettings is None:
+ return
+ splitter = self
+ editor = None
+ for index, (is_vertical, cfname, clines) in enumerate(splitsettings):
+ if index > 0:
+ splitter.split(Qt.Vertical if is_vertical else Qt.Horizontal)
+ splitter = splitter.widget(1)
+ editorstack = splitter.widget(0)
+ for index, finfo in enumerate(editorstack.data):
+ editor = finfo.editor
+ # TODO: go_to_line is not working properly (the line it jumps
+ # to is not the corresponding to that file). This will be fixed
+ # in a future PR (which will fix issue #3857)
+ if dont_goto is not None:
+ # skip go to line for first file because is already there
+ pass
+ else:
+ try:
+ editor.go_to_line(clines[index])
+ except IndexError:
+ pass
+ hexstate = settings.get('hexstate')
+ if hexstate is not None:
+ self.restoreState( QByteArray().fromHex(
+ str(hexstate).encode('utf-8')) )
+ sizes = settings.get('sizes')
+ if sizes is not None:
+ self.setSizes(sizes)
+ if editor is not None:
+ editor.clearFocus()
+ editor.setFocus()
+
+
+class EditorWidget(QSplitter):
+ def __init__(self, parent, plugin, menu_actions, outline_explorer_options):
+ QSplitter.__init__(self, parent)
+ self.setAttribute(Qt.WA_DeleteOnClose)
+
+ statusbar = parent.statusBar() # Create a status bar
+ self.vcs_status = VCSStatus(self, statusbar)
+ self.cursorpos_status = CursorPositionStatus(self, statusbar)
+ self.encoding_status = EncodingStatus(self, statusbar)
+ self.eol_status = EOLStatus(self, statusbar)
+ self.readwrite_status = ReadWriteStatus(self, statusbar)
+
+ self.editorstacks = []
+
+ self.plugin = plugin
+
+ self.find_widget = FindReplace(self, enable_replace=True)
+ self.plugin.register_widget_shortcuts(self.find_widget)
+ self.find_widget.hide()
+ self.outlineexplorer = OutlineExplorerWidget(
+ self,
+ show_fullpath=outline_explorer_options['show_fullpath'],
+ show_all_files=outline_explorer_options['show_all_files'],
+ group_cells=outline_explorer_options['group_cells'],
+ show_comments=outline_explorer_options['show_comments'],
+ sort_files_alphabetically=outline_explorer_options[
+ 'sort_files_alphabetically'],
+ )
+ self.outlineexplorer.edit_goto.connect(
+ lambda filenames, goto, word:
+ plugin.load(filenames=filenames, goto=goto, word=word,
+ editorwindow=self.parent()))
+
+ editor_widgets = QWidget(self)
+ editor_layout = QVBoxLayout()
+ editor_layout.setContentsMargins(0, 0, 0, 0)
+ editor_widgets.setLayout(editor_layout)
+ editorsplitter = EditorSplitter(self, plugin, menu_actions,
+ register_editorstack_cb=self.register_editorstack,
+ unregister_editorstack_cb=self.unregister_editorstack)
+ self.editorsplitter = editorsplitter
+ editor_layout.addWidget(editorsplitter)
+ editor_layout.addWidget(self.find_widget)
+
+ splitter = QSplitter(self)
+ splitter.setContentsMargins(0, 0, 0, 0)
+ splitter.addWidget(editor_widgets)
+ splitter.addWidget(self.outlineexplorer)
+ splitter.setStretchFactor(0, 5)
+ splitter.setStretchFactor(1, 1)
+
+ # Refreshing outline explorer
+ editorsplitter.editorstack.initialize_outlineexplorer()
+
+ def register_editorstack(self, editorstack):
+ self.editorstacks.append(editorstack)
+ logger.debug("EditorWidget.register_editorstack: %r" % editorstack)
+ self.__print_editorstacks()
+ self.plugin.last_focus_editorstack[self.parent()] = editorstack
+ editorstack.set_closable( len(self.editorstacks) > 1 )
+ editorstack.set_outlineexplorer(self.outlineexplorer)
+ editorstack.set_find_widget(self.find_widget)
+ editorstack.reset_statusbar.connect(self.readwrite_status.hide)
+ editorstack.reset_statusbar.connect(self.encoding_status.hide)
+ editorstack.reset_statusbar.connect(self.cursorpos_status.hide)
+ editorstack.readonly_changed.connect(
+ self.readwrite_status.update_readonly)
+ editorstack.encoding_changed.connect(
+ self.encoding_status.update_encoding)
+ editorstack.sig_editor_cursor_position_changed.connect(
+ self.cursorpos_status.update_cursor_position)
+ editorstack.sig_refresh_eol_chars.connect(self.eol_status.update_eol)
+ self.plugin.register_editorstack(editorstack)
+ oe_btn = create_toolbutton(self)
+ oe_btn.setDefaultAction(self.outlineexplorer.visibility_action)
+ editorstack.add_corner_widgets_to_tabbar([5, oe_btn])
+
+ def __print_editorstacks(self):
+ logger.debug("%d editorstack(s) in editorwidget:" %
+ len(self.editorstacks))
+ for edst in self.editorstacks:
+ logger.debug(" %r" % edst)
+
+ def unregister_editorstack(self, editorstack):
+ logger.debug("EditorWidget.unregister_editorstack: %r" % editorstack)
+ self.plugin.unregister_editorstack(editorstack)
+ self.editorstacks.pop(self.editorstacks.index(editorstack))
+ self.__print_editorstacks()
+
+
+class EditorMainWindow(QMainWindow):
+ def __init__(self, plugin, menu_actions, toolbar_list, menu_list,
+ outline_explorer_options):
+ QMainWindow.__init__(self)
+ self.setAttribute(Qt.WA_DeleteOnClose)
+
+ self.plugin = plugin
+ self.window_size = None
+
+ self.editorwidget = EditorWidget(self, plugin, menu_actions,
+ outline_explorer_options)
+ self.setCentralWidget(self.editorwidget)
+
+ # Setting interface theme
+ if is_dark_interface():
+ self.setStyleSheet(qdarkstyle.load_stylesheet_from_environment())
+
+ # Give focus to current editor to update/show all status bar widgets
+ editorstack = self.editorwidget.editorsplitter.editorstack
+ editor = editorstack.get_current_editor()
+ if editor is not None:
+ editor.setFocus()
+
+ self.setWindowTitle("Spyder - %s" % plugin.windowTitle())
+ self.setWindowIcon(plugin.windowIcon())
+
+ if toolbar_list:
+ self.toolbars = []
+ for title, object_name, actions in toolbar_list:
+ toolbar = self.addToolBar(title)
+ toolbar.setObjectName(object_name)
+ add_actions(toolbar, actions)
+ self.toolbars.append(toolbar)
+ if menu_list:
+ quit_action = create_action(self, _("Close window"),
+ icon="close_panel.png",
+ tip=_("Close this window"),
+ triggered=self.close)
+ self.menus = []
+ for index, (title, actions) in enumerate(menu_list):
+ menu = self.menuBar().addMenu(title)
+ if index == 0:
+ # File menu
+ add_actions(menu, actions+[None, quit_action])
+ else:
+ add_actions(menu, actions)
+ self.menus.append(menu)
+
+ def get_toolbars(self):
+ """Get the toolbars."""
+ return self.toolbars
+
+ def add_toolbars_to_menu(self, menu_title, actions):
+ """Add toolbars to a menu."""
+ # Six is the position of the view menu in menus list
+ # that you can find in plugins/editor.py setup_other_windows.
+ view_menu = self.menus[6]
+ if actions == self.toolbars and view_menu:
+ toolbars = []
+ for toolbar in self.toolbars:
+ action = toolbar.toggleViewAction()
+ toolbars.append(action)
+ add_actions(view_menu, toolbars)
+
+ def load_toolbars(self):
+ """Loads the last visible toolbars from the .ini file."""
+ toolbars_names = CONF.get('main', 'last_visible_toolbars', default=[])
+ if toolbars_names:
+ dic = {}
+ for toolbar in self.toolbars:
+ dic[toolbar.objectName()] = toolbar
+ toolbar.toggleViewAction().setChecked(False)
+ toolbar.setVisible(False)
+ for name in toolbars_names:
+ if name in dic:
+ dic[name].toggleViewAction().setChecked(True)
+ dic[name].setVisible(True)
+
+ def resizeEvent(self, event):
+ """Reimplement Qt method"""
+ if not self.isMaximized() and not self.isFullScreen():
+ self.window_size = self.size()
+ QMainWindow.resizeEvent(self, event)
+
+ def closeEvent(self, event):
+ """Reimplement Qt method"""
+ if self.plugin.undocked_window is not None:
+ self.plugin.dockwidget.setWidget(self.plugin)
+ self.plugin.dockwidget.setVisible(True)
+ self.plugin.switch_to_plugin()
+ QMainWindow.closeEvent(self, event)
+ if self.plugin.undocked_window is not None:
+ self.plugin.undocked_window = None
+
+ def get_layout_settings(self):
+ """Return layout state"""
+ splitsettings = self.editorwidget.editorsplitter.get_layout_settings()
+ return dict(size=(self.window_size.width(), self.window_size.height()),
+ pos=(self.pos().x(), self.pos().y()),
+ is_maximized=self.isMaximized(),
+ is_fullscreen=self.isFullScreen(),
+ hexstate=qbytearray_to_str(self.saveState()),
+ splitsettings=splitsettings)
+
+ def set_layout_settings(self, settings):
+ """Restore layout state"""
+ size = settings.get('size')
+ if size is not None:
+ self.resize( QSize(*size) )
+ self.window_size = self.size()
+ pos = settings.get('pos')
+ if pos is not None:
+ self.move( QPoint(*pos) )
+ hexstate = settings.get('hexstate')
+ if hexstate is not None:
+ self.restoreState( QByteArray().fromHex(
+ str(hexstate).encode('utf-8')) )
+ if settings.get('is_maximized'):
+ self.setWindowState(Qt.WindowMaximized)
+ if settings.get('is_fullscreen'):
+ self.setWindowState(Qt.WindowFullScreen)
+ splitsettings = settings.get('splitsettings')
+ if splitsettings is not None:
+ self.editorwidget.editorsplitter.set_layout_settings(splitsettings)
+
+
+class EditorPluginExample(QSplitter):
+ def __init__(self):
+ QSplitter.__init__(self)
+
+ self.dock_action = None
+ self.undock_action = None
+ self.close_plugin_action = None
+ self.undocked_window = None
+ menu_actions = []
+
+ self.editorstacks = []
+ self.editorwindows = []
+
+ self.last_focus_editorstack = {} # fake
+
+ self.find_widget = FindReplace(self, enable_replace=True)
+ self.outlineexplorer = OutlineExplorerWidget(self, show_fullpath=False,
+ show_all_files=False)
+ self.outlineexplorer.edit_goto.connect(self.go_to_file)
+ self.editor_splitter = EditorSplitter(self, self, menu_actions,
+ first=True)
+
+ editor_widgets = QWidget(self)
+ editor_layout = QVBoxLayout()
+ editor_layout.setContentsMargins(0, 0, 0, 0)
+ editor_widgets.setLayout(editor_layout)
+ editor_layout.addWidget(self.editor_splitter)
+ editor_layout.addWidget(self.find_widget)
+
+ self.setContentsMargins(0, 0, 0, 0)
+ self.addWidget(editor_widgets)
+ self.addWidget(self.outlineexplorer)
+
+ self.setStretchFactor(0, 5)
+ self.setStretchFactor(1, 1)
+
+ self.menu_actions = menu_actions
+ self.toolbar_list = None
+ self.menu_list = None
+ self.setup_window([], [])
+
+ def go_to_file(self, fname, lineno, text='', start_column=None):
+ editorstack = self.editorstacks[0]
+ editorstack.set_current_filename(to_text_string(fname))
+ editor = editorstack.get_current_editor()
+ editor.go_to_line(lineno, word=text, start_column=start_column)
+
+ def closeEvent(self, event):
+ for win in self.editorwindows[:]:
+ win.close()
+ logger.debug("%d: %r" % (len(self.editorwindows), self.editorwindows))
+ logger.debug("%d: %r" % (len(self.editorstacks), self.editorstacks))
+ event.accept()
+
+ def load(self, fname):
+ QApplication.processEvents()
+ editorstack = self.editorstacks[0]
+ editorstack.load(fname)
+ editorstack.analyze_script()
+
+ def register_editorstack(self, editorstack):
+ logger.debug("FakePlugin.register_editorstack: %r" % editorstack)
+ self.editorstacks.append(editorstack)
+ if self.isAncestorOf(editorstack):
+ # editorstack is a child of the Editor plugin
+ editorstack.set_closable(len(self.editorstacks) > 1)
+ editorstack.set_outlineexplorer(self.outlineexplorer)
+ editorstack.set_find_widget(self.find_widget)
+ oe_btn = create_toolbutton(self)
+ oe_btn.setDefaultAction(self.outlineexplorer.visibility_action)
+ editorstack.add_corner_widgets_to_tabbar([5, oe_btn])
+
+ action = QAction(self)
+ editorstack.set_io_actions(action, action, action, action)
+ font = QFont("Courier New")
+ font.setPointSize(10)
+ editorstack.set_default_font(font, color_scheme='Spyder')
+
+ editorstack.sig_close_file.connect(self.close_file_in_all_editorstacks)
+ editorstack.file_saved.connect(self.file_saved_in_editorstack)
+ editorstack.file_renamed_in_data.connect(
+ self.file_renamed_in_data_in_editorstack)
+ editorstack.plugin_load.connect(self.load)
+
+ def unregister_editorstack(self, editorstack):
+ logger.debug("FakePlugin.unregister_editorstack: %r" % editorstack)
+ self.editorstacks.pop(self.editorstacks.index(editorstack))
+
+ def clone_editorstack(self, editorstack):
+ editorstack.clone_from(self.editorstacks[0])
+
+ def setup_window(self, toolbar_list, menu_list):
+ self.toolbar_list = toolbar_list
+ self.menu_list = menu_list
+
+ def create_new_window(self):
+ window = EditorMainWindow(self, self.menu_actions,
+ self.toolbar_list, self.menu_list,
+ show_fullpath=False, show_all_files=False,
+ group_cells=True, show_comments=True,
+ sort_files_alphabetically=False)
+ window.resize(self.size())
+ window.show()
+ self.register_editorwindow(window)
+ window.destroyed.connect(lambda: self.unregister_editorwindow(window))
+
+ def register_editorwindow(self, window):
+ logger.debug("register_editorwindowQObject*: %r" % window)
+ self.editorwindows.append(window)
+
+ def unregister_editorwindow(self, window):
+ logger.debug("unregister_editorwindow: %r" % window)
+ self.editorwindows.pop(self.editorwindows.index(window))
+
+ def get_focus_widget(self):
+ pass
+
+ @Slot(str, str)
+ def close_file_in_all_editorstacks(self, editorstack_id_str, filename):
+ for editorstack in self.editorstacks:
+ if str(id(editorstack)) != editorstack_id_str:
+ editorstack.blockSignals(True)
+ index = editorstack.get_index_from_filename(filename)
+ editorstack.close_file(index, force=True)
+ editorstack.blockSignals(False)
+
+ # This method is never called in this plugin example. It's here only
+ # to show how to use the file_saved signal (see above).
+ @Slot(str, str, str)
+ def file_saved_in_editorstack(self, editorstack_id_str,
+ original_filename, filename):
+ """A file was saved in editorstack, this notifies others"""
+ for editorstack in self.editorstacks:
+ if str(id(editorstack)) != editorstack_id_str:
+ editorstack.file_saved_in_other_editorstack(original_filename,
+ filename)
+
+ # This method is never called in this plugin example. It's here only
+ # to show how to use the file_saved signal (see above).
+ @Slot(str, str, str)
+ def file_renamed_in_data_in_editorstack(self, editorstack_id_str,
+ original_filename, filename):
+ """A file was renamed in data in editorstack, this notifies others"""
+ for editorstack in self.editorstacks:
+ if str(id(editorstack)) != editorstack_id_str:
+ editorstack.rename_in_data(original_filename, filename)
+
+ def register_widget_shortcuts(self, widget):
+ """Fake!"""
+ pass
+
+
+def test():
+ from spyder.utils.qthelpers import qapplication
+ from spyder.config.base import get_module_path
+
+ spyder_dir = get_module_path('spyder')
+ app = qapplication(test_time=8)
+
+ test = EditorPluginExample()
+ test.resize(900, 700)
+ test.show()
+
+ import time
+ t0 = time.time()
+ test.load(osp.join(spyder_dir, "plugins", "editor", "widgets",
+ "editor.py"))
+ test.load(osp.join(spyder_dir, "plugins", "explorer", "widgets.py"))
+ test.load(osp.join(spyder_dir, "plugins", "variableexplorer", "widgets",
+ "collectionseditor.py"))
+ test.load(osp.join(spyder_dir, "plugins", "editor", "widgets",
+ "codeeditor.py"))
+ print("Elapsed time: %.3f s" % (time.time()-t0)) # spyder: test-skip
+
+ sys.exit(app.exec_())
+
+
+if __name__ == "__main__":
+ test()
diff --git a/spyder/plugins/editor/widgets/recover.py b/spyder/plugins/editor/widgets/recover.py
new file mode 100644
index 00000000000..2ac5fffd7b1
--- /dev/null
+++ b/spyder/plugins/editor/widgets/recover.py
@@ -0,0 +1,340 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Dialog window for recovering files from autosave"""
+
+# Standard library imports
+from os import path as osp
+import os
+import shutil
+import time
+
+# Third party imports
+from qtpy.compat import getsavefilename
+from qtpy.QtCore import Qt
+from qtpy.QtWidgets import (QDialog, QDialogButtonBox, QHBoxLayout, QLabel,
+ QMessageBox, QPushButton, QTableWidget,
+ QVBoxLayout, QWidget)
+
+# Local imports
+from spyder.config.base import _, running_under_pytest
+
+
+def gather_file_data(name):
+ """
+ Gather data about a given file.
+
+ Returns a dict with fields name, mtime and size, containing the relevant
+ data for the fiel.
+ """
+ res = {'name': name}
+ try:
+ res['mtime'] = osp.getmtime(name)
+ res['size'] = osp.getsize(name)
+ except OSError:
+ pass
+ return res
+
+
+def file_data_to_str(data):
+ """
+ Convert file data to a string for display.
+
+ This function takes the file data produced by gather_file_data().
+ """
+ if not data:
+ return _('File name not recorded')
+ res = data['name']
+ try:
+ mtime_as_str = time.strftime('%Y-%m-%d %H:%M:%S',
+ time.localtime(data['mtime']))
+ res += '
{}: {}'.format(_('Last modified'), mtime_as_str)
+ res += '
{}: {} {}'.format(
+ _('Size'), data['size'], _('bytes'))
+ except KeyError:
+ res += '
' + _('File no longer exists')
+ return res
+
+
+def recovery_data_key_function(item):
+ """
+ Convert item in `RecoveryDialog.data` to tuple so that it can be sorted.
+
+ Sorting the tuples returned by this function will sort first by name of
+ the original file, then by name of the autosave file. All items without an
+ original file name will be at the end.
+ """
+ orig_dict, autosave_dict = item
+ if orig_dict:
+ return (0, orig_dict['name'], autosave_dict['name'])
+ else:
+ return (1, 0, autosave_dict['name'])
+
+
+class RecoveryDialog(QDialog):
+ def __init__(self, autosave_dir, autosave_mapping, parent=None):
+ """Constructor."""
+ QDialog.__init__(self, parent)
+ self.layout = QVBoxLayout(self)
+ self.setLayout(self.layout)
+ self.layout.setSpacing(self.layout.spacing() * 3)
+ self.autosave_dir = autosave_dir
+ self.autosave_mapping = autosave_mapping
+ self.files_to_open = []
+ self.gather_data()
+ self.add_label()
+ self.add_table()
+ self.add_cancel_button()
+ self.setWindowTitle(_('Recover from autosave'))
+
+ def gather_data(self):
+ """
+ Gather data about files which may be recovered.
+
+ The data is stored in self.data as a list of tuples with the data
+ pertaining to the original file and the autosave file. Each element of
+ the tuple is a dict as returned by gather_file_data().
+ """
+ self.data = []
+ try:
+ FileNotFoundError
+ except NameError: # Python 2
+ FileNotFoundError = OSError
+ # In Python 3, easier to use os.scandir()
+ try:
+ for name in os.listdir(self.autosave_dir):
+ full_name = osp.join(self.autosave_dir, name)
+ if osp.isdir(full_name):
+ continue
+ for orig, autosave in self.autosave_mapping.items():
+ if autosave == full_name:
+ orig_dict = gather_file_data(orig)
+ break
+ else:
+ orig_dict = None
+ autosave_dict = gather_file_data(full_name)
+ self.data.append((orig_dict, autosave_dict))
+ except FileNotFoundError: # autosave dir does not exist
+ pass
+ self.data.sort(key=recovery_data_key_function)
+ self.num_enabled = len(self.data)
+
+ def add_label(self):
+ """Add label with explanation at top of dialog window."""
+ txt = _('Autosave files found. What would you like to do?\n\n'
+ 'This dialog will be shown again on next startup if any '
+ 'autosave files are not restored, moved or deleted.')
+ label = QLabel(txt, self)
+ label.setWordWrap(True)
+ self.layout.addWidget(label)
+
+ def add_label_to_table(self, row, col, txt):
+ """Add a label to specified cell in table."""
+ label = QLabel(txt)
+ label.setMargin(5)
+ label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
+ self.table.setCellWidget(row, col, label)
+
+ def add_table(self):
+ """Add table with info about files to be recovered."""
+ table = QTableWidget(len(self.data), 3, self)
+ self.table = table
+
+ labels = [_('Original file'), _('Autosave file'), _('Actions')]
+ table.setHorizontalHeaderLabels(labels)
+ table.verticalHeader().hide()
+
+ table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+ table.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+ table.setSelectionMode(QTableWidget.NoSelection)
+
+ # Show horizontal grid lines
+ table.setShowGrid(False)
+ table.setStyleSheet('::item { border-bottom: 1px solid gray }')
+
+ for idx, (original, autosave) in enumerate(self.data):
+ self.add_label_to_table(idx, 0, file_data_to_str(original))
+ self.add_label_to_table(idx, 1, file_data_to_str(autosave))
+
+ widget = QWidget()
+ layout = QHBoxLayout()
+
+ tooltip = _('Recover the autosave file to its original location, '
+ 'replacing the original if it exists.')
+ button = QPushButton(_('Restore'))
+ button.setToolTip(tooltip)
+ button.clicked.connect(
+ lambda checked, my_idx=idx: self.restore(my_idx))
+ layout.addWidget(button)
+
+ tooltip = _('Delete the autosave file.')
+ button = QPushButton(_('Discard'))
+ button.setToolTip(tooltip)
+ button.clicked.connect(
+ lambda checked, my_idx=idx: self.discard(my_idx))
+ layout.addWidget(button)
+
+ tooltip = _('Display the autosave file (and the original, if it '
+ 'exists) in Spyder\'s Editor. You will have to move '
+ 'or delete it manually.')
+ button = QPushButton(_('Open'))
+ button.setToolTip(tooltip)
+ button.clicked.connect(
+ lambda checked, my_idx=idx: self.open_files(my_idx))
+ layout.addWidget(button)
+
+ widget.setLayout(layout)
+ self.table.setCellWidget(idx, 2, widget)
+
+ table.resizeRowsToContents()
+ table.resizeColumnsToContents()
+
+ # Need to add the "+ 2" because otherwise the table scrolls a tiny
+ # amount; no idea why
+ width = table.horizontalHeader().length() + 2
+ height = (table.verticalHeader().length()
+ + table.horizontalHeader().height() + 2)
+ table.setFixedSize(width, height)
+ self.layout.addWidget(table)
+
+ def add_cancel_button(self):
+ """Add a cancel button at the bottom of the dialog window."""
+ button_box = QDialogButtonBox(QDialogButtonBox.Cancel, self)
+ button_box.rejected.connect(self.reject)
+ self.layout.addWidget(button_box)
+
+ def restore(self, idx):
+ orig, autosave = self.data[idx]
+ if orig:
+ orig_name = orig['name']
+ else:
+ orig_name, ignored = getsavefilename(
+ self, _('Restore autosave file to ...'),
+ osp.basename(autosave['name']))
+ if not orig_name:
+ return
+ try:
+ try:
+ os.replace(autosave['name'], orig_name)
+ except (AttributeError, OSError):
+ # os.replace() does not exist on Python 2 and fails if the
+ # files are on different file systems (issue #8631)
+ shutil.copy2(autosave['name'], orig_name)
+ os.remove(autosave['name'])
+ self.deactivate(idx)
+ except EnvironmentError as error:
+ text = (_('Unable to restore {} using {}')
+ .format(orig_name, autosave['name']))
+ self.report_error(text, error)
+
+ def discard(self, idx):
+ ignored, autosave = self.data[idx]
+ try:
+ os.remove(autosave['name'])
+ self.deactivate(idx)
+ except EnvironmentError as error:
+ text = _('Unable to discard {}').format(autosave['name'])
+ self.report_error(text, error)
+
+ def open_files(self, idx):
+ orig, autosave = self.data[idx]
+ if orig:
+ self.files_to_open.append(orig['name'])
+ self.files_to_open.append(autosave['name'])
+ self.deactivate(idx)
+
+ def report_error(self, text, error):
+ heading = _('Error message:')
+ msgbox = QMessageBox(
+ QMessageBox.Critical, _('Restore'),
+ _('{}
{}
{}').format(text, heading, error),
+ parent=self)
+ msgbox.exec_()
+
+ def deactivate(self, idx):
+ for col in range(self.table.columnCount()):
+ self.table.cellWidget(idx, col).setEnabled(False)
+ self.num_enabled -= 1
+ if self.num_enabled == 0:
+ self.accept()
+
+ def exec_if_nonempty(self):
+ """Execute dialog window if there is data to show."""
+ if self.data:
+ return self.exec_()
+ else:
+ return QDialog.Accepted
+
+ def exec_(self):
+ """Execute dialog window."""
+ if running_under_pytest():
+ return QDialog.Accepted
+ return super(RecoveryDialog, self).exec_()
+
+
+def make_temporary_files(tempdir):
+ """
+ Make temporary files to simulate a recovery use case.
+
+ Create a directory under tempdir containing some original files and another
+ directory with autosave files. Return a tuple with the name of the
+ directory with the original files, the name of the directory with the
+ autosave files, and the autosave mapping.
+ """
+ orig_dir = osp.join(tempdir, 'orig')
+ os.mkdir(orig_dir)
+ autosave_dir = osp.join(tempdir, 'autosave')
+ os.mkdir(autosave_dir)
+ autosave_mapping = {}
+
+ # ham.py: Both original and autosave files exist, mentioned in mapping
+ orig_file = osp.join(orig_dir, 'ham.py')
+ with open(orig_file, 'w') as f:
+ f.write('ham = "original"\n')
+ autosave_file = osp.join(autosave_dir, 'ham.py')
+ with open(autosave_file, 'w') as f:
+ f.write('ham = "autosave"\n')
+ autosave_mapping[orig_file] = autosave_file
+
+ # spam.py: Only autosave file exists, mentioned in mapping
+ orig_file = osp.join(orig_dir, 'spam.py')
+ autosave_file = osp.join(autosave_dir, 'spam.py')
+ with open(autosave_file, 'w') as f:
+ f.write('spam = "autosave"\n')
+ autosave_mapping[orig_file] = autosave_file
+
+ # eggs.py: Only original files exists, mentioned in mapping
+ orig_file = osp.join(orig_dir, 'eggs.py')
+ with open(orig_file, 'w') as f:
+ f.write('eggs = "original"\n')
+ autosave_file = osp.join(autosave_dir, 'eggs.py')
+ autosave_mapping[orig_file] = autosave_file
+
+ # cheese.py: Only autosave file exists, not mentioned in mapping
+ autosave_file = osp.join(autosave_dir, 'cheese.py')
+ with open(autosave_file, 'w') as f:
+ f.write('cheese = "autosave"\n')
+
+ return orig_dir, autosave_dir, autosave_mapping
+
+
+def test(): # pragma: no cover
+ """Display recovery dialog for manual testing."""
+ import shutil
+ import tempfile
+ from spyder.utils.qthelpers import qapplication
+
+ app = qapplication()
+ tempdir = tempfile.mkdtemp()
+ _, autosave_dir, autosave_mapping = make_temporary_files(tempdir)
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping)
+ dialog.exec_()
+ print('files_to_open =', dialog.files_to_open) # spyder: test-skip
+ shutil.rmtree(tempdir)
+
+
+if __name__ == "__main__": # pragma: no cover
+ test()
diff --git a/spyder/plugins/editor/widgets/status.py b/spyder/plugins/editor/widgets/status.py
new file mode 100644
index 00000000000..368afc8b95b
--- /dev/null
+++ b/spyder/plugins/editor/widgets/status.py
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Status bar widgets."""
+
+# Standard library imports
+import os
+
+# Local imports
+from spyder.config.base import _
+from spyder.py3compat import to_text_string
+from spyder.utils import icon_manager as ima
+from spyder.utils.vcs import get_git_refs
+from spyder.widgets.status import StatusBarWidget
+
+
+class ReadWriteStatus(StatusBarWidget):
+ """Status bar widget for current file read/write mode."""
+ TIP = _("File permissions")
+
+ def update_readonly(self, readonly):
+ """Update read/write file status."""
+ value = "R" if readonly else "RW"
+ self.set_value(value.ljust(3))
+
+
+class EOLStatus(StatusBarWidget):
+ """Status bar widget for the current file end of line."""
+ TIP = _("End of line")
+
+ def update_eol(self, os_name):
+ """Update end of line status."""
+ os_name = to_text_string(os_name)
+ value = {"nt": "CRLF", "posix": "LF"}.get(os_name, "CR")
+ self.set_value(value)
+
+
+class EncodingStatus(StatusBarWidget):
+ """Status bar widget for the current file encoding."""
+ TIP = _("Encoding")
+
+ def update_encoding(self, encoding):
+ """Update encoding of current file."""
+ value = str(encoding).upper()
+ self.set_value(value)
+
+
+class CursorPositionStatus(StatusBarWidget):
+ """Status bar widget for the current file cursor postion."""
+ TIP = _("Cursor position")
+
+ def update_cursor_position(self, line, index):
+ """Update cursor position."""
+ value = 'Line {}, Col {}'.format(line + 1, index + 1)
+ self.set_value(value)
+
+
+class VCSStatus(StatusBarWidget):
+ """Status bar widget for system vcs."""
+ TIP = _("Git branch")
+
+ def __init__(self, parent, statusbar):
+ super(VCSStatus, self).__init__(parent, statusbar,
+ icon=ima.icon('code_fork'))
+
+ def update_vcs_state(self, idx, fname, fname2):
+ """Update vcs status."""
+ self.update_vcs(fname, None)
+
+ def update_vcs(self, fname, index):
+ """Update vcs status."""
+ fpath = os.path.dirname(fname)
+ branches, branch, files_modified = get_git_refs(fpath)
+ text = branch if branch else ''
+
+ if len(files_modified):
+ text = text + ' [{}]'.format(len(files_modified))
+
+ self.setVisible(bool(branch))
+ self.set_value(text)
+
+ def change_branch(self):
+ """Change current branch."""
+ pass
+
+
+def test():
+ from qtpy.QtWidgets import QMainWindow
+ from spyder.utils.qthelpers import qapplication
+
+ app = qapplication(test_time=5)
+ win = QMainWindow()
+ win.setWindowTitle("Status widgets test")
+ win.resize(900, 300)
+ statusbar = win.statusBar()
+ status_widgets = []
+ for status_class in (ReadWriteStatus, EOLStatus, EncodingStatus,
+ CursorPositionStatus):
+ status_widget = status_class(win, statusbar)
+ status_widgets.append(status_widget)
+ win.show()
+ app.exec_()
+
+
+if __name__ == "__main__":
+ test()
diff --git a/spyder/plugins/tests/__init__.py b/spyder/plugins/editor/widgets/tests/__init__.py
similarity index 100%
rename from spyder/plugins/tests/__init__.py
rename to spyder/plugins/editor/widgets/tests/__init__.py
diff --git a/spyder/plugins/editor/widgets/tests/conftest.py b/spyder/plugins/editor/widgets/tests/conftest.py
new file mode 100644
index 00000000000..476f5eff21f
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/conftest.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+
+"""
+Testing utilities to be used with pytest.
+"""
+
+# Stdlib imports
+try:
+ from unittest.mock import Mock
+except ImportError:
+ from mock import Mock # Python 2
+
+# Third party imports
+import pytest
+from qtpy.QtGui import QFont
+
+# Local imports
+from spyder.plugins.editor.tests.conftest import (
+ editor_plugin, editor_plugin_open_files, python_files)
+from spyder.plugins.editor.lsp.tests.conftest import (
+ lsp_manager, qtbot_module)
+from spyder.plugins.editor.widgets.codeeditor import CodeEditor
+from spyder.plugins.editor.widgets.editor import EditorStack
+from spyder.plugins.explorer.tests.conftest import create_folders_files
+from spyder.widgets.findreplace import FindReplace
+
+
+@pytest.fixture
+def setup_editor(qtbot):
+ """
+ Set up EditorStack with CodeEditor containing some Python code.
+ The cursor is at the empty line below the code.
+ Returns tuple with EditorStack and CodeEditor.
+ """
+ text = ('a = 1\n'
+ 'print(a)\n'
+ '\n'
+ 'x = 2') # a newline is added at end
+ editorStack = EditorStack(None, [])
+ editorStack.set_find_widget(FindReplace(editorStack))
+ editorStack.set_io_actions(Mock(), Mock(), Mock(), Mock())
+ finfo = editorStack.new('foo.py', 'utf-8', text)
+ qtbot.addWidget(editorStack)
+ return editorStack, finfo.editor
+
+
+@pytest.fixture
+def lsp_codeeditor(lsp_manager, qtbot_module, request):
+ """CodeEditor instance with LSP services activated."""
+ # Create a CodeEditor instance
+ editor = CodeEditor(parent=None)
+ editor.setup_editor(language='Python',
+ tab_mode=False,
+ markers=True,
+ close_quotes=True,
+ close_parentheses=True,
+ color_scheme='spyder/dark',
+ font=QFont("Monospace", 10))
+ editor.resize(640, 480)
+ qtbot_module.addWidget(editor)
+ editor.show()
+
+ # Redirect editor LSP requests to lsp_manager
+ editor.sig_perform_lsp_request.connect(lsp_manager.send_request)
+
+ editor.filename = 'test.py'
+ editor.language = 'Python'
+ lsp_manager.register_file('python', 'test.py', editor)
+ server_settings = lsp_manager.main.editor.lsp_editor_settings['python']
+ editor.start_lsp_services(server_settings)
+
+ with qtbot_module.waitSignal(editor.lsp_response_signal, timeout=30000):
+ editor.document_did_open()
+
+ def teardown():
+ editor.hide()
+ editor.completion_widget.hide()
+
+ request.addfinalizer(teardown)
+ return editor, lsp_manager
diff --git a/spyder/widgets/sourcecode/tests/test_autocolon.py b/spyder/plugins/editor/widgets/tests/test_autocolon.py
similarity index 88%
rename from spyder/widgets/sourcecode/tests/test_autocolon.py
rename to spyder/plugins/editor/widgets/tests/test_autocolon.py
index 03e323d1412..dd70791aed6 100644
--- a/spyder/widgets/sourcecode/tests/test_autocolon.py
+++ b/spyder/plugins/editor/widgets/tests/test_autocolon.py
@@ -14,7 +14,7 @@
# Local imports
from spyder.utils.qthelpers import qapplication
-from spyder.widgets.sourcecode.codeeditor import CodeEditor
+from spyder.plugins.editor.widgets.codeeditor import CodeEditor
# --- Fixtures
@@ -39,7 +39,7 @@ def test_no_auto_colon_after_simple_statement():
def test_auto_colon_after_if_statement():
editor = construct_editor("if x == 1")
assert editor.autoinsert_colons() == True
-
+
def test_no_auto_colon_if_not_at_end_of_line():
editor = construct_editor("if x == 1")
cursor = editor.textCursor()
@@ -47,8 +47,8 @@ def test_no_auto_colon_if_not_at_end_of_line():
editor.setTextCursor(cursor)
assert editor.autoinsert_colons() == False
-def test_no_auto_colon_if_unterminated_string():
- editor = construct_editor("if x == '1")
+def test_no_auto_colon_if_unterminated_string():
+ editor = construct_editor("if x == '1")
assert editor.autoinsert_colons() == False
def test_no_auto_colon_in_comment():
@@ -56,15 +56,15 @@ def test_no_auto_colon_in_comment():
assert editor.autoinsert_colons() == False
def test_no_auto_colon_if_already_ends_in_colon():
- editor = construct_editor("if x == 1:")
+ editor = construct_editor("if x == 1:")
assert editor.autoinsert_colons() == False
def test_no_auto_colon_if_ends_in_backslash():
- editor = construct_editor("if x == 1 \\")
+ editor = construct_editor("if x == 1 \\")
assert editor.autoinsert_colons() == False
def test_no_auto_colon_in_one_line_if_statement():
- editor = construct_editor("if x < 0: x = 0")
+ editor = construct_editor("if x < 0: x = 0")
assert editor.autoinsert_colons() == False
def test_auto_colon_even_if_colon_inside_brackets():
@@ -75,7 +75,7 @@ def test_no_auto_colon_in_listcomp_over_two_lines():
editor = construct_editor("ns = [ n for ns in range(10) \n if n < 5 ]")
assert editor.autoinsert_colons() == False
-
+
# --- Failing tests
# -----------------------------------------------------------------------------
@pytest.mark.xfail
@@ -94,9 +94,9 @@ def test_no_auto_colon_in_listcomp_over_three_lines():
@pytest.mark.xfail
def test_auto_colon_in_two_if_statements_on_one_line():
- editor = construct_editor("if x < 0: x = 0; if x == 0")
+ editor = construct_editor("if x < 0: x = 0; if x == 0")
assert editor.autoinsert_colons() == True
-
+
if __name__ == "__main__":
pytest.main()
diff --git a/spyder/plugins/editor/widgets/tests/test_autoindent.py b/spyder/plugins/editor/widgets/tests/test_autoindent.py
new file mode 100644
index 00000000000..5e7f102e104
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/test_autoindent.py
@@ -0,0 +1,264 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+
+"""
+Tests for the autoindent features
+"""
+
+# Third party imports
+from qtpy.QtGui import QTextCursor
+import pytest
+
+# Local imports
+from spyder.utils.qthelpers import qapplication
+from spyder.py3compat import to_text_string
+from spyder.plugins.editor.widgets.codeeditor import CodeEditor
+
+
+# ---- Fixtures
+def get_indent_fix(text, indent_chars=" " * 4, tab_stop_width_spaces=4,
+ sol=False, forward=True, language='Python'):
+ """Return text with last line's indentation fixed."""
+ app = qapplication()
+ editor = CodeEditor(parent=None)
+ editor.setup_editor(language=language, indent_chars=indent_chars,
+ tab_stop_width_spaces=tab_stop_width_spaces)
+
+ editor.set_text(text)
+ cursor = editor.textCursor()
+ cursor.movePosition(QTextCursor.End)
+ if sol:
+ lines = text.splitlines(True)
+ repeat = len(lines[-1].lstrip())
+ cursor.movePosition(QTextCursor.Left, n=repeat)
+ editor.setTextCursor(cursor)
+ editor.fix_indent(forward=forward)
+ return to_text_string(editor.toPlainText())
+
+
+# ---- Tests
+def test_simple_tuple():
+ text = get_indent_fix("this_tuple = (1, 2)\n")
+ assert text == "this_tuple = (1, 2)\n"
+
+
+def test_def_with_newline():
+ text = get_indent_fix("\ndef function():\n")
+ assert text == "\ndef function():\n ", repr(text)
+
+
+def test_def_with_indented_comment():
+ text = get_indent_fix("def function():\n # Comment\n")
+ assert text == "def function():\n # Comment\n ", repr(text)
+
+
+def test_brackets_alone():
+ text = get_indent_fix("def function():\n print []\n")
+ assert text == "def function():\n print []\n ", repr(text)
+
+
+def test_simple_def():
+ text = get_indent_fix("def function():\n")
+ assert text == "def function():\n ", repr(text)
+
+
+def test_open_parenthesis():
+ # An open parenthesis with no item is followed by a hanging indent
+ text = get_indent_fix("open_parenthesis(\n")
+ assert text == "open_parenthesis(\n ", repr(text)
+
+
+def test_open_bracket():
+ # An open bracket with no item is followed by a hanging indent
+ text = get_indent_fix("open_bracket[\n")
+ assert text == "open_bracket[\n ", repr(text)
+
+
+def test_open_curly():
+ # An open curly bracket with no item is followed by a hanging indent
+ text = get_indent_fix("open_curly{\n")
+ assert text == "open_curly{\n ", repr(text)
+
+
+def test_align_on_parenthesis():
+ # An open parenthesis with one or more item is followed by an indent
+ # up to the parenthesis.
+ text = get_indent_fix("parenthesis_w_item = (1,\n")
+ assert text == "parenthesis_w_item = (1,\n ", repr(text)
+
+
+def test_align_on_bracket():
+ # An open bracket with one or more item is followed by an indent
+ # up to the parenthesis.
+ text = get_indent_fix("bracket_w_item = (1,\n")
+ assert text == "bracket_w_item = (1,\n ", repr(text)
+
+
+def test_align_on_curly():
+ # An open curly bracket with one or more item is followed by an indent
+ # up to the parenthesis.
+ text = get_indent_fix("curly_w_item = (1,\n")
+ assert text == "curly_w_item = (1,\n ", repr(text)
+
+
+def test_keep_unindent():
+ # Keep line unindented if there is more than one line under the statement
+ text = (" def foo(bar):\n"
+ " generic = bar\n"
+ " \n"
+ " keep_unindent\n")
+ correct_text = (" def foo(bar):\n"
+ " generic = bar\n"
+ " \n"
+ " keep_unindent\n")
+ text = get_indent_fix(text, sol=True)
+ assert text == correct_text, repr(text)
+
+
+def test_keep_unindent_fix_indent():
+ # Keep line unindented but fix indent if not multiple of len(indent_chars)
+ text = (" for x in range(n):\n"
+ " increment += 1\n"
+ " \n"
+ " keep_unindent\n")
+ correct_text = (" for x in range(n):\n"
+ " increment += 1\n"
+ " \n"
+ " keep_unindent\n")
+ text = get_indent_fix(text, sol=True)
+ assert text == correct_text, repr(text)
+
+
+def test_keep_unindent_if_blank():
+ # Keep line unindented if return is pressed on a line which is both
+ # blank and unindented.
+ text = (" def f(x):\n"
+ " return x\n"
+ "\n"
+ "")
+ text = get_indent_fix(text)
+ assert text == " def f(x):\n return x\n\n", repr(text)
+
+
+def test_first_line():
+ # Test fix_indent() when the cursor is on the first line.
+ text = get_indent_fix("import numpy")
+ assert text == "import numpy", repr(text)
+
+
+def test_indentation_with_spaces():
+ text_input_expected_comment = [
+ ("tags = ['(a)', '(b)', '(c)']\n", "tags = ['(a)', '(b)', '(c)']\n",
+ "test_commented_brackets"),
+ ("s = a[(a['a'] == l) & (a['a'] == 1)]['a']\n",
+ "s = a[(a['a'] == l) & (a['a'] == 1)]['a']\n",
+ "test_balanced_brackets"),
+ ("a = (a # some comment\n", "a = (a # some comment\n ",
+ "test_inline_comment"),
+ ("len(a) == 1\n", "len(a) == 1\n",
+ "test_balanced_brackets_not_ending_in_bracket"),
+ ("x = f(\n", "x = f(\n ",
+ "test_short_open_bracket_not_hanging_indent"),
+ ("def some_func():\n return 10\n",
+ "def some_func():\n return 10\n",
+ "test_return"),
+ ("def some_func():\n returns = 10\n",
+ "def some_func():\n returns = 10\n ",
+ "test_return_not_keyword"),
+ ("foo = 1 # Comment open parenthesis (\n",
+ "foo = 1 # Comment open parenthesis (\n",
+ "test_comment_with parenthesis")
+ ]
+ for text_input, expected, comment in text_input_expected_comment:
+ text = get_indent_fix(text_input)
+ assert text == expected, comment
+
+
+def test_def_with_unindented_comment():
+ text = get_indent_fix("def function():\n# Comment\n")
+ assert text == "def function():\n# Comment\n ", repr(text)
+
+
+# ---- Tabs tests
+def test_indentation_with_tabs():
+ text_input_expected_comment = [
+ ("this_tuple = (1, 2)\n", "this_tuple = (1, 2)\n", "simple tuple"),
+ ("\ndef function():\n", "\ndef function():\n\t", "def with new line"),
+ ("def function():\n\t# Comment\n", "def function():\n\t# Comment\n\t",
+ "test with indented comment"),
+ ("def function():\n\tprint []\n", "def function():\n\tprint []\n\t",
+ "test brackets alone"),
+ ("\nsome_long_name = {\n", "\nsome_long_name = {\n\t\t",
+ "indentation after opening bracket"),
+ ("def function():\n", "def function():\n\t", "test simple def"),
+ ("open_parenthesis(\n", "open_parenthesis(\n\t\t",
+ "open parenthesis"),
+ ("tags = ['(a)', '(b)', '(c)']\n", "tags = ['(a)', '(b)', '(c)']\n",
+ "test_commented_brackets"),
+ ("s = a[(a['a'] == l) & (a['a'] == 1)]['a']\n",
+ "s = a[(a['a'] == l) & (a['a'] == 1)]['a']\n",
+ "test_balanced_brackets"),
+ ("def some_func():\n\treturn 10\n", "def some_func():\n\treturn 10\n",
+ "test_return"),
+ ("def some_func():\n\treturns = 10\n",
+ "def some_func():\n\treturns = 10\n\t",
+ "test_return_not_keyword"),
+ ("def function():\n# Comment\n", "def function():\n# Comment\n\t",
+ "test_def_with_unindented_comment")
+ ]
+
+ for text_input, expected, comment in text_input_expected_comment:
+ for tab_stop_width_spaces in [1, 2, 3, 4, 5, 6, 7, 8]:
+ text = get_indent_fix(text_input, indent_chars="\t",
+ tab_stop_width_spaces=tab_stop_width_spaces)
+ assert text == expected, comment
+
+
+def test_indentation_with_tabs_parenthesis():
+ """Simple parenthesis indentation test with different tab stop widths."""
+ text_input_expected_tab = [
+ ("print(\n)", "print(\n\t\t)", 1),
+ ("print(\n)", "print(\n\t\t)", 2),
+ ("print(\n)", "print(\n\t\t)", 3),
+ ("print(\n)", "print(\n\t )", 4),
+ ("print(\n)", "print(\n\t )", 5),
+ ("print(\n)", "print(\n\t)", 6),
+ ("print(\n)", "print(\n )", 7),
+ ("print(\n)", "print(\n )", 8),
+ ("a = (a # some comment\n", "a = (a # some comment\n\t ", 4)
+ ]
+ for text_input, expected, tab_stop_width_spaces in text_input_expected_tab:
+ text = get_indent_fix(text_input, indent_chars="\t",
+ tab_stop_width_spaces=tab_stop_width_spaces)
+ assert text == expected, tab_stop_width_spaces
+
+
+def test_unindentation_with_tabs():
+ text_input = "\tx = 1"
+ expected_text = "x = 1"
+ for tab_stop_width_spaces in [1, 2, 3, 4, 5, 6, 7, 8]:
+ text = get_indent_fix(text_input, indent_chars="\t",
+ tab_stop_width_spaces=tab_stop_width_spaces,
+ forward=False)
+ assert text == expected_text
+
+
+# ---- Simple indentation tests
+def test_simple_indentation():
+ # language None deactivate smart indentation
+ text_input_expected_comment = [
+ ("hola\n", "hola\n", "witout indentation"),
+ (" hola\n", " hola\n ", "some indentation"),
+ ("\thola\n", "\thola\n\t", "tab indentation"),
+ (" hola(\n", " hola(\n ", "line with parenthesis")
+ ]
+ for text_input, text_expected, comment in text_input_expected_comment:
+ text = get_indent_fix(text_input, language=None)
+ assert text == text_expected, comment
+
+
+if __name__ == "__main__":
+ pytest.main()
diff --git a/spyder/plugins/editor/widgets/tests/test_autosaveerror.py b/spyder/plugins/editor/widgets/tests/test_autosaveerror.py
new file mode 100644
index 00000000000..fa58fb19146
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/test_autosaveerror.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+"""Tests for autosaveerror.py"""
+
+# Third party imports
+from qtpy.QtWidgets import QPushButton
+
+# Local imports
+from spyder.plugins.editor.widgets.autosaveerror import AutosaveErrorDialog
+
+
+def test_autosave_error_message_box(qtbot, mocker):
+ """Test that AutosaveErrorDialog exec's at first, but that after the
+ 'do not show anymore' checkbox is clicked, it does not exec anymore."""
+ mock_exec = mocker.patch.object(AutosaveErrorDialog, 'exec_')
+ box = AutosaveErrorDialog('action', 'error')
+ box.exec_if_enabled()
+ assert mock_exec.call_count == 1
+ box.dismiss_box.click()
+ ok_button = box.findChild(QPushButton)
+ ok_button.click()
+ box2 = AutosaveErrorDialog('action', 'error')
+ box2.exec_if_enabled()
+ assert mock_exec.call_count == 1
diff --git a/spyder/plugins/editor/widgets/tests/test_bookmarks.py b/spyder/plugins/editor/widgets/tests/test_bookmarks.py
new file mode 100644
index 00000000000..efbde4e3456
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/test_bookmarks.py
@@ -0,0 +1,225 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+Tests for bookmarks.
+"""
+
+# Stdlib imports
+try:
+ from unittest.mock import Mock
+except ImportError:
+ from mock import Mock # Python 2
+
+# Third party imports
+import pytest
+from qtpy.QtGui import QTextCursor
+
+# Local imports
+import spyder.plugins.editor.widgets.codeeditor as codeeditor
+
+
+# -----------------------------------------------------------------------------
+# --- Helper functions
+# -----------------------------------------------------------------------------
+def reset_emits(editor):
+ """Reset signal mocks."""
+ editor.sig_bookmarks_changed.reset_mock()
+
+
+def editor_assert_helper(editor, block=None, bm=None, emits=True):
+ """
+ Run the tests for call to add_remove_breakpoint.
+
+ Args:
+ editor (CodeEditor): CodeEditor instance.
+ block (QTextBlock): Block of text.
+ bm (list): A list containing slots and columns of bookmarks
+ emits (bool): Boolean to test if signals were emitted?
+ """
+ data = block.userData()
+ assert data.bookmarks == bm
+ if emits:
+ editor.sig_bookmarks_changed.emit.assert_called_with()
+ else:
+ editor.sig_bookmarks_changed.emit.assert_not_called()
+
+
+# -----------------------------------------------------------------------------
+# --- Fixtures
+# -----------------------------------------------------------------------------
+@pytest.fixture
+def code_editor_bookmarks(qtbot):
+ """Create code editor with default Python code."""
+ editor = codeeditor.CodeEditor(parent=None)
+ indent_chars = ' ' * 4
+ tab_stop_width_spaces = 4
+ editor.setup_editor(language='Python', indent_chars=indent_chars,
+ tab_stop_width_spaces=tab_stop_width_spaces)
+ # Mock the signal emit to test when it's been called.
+ editor.sig_bookmarks_changed = Mock()
+ text = ('def f1(a, b):\n'
+ '"Double quote string."\n'
+ '\n' # Blank line.
+ ' c = a * b\n'
+ ' return c\n'
+ )
+ editor.set_text(text)
+ return editor, qtbot
+
+
+# -----------------------------------------------------------------------------
+# --- Tests
+# -----------------------------------------------------------------------------
+def test_add_bookmark(code_editor_bookmarks):
+ """Test CodeEditor.add_bookmark. Adds bookmark data to Textblock."""
+ editor, __ = code_editor_bookmarks
+
+ editor.go_to_line(1)
+ block = editor.textCursor().block()
+
+ # Test with default call to slot 1 on text line containing code.
+ reset_emits(editor)
+ editor.add_bookmark(1)
+ editor_assert_helper(editor, block, bm=[(1, 0)], emits=True)
+
+ # Test on indented line and add multiple bookmarks.
+ reset_emits(editor)
+ editor.go_to_line(4)
+ block = editor.textCursor().block()
+ editor.add_bookmark(1)
+ cursor = editor.textCursor()
+ cursor.movePosition(QTextCursor.Right, n=2)
+ editor.setTextCursor(cursor)
+ editor.add_bookmark(2)
+ editor_assert_helper(editor, block, bm=[(1, 0), (2, 2)], emits=True)
+
+
+def test_get_bookmarks(code_editor_bookmarks):
+ """Test CodeEditor.get_bookmarks. Returns data found in textblocks."""
+ editor, __ = code_editor_bookmarks
+ gb = editor.get_bookmarks
+
+ assert(gb() == {})
+
+ # Add bookmarks.
+ bm = {1: ('filename', 1, 0), 2: ('filename', 3, 5), 3: ('filename', 4, 3)}
+ editor.set_bookmarks(bm)
+ assert(gb() == {1: [1, 0], 2: [3, 5], 3: [4, 3]})
+
+
+def test_clear_bookmarks(code_editor_bookmarks):
+ """Test CodeEditor.clear_bookmarks. Remove bookmarks from all blocks."""
+ editor, __ = code_editor_bookmarks
+
+ assert len(list(editor.blockuserdata_list())) == 1
+
+ bm = {1: ('filename', 1, 0), 2: ('filename', 3, 5)}
+ editor.set_bookmarks(bm)
+ assert editor.get_bookmarks() == {1: [1, 0], 2: [3, 5]}
+ assert len(list(editor.blockuserdata_list())) == 3
+
+ editor.clear_bookmarks()
+ assert editor.get_bookmarks() == {}
+ # Even though there is a 'del data' that would pop the item from the
+ # list, the __del__ funcion isn't called.
+ assert len(list(editor.blockuserdata_list())) == 3
+ for data in editor.blockuserdata_list():
+ assert not data.bookmarks
+
+
+def test_update_bookmarks(code_editor_bookmarks):
+ """Test CodeEditor.update_bookmarks. Check if signal is emitted."""
+ editor, __ = code_editor_bookmarks
+ reset_emits(editor)
+ editor.sig_bookmarks_changed.emit.assert_not_called()
+ # update_bookmarks is the slot for the blockCountChanged signal.
+ editor.textCursor().insertBlock()
+ editor.sig_bookmarks_changed.emit.assert_called_with()
+
+
+def test_save_bookmark(editor_plugin_open_files):
+ """
+ Test Plugin.save_bookmark.
+
+ Test saving of bookmarks by looking at data in blocks. Reassignment
+ should remove data from old block and put it in new.
+ """
+ editor, _, _ = editor_plugin_open_files(None, None)
+
+ # Get current editorstack, active editor and cursor
+ editorstack = editor.get_current_editorstack()
+ edtr = editorstack.get_current_editor()
+ cursor = edtr.textCursor()
+
+ # Basic functionality: save a bookmark and check if it's there
+ editor.save_bookmark(1)
+ bookmarks = edtr.document().findBlockByNumber(0).userData().bookmarks
+ assert bookmarks == [(1, 0)]
+
+ # Move the cursor and reset the same bookmark
+ cursor.movePosition(QTextCursor.Down, n=1)
+ cursor.movePosition(QTextCursor.Right, n=2)
+ edtr.setTextCursor(cursor)
+ editor.save_bookmark(1)
+
+ # Check if bookmark is there
+ bookmarks = edtr.document().findBlockByNumber(1).userData().bookmarks
+ assert bookmarks == [(1, 2)]
+
+ # Check if bookmark was removed from previous block
+ bookmarks = edtr.document().findBlockByNumber(0).userData().bookmarks
+ assert bookmarks == []
+
+
+def test_load_bookmark(editor_plugin_open_files):
+ """
+ Test that loading a bookmark works.
+
+ Check this by saving and loading bookmarks and checking for cursor
+ position. Also over multiple files.
+ """
+ editor, _, _ = editor_plugin_open_files(None, None)
+
+ # Get current editorstack, active editor and cursor
+ editorstack = editor.get_current_editorstack()
+ edtr = editorstack.get_current_editor()
+ cursor = edtr.textCursor()
+
+ # Basic functionality: save and load a bookmark and
+ # check if the cursor is there.
+ editor.save_bookmark(1)
+ cursor.movePosition(QTextCursor.Down, n=1)
+ cursor.movePosition(QTextCursor.Right, n=4)
+ edtr.setTextCursor(cursor)
+
+ assert edtr.get_cursor_line_column() != (0, 0)
+
+ editor.load_bookmark(1)
+
+ assert edtr.get_cursor_line_column() == (0, 0)
+
+ # Move cursor to end of line and remove characters
+ cursor.movePosition(QTextCursor.Down, n=1)
+ cursor.movePosition(QTextCursor.Right, n=19)
+ edtr.setTextCursor(cursor)
+
+ editor.save_bookmark(2)
+ edtr.stdkey_backspace()
+ edtr.stdkey_backspace()
+ editor.load_bookmark(2)
+
+ assert edtr.get_cursor_line_column() == (1, 18)
+
+ # Check if loading bookmark switches file correctly
+ editor.save_bookmark(2)
+ editorstack.tabs.setCurrentIndex(1)
+ editor.load_bookmark(2)
+ assert editorstack.tabs.currentIndex() == 0
+
+
+if __name__ == "__main__":
+ pytest.main()
diff --git a/spyder/widgets/sourcecode/tests/test_breakpoints.py b/spyder/plugins/editor/widgets/tests/test_breakpoints.py
similarity index 75%
rename from spyder/widgets/sourcecode/tests/test_breakpoints.py
rename to spyder/plugins/editor/widgets/tests/test_breakpoints.py
index 69d3ac422eb..4b54883b33b 100644
--- a/spyder/widgets/sourcecode/tests/test_breakpoints.py
+++ b/spyder/plugins/editor/widgets/tests/test_breakpoints.py
@@ -20,17 +20,17 @@
# Local imports
from spyder import version_info
from spyder.py3compat import to_text_string
-import spyder.widgets.sourcecode.codeeditor as codeeditor
+import spyder.plugins.editor.widgets.codeeditor as codeeditor
+from spyder.plugins.editor.utils import debugger
# --- Helper methods
# -----------------------------------------------------------------------------
def reset_emits(editor):
"Reset signal mocks."
- editor.linenumberarea.reset_mock()
if version_info > (4, ):
editor.sig_flags_changed.reset_mock()
- editor.breakpoints_changed.reset_mock()
+ editor.sig_breakpoints_changed.reset_mock()
def editor_assert_helper(editor, block=None, bp=False, bpc=None, emits=True):
@@ -47,15 +47,13 @@ def editor_assert_helper(editor, block=None, bp=False, bpc=None, emits=True):
assert data.breakpoint == bp
assert data.breakpoint_condition == bpc
if emits:
- editor.linenumberarea.update.assert_called_with()
if version_info > (4, ):
editor.sig_flags_changed.emit.assert_called_with()
- editor.breakpoints_changed.emit.assert_called_with()
+ editor.sig_breakpoints_changed.emit.assert_called_with()
else:
- editor.linenumberarea.update.assert_not_called()
if version_info > (4, ):
editor.sig_flags_changed.emit.assert_not_called()
- editor.breakpoints_changed.emit.assert_not_called()
+ editor.sig_breakpoints_changed.emit.assert_not_called()
# --- Fixtures
@@ -70,12 +68,11 @@ def code_editor_bot(qtbot):
tab_stop_width_spaces=tab_stop_width_spaces)
# Mock the screen updates and signal emits to test when they've been
# called.
- editor.linenumberarea = Mock()
if version_info > (4, ):
editor.sig_flags_changed = Mock()
else:
editor.get_linenumberarea_width = Mock(return_value=1)
- editor.breakpoints_changed = Mock()
+ editor.sig_breakpoints_changed = Mock()
text = ('def f1(a, b):\n'
'"Double quote string."\n'
'\n' # Blank line.
@@ -91,9 +88,9 @@ def code_editor_bot(qtbot):
def test_add_remove_breakpoint(code_editor_bot, mocker):
"""Test CodeEditor.add_remove_breakpoint()."""
editor, qtbot = code_editor_bot
- arb = editor.add_remove_breakpoint
+ arb = editor.debugger.toogle_breakpoint
- mocker.patch.object(codeeditor.QInputDialog, 'getText')
+ mocker.patch.object(debugger.QInputDialog, 'getText')
editor.go_to_line(1)
block = editor.textCursor().block()
@@ -103,11 +100,9 @@ def test_add_remove_breakpoint(code_editor_bot, mocker):
reset_emits(editor)
arb()
assert block # Block exists.
- assert not block.userData() # But user data not added to it.
- editor.linenumberarea.update.assert_not_called()
if version_info > (4, ):
editor.sig_flags_changed.emit.assert_not_called()
- editor.breakpoints_changed.emit.assert_not_called()
+ editor.sig_breakpoints_changed.emit.assert_not_called()
# Reset language.
editor.set_language('Python')
@@ -137,13 +132,13 @@ def test_add_remove_breakpoint(code_editor_bot, mocker):
# Call already set breakpoint with edit condition.
reset_emits(editor)
- codeeditor.QInputDialog.getText.return_value = ('a == 42', False)
+ debugger.QInputDialog.getText.return_value = ('a == 42', False)
arb(line_number=4, edit_condition=True)
# Condition not changed because edit was cancelled.
editor_assert_helper(editor, block, bp=True, bpc='a > 50', emits=False)
# Condition changed.
- codeeditor.QInputDialog.getText.return_value = ('a == 42', True) # OK.
+ debugger.QInputDialog.getText.return_value = ('a == 42', True) # OK.
reset_emits(editor)
arb(line_number=4, edit_condition=True)
editor_assert_helper(editor, block, bp=True, bpc='a == 42', emits=True)
@@ -154,8 +149,8 @@ def test_add_remove_breakpoint_with_edit_condition(code_editor_bot, mocker):
# For issue 2179.
editor, qtbot = code_editor_bot
- arb = editor.add_remove_breakpoint
- mocker.patch.object(codeeditor.QInputDialog, 'getText')
+ arb = editor.debugger.toogle_breakpoint
+ mocker.patch.object(debugger.QInputDialog, 'getText')
linenumber = 5
block = editor.document().findBlockByLineNumber(linenumber - 1)
@@ -164,25 +159,24 @@ def test_add_remove_breakpoint_with_edit_condition(code_editor_bot, mocker):
# Once a line has a breakpoint set, it remains in userData(), which results
# in a different behavior when calling the dialog box (tested below).
reset_emits(editor)
- codeeditor.QInputDialog.getText.return_value = ('b == 1', False)
+ debugger.QInputDialog.getText.return_value = ('b == 1', False)
arb(line_number=linenumber, edit_condition=True)
data = block.userData()
assert not data # Data isn't saved in this case.
- # Confirm line number area, scrollflag, and breakpoints not called.
- editor.linenumberarea.update.assert_not_called()
+ # Confirm scrollflag, and breakpoints not called.
if version_info > (4, ):
editor.sig_flags_changed.emit.assert_not_called()
- editor.breakpoints_changed.emit.assert_not_called()
+ editor.sig_breakpoints_changed.emit.assert_not_called()
# Call as if 'OK' button pressed.
reset_emits(editor)
- codeeditor.QInputDialog.getText.return_value = ('b == 1', True)
+ debugger.QInputDialog.getText.return_value = ('b == 1', True)
arb(line_number=linenumber, edit_condition=True)
editor_assert_helper(editor, block, bp=True, bpc='b == 1', emits=True)
# Call again with dialog cancelled - breakpoint is already active.
reset_emits(editor)
- codeeditor.QInputDialog.getText.return_value = ('b == 9', False)
+ debugger.QInputDialog.getText.return_value = ('b == 9', False)
arb(line_number=linenumber, edit_condition=True)
# Breakpoint stays active, but signals aren't emitted.
editor_assert_helper(editor, block, bp=True, bpc='b == 1', emits=False)
@@ -194,7 +188,7 @@ def test_add_remove_breakpoint_with_edit_condition(code_editor_bot, mocker):
# Call again with dialog cancelled.
reset_emits(editor)
- codeeditor.QInputDialog.getText.return_value = ('b == 9', False)
+ debugger.QInputDialog.getText.return_value = ('b == 9', False)
arb(line_number=linenumber, edit_condition=True)
editor_assert_helper(editor, block, bp=False, bpc=None, emits=False)
@@ -202,14 +196,14 @@ def test_add_remove_breakpoint_with_edit_condition(code_editor_bot, mocker):
def test_get_breakpoints(code_editor_bot):
"""Test CodeEditor.get_breakpoints."""
editor, qtbot = code_editor_bot
- arb = editor.add_remove_breakpoint
- gb = editor.get_breakpoints
+ arb = editor.debugger.toogle_breakpoint
+ gb = editor.debugger.get_breakpoints
assert(gb() == [])
# Add breakpoints.
bp = [(1, None), (3, None), (4, 'a > 1'), (5, 'c == 10')]
- editor.set_breakpoints(bp)
+ editor.debugger.set_breakpoints(bp)
assert(gb() == [(1, None), (4, 'a > 1'), (5, 'c == 10')])
# Only includes active breakpoints. Calling add_remove turns the
@@ -223,19 +217,19 @@ def test_clear_breakpoints(code_editor_bot):
"""Test CodeEditor.clear_breakpoints."""
editor, qtbot = code_editor_bot
- assert len(editor.blockuserdata_list) == 0
+ assert len(list(editor.blockuserdata_list())) == 1
bp = [(1, None), (4, None)]
- editor.set_breakpoints(bp)
- assert editor.get_breakpoints() == bp
- assert len(editor.blockuserdata_list) == 2
+ editor.debugger.set_breakpoints(bp)
+ assert editor.debugger.get_breakpoints() == bp
+ assert len(list(editor.blockuserdata_list())) == 2
- editor.clear_breakpoints()
- assert editor.get_breakpoints() == []
+ editor.debugger.clear_breakpoints()
+ assert editor.debugger.get_breakpoints() == []
# Even though there is a 'del data' that would pop the item from the
# list, the __del__ funcion isn't called.
- assert len(editor.blockuserdata_list) == 2
- for data in editor.blockuserdata_list:
+ assert len(list(editor.blockuserdata_list())) == 2
+ for data in editor.blockuserdata_list():
assert not data.breakpoint
@@ -243,28 +237,28 @@ def test_set_breakpoints(code_editor_bot):
"""Test CodeEditor.set_breakpoints."""
editor, qtbot = code_editor_bot
- editor.set_breakpoints([])
- assert editor.get_breakpoints() == []
+ editor.debugger.set_breakpoints([])
+ assert editor.debugger.get_breakpoints() == []
bp = [(1, 'a > b'), (4, None)]
- editor.set_breakpoints(bp)
- assert editor.get_breakpoints() == bp
- assert editor.blockuserdata_list[0].breakpoint
+ editor.debugger.set_breakpoints(bp)
+ assert editor.debugger.get_breakpoints() == bp
+ assert list(editor.blockuserdata_list())[0].breakpoint
bp = [(1, None), (5, 'c == 50')]
- editor.set_breakpoints(bp)
- assert editor.get_breakpoints() == bp
- assert editor.blockuserdata_list[0].breakpoint
+ editor.debugger.set_breakpoints(bp)
+ assert editor.debugger.get_breakpoints() == bp
+ assert list(editor.blockuserdata_list())[0].breakpoint
def test_update_breakpoints(code_editor_bot):
"""Test CodeEditor.update_breakpoints."""
editor, qtbot = code_editor_bot
reset_emits(editor)
- editor.breakpoints_changed.emit.assert_not_called()
+ editor.sig_breakpoints_changed.emit.assert_not_called()
# update_breakpoints is the slot for the blockCountChanged signal.
editor.textCursor().insertBlock()
- editor.breakpoints_changed.emit.assert_called_with()
+ editor.sig_breakpoints_changed.emit.assert_called_with()
if __name__ == "__main__":
diff --git a/spyder/plugins/editor/widgets/tests/test_codeeditor.py b/spyder/plugins/editor/widgets/tests/test_codeeditor.py
new file mode 100644
index 00000000000..e7a33d7669c
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/test_codeeditor.py
@@ -0,0 +1,207 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+
+# Third party imports
+from qtpy.QtCore import Qt, QEvent
+from qtpy.QtGui import QFont, QTextCursor, QMouseEvent
+from pytestqt import qtbot
+import pytest
+
+# Local imports
+from spyder.plugins.editor.widgets.editor import codeeditor
+from spyder.py3compat import PY3
+
+
+# --- Fixtures
+# -----------------------------------------------------------------------------
+@pytest.fixture
+def editorbot(qtbot):
+ widget = codeeditor.CodeEditor(None)
+ widget.setup_editor(linenumbers=True, markers=True, tab_mode=False,
+ font=QFont("Courier New", 10),
+ show_blanks=True, color_scheme='Zenburn',
+ scroll_past_end=True)
+ widget.setup_editor(language='Python')
+ qtbot.addWidget(widget)
+ widget.show()
+ return qtbot, widget
+
+# --- Tests
+# -----------------------------------------------------------------------------
+# testing lowercase transformation functionality
+
+def test_editor_upper_to_lower(editorbot):
+ qtbot, widget = editorbot
+ text = 'UPPERCASE'
+ widget.set_text(text)
+ cursor = widget.textCursor()
+ cursor.movePosition(QTextCursor.NextCharacter,
+ QTextCursor.KeepAnchor)
+ widget.setTextCursor(cursor)
+ widget.transform_to_lowercase()
+ new_text = widget.get_text('sof', 'eof')
+ assert text != new_text
+
+
+def test_editor_lower_to_upper(editorbot):
+ qtbot, widget = editorbot
+ text = 'uppercase'
+ widget.set_text(text)
+ cursor = widget.textCursor()
+ cursor.movePosition(QTextCursor.NextCharacter,
+ QTextCursor.KeepAnchor)
+ widget.setTextCursor(cursor)
+ widget.transform_to_uppercase()
+ new_text = widget.get_text('sof', 'eof')
+ assert text != new_text
+
+
+@pytest.mark.skipif(PY3, reason='Test only makes sense on Python 2.')
+def test_editor_log_lsp_handle_errors(editorbot, capsys):
+ """Test the lsp error handling / dialog report Python 2."""
+ qtbot, widget = editorbot
+ params = {
+ 'params': {
+ 'activeParameter': 'boo',
+ 'signatures': {
+ 'documentation': b'\x81',
+ 'label': 'foo',
+ 'parameters': {
+ 'boo': {
+ 'documentation': b'\x81',
+ 'label': 'foo',
+ },
+ }
+ }
+ }
+ }
+
+ widget.process_signatures(params)
+ captured = capsys.readouterr()
+ test_1 = "Error when processing signature" in captured.err
+ test_2 = "codec can't decode byte 0x81" in captured.err
+ assert test_1 or test_2
+
+
+@pytest.mark.parametrize(
+ "input_text, expected_text, keys, strip_all",
+ [
+ ("for i in range(2): ",
+ "for i in range(2): \n\n \n ",
+ [Qt.Key_Enter, Qt.Key_Enter, ' ', Qt.Key_Enter],
+ False),
+ ('for i in range(2): ',
+ 'for i in range(2):\n\n ',
+ [Qt.Key_Enter, Qt.Key_Enter],
+ True),
+ ('myvar = 2 ',
+ 'myvar = 2\n',
+ [Qt.Key_Enter],
+ True),
+ ('somecode = 1\nmyvar = 2 \nmyvar = 3',
+ 'somecode = 1\nmyvar = 2 \nmyvar = 3',
+ [' ', Qt.Key_Up, Qt.Key_Up],
+ True),
+ ('somecode = 1\nmyvar = 2 ',
+ 'somecode = 1\nmyvar = 2 ',
+ [Qt.Key_Left],
+ True),
+ ('"""This is a string with important spaces\n ',
+ '"""This is a string with important spaces\n \n',
+ [Qt.Key_Enter],
+ True),
+ ('"""string ',
+ '"""string \n',
+ [Qt.Key_Enter],
+ True),
+ ('somecode = 1\nmyvar = 2',
+ 'somecode = 1\nmyvar = 2',
+ [' ', (Qt.LeftButton, 0)],
+ True),
+ ('somecode = 1\nmyvar = 2',
+ 'somecode = 1\nmyvar = 2 ',
+ [' ', (Qt.LeftButton, 23)],
+ True),
+ ('a=1\na=2 \na=3',
+ 'a=1\na=2 \na=3',
+ [(Qt.LeftButton, 6), Qt.Key_Up],
+ True),
+ ])
+def test_editor_rstrip_keypress(
+ editorbot, input_text, expected_text, keys, strip_all):
+ """
+ Test that whitespace is removed when leaving a line.
+ """
+ qtbot, widget = editorbot
+ widget.strip_trailing_spaces_on_modify = strip_all
+ widget.set_text(input_text)
+ cursor = widget.textCursor()
+ cursor.movePosition(QTextCursor.End)
+ widget.setTextCursor(cursor)
+ for key in keys:
+ if isinstance(key, tuple):
+ # Mouse event
+ button, position = key
+ cursor = widget.textCursor()
+ cursor.setPosition(position)
+ xypos = widget.cursorRect(cursor).center()
+ widget.mousePressEvent(QMouseEvent(
+ QEvent.MouseButtonPress, xypos,
+ button, button,
+ Qt.NoModifier))
+ else:
+ qtbot.keyPress(widget, key)
+ assert widget.toPlainText() == expected_text
+
+
+@pytest.mark.parametrize(
+ "input_text, expected_state", [
+ ("'string ", [True, False]),
+ ('"string ', [True, False]),
+ ("'string \\", [True, True]),
+ ('"string \\', [True, True]),
+ ("'string \\ ", [True, False]),
+ ('"string \\ ', [True, False]),
+ ("'string ' ", [False, False]),
+ ('"string " ', [False, False]),
+ ("'string \"", [True, False]),
+ ('"string \'', [True, False]),
+ ("'string \" ", [True, False]),
+ ('"string \' ', [True, False]),
+ ("'''string ", [True, True]),
+ ('"""string ', [True, True]),
+ ("'''string \\", [True, True]),
+ ('"""string \\', [True, True]),
+ ("'''string \\ ", [True, True]),
+ ('"""string \\ ', [True, True]),
+ ("'''string ''' ", [False, False]),
+ ('"""string """ ', [False, False]),
+ ("'''string \"\"\"", [True, True]),
+ ('"""string \'\'\'', [True, True]),
+ ("'''string \"\"\" ", [True, True]),
+ ('"""string \'\'\' ', [True, True]),
+ ])
+def test_in_string(editorbot, input_text, expected_state):
+ """
+ Test that in_string works correctly.
+ """
+ qtbot, widget = editorbot
+ widget.set_text(input_text + '\n ')
+ cursor = widget.textCursor()
+
+ for blanks_enabled in [True, False]:
+ widget.set_blanks_enabled(blanks_enabled)
+
+ cursor.setPosition(len(input_text))
+ assert cursor.position() == len(input_text)
+ assert widget.in_string(cursor) == expected_state[0]
+
+ cursor.setPosition(len(input_text) + 3)
+ assert widget.in_string(cursor) == expected_state[1]
+
+
+if __name__ == '__main__':
+ pytest.main(['test_codeeditor.py'])
diff --git a/spyder/plugins/editor/widgets/tests/test_codeeditor_1.py b/spyder/plugins/editor/widgets/tests/test_codeeditor_1.py
new file mode 100644
index 00000000000..c2e5ddf1815
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/test_codeeditor_1.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+
+"""
+Tests for codeeditor.py.
+"""
+
+# Standard library imports
+import os.path as osp
+try:
+ from unittest.mock import Mock
+except ImportError:
+ from mock import Mock # Python 2
+
+# Third party imports
+import pytest
+from qtpy.QtGui import QTextCursor
+from qtpy.QtCore import QMimeData, QUrl
+from qtpy.QtWidgets import QApplication
+
+# Local imports
+from spyder import version_info
+import spyder.plugins.editor.widgets.codeeditor as codeeditor
+
+
+@pytest.fixture
+def code_editor_bot(qtbot):
+ """Create code editor with default Python code."""
+ editor = codeeditor.CodeEditor(parent=None)
+ indent_chars = ' ' * 4
+ tab_stop_width_spaces = 4
+ editor.setup_editor(language='Python', indent_chars=indent_chars,
+ tab_stop_width_spaces=tab_stop_width_spaces)
+ # Mock the screen updates and signal emits to test when they've been
+ # called.
+ editor.linenumberarea = Mock()
+ if version_info > (4, ):
+ editor.sig_flags_changed = Mock()
+ else:
+ editor.get_linenumberarea_width = Mock(return_value=1)
+ editor.breakpoints_changed = Mock()
+ return editor, qtbot
+
+
+@pytest.fixture
+def copy_files_clipboard(create_folders_files):
+ """Fixture to copy files/folders into the clipboard"""
+ file_paths = create_folders_files[0]
+ file_content = QMimeData()
+ file_content.setUrls([QUrl.fromLocalFile(fname) for fname in file_paths])
+ cb = QApplication.clipboard()
+ cb.setMimeData(file_content, mode=cb.Clipboard)
+ return file_paths
+
+
+# --- Tests
+# -----------------------------------------------------------------------------
+def test_delete(code_editor_bot, mocker):
+ """Test CodeEditor.delete()."""
+ editor, qtbot = code_editor_bot
+ text = ('def f1(a, b):\n')
+ editor.set_text(text)
+
+ # Move to start and delete next character without selection.
+ cursor = editor.textCursor()
+ cursor.movePosition(QTextCursor.Start)
+ editor.setTextCursor(cursor)
+ editor.delete()
+ assert editor.get_text_line(0) == 'ef f1(a, b):'
+
+ # Delete selection.
+ cursor = editor.textCursor()
+ cursor.select(QTextCursor.WordUnderCursor)
+ editor.setTextCursor(cursor)
+ editor.delete()
+ assert editor.get_text_line(0) == ' f1(a, b):'
+
+ # Move to end of document - nothing to delete after cursor.
+ cursor = editor.textCursor()
+ cursor.movePosition(QTextCursor.End)
+ editor.setTextCursor(cursor)
+ editor.delete()
+ assert editor.get_text_line(0) == ' f1(a, b):'
+
+
+def test_paste_files(code_editor_bot, copy_files_clipboard):
+ """Test pasting files/folders into the editor."""
+ editor = code_editor_bot[0]
+ file_paths = copy_files_clipboard
+ cursor = editor.textCursor()
+ cursor.movePosition(QTextCursor.Start)
+ editor.setTextCursor(cursor)
+ editor.paste()
+ editor.selectAll()
+ text = editor.toPlainText()
+ path_list_in_editor = [path.strip(',"') for path in text.splitlines()]
+ assert len(file_paths) == len(path_list_in_editor)
+ for path, expected_path in zip(path_list_in_editor, file_paths):
+ assert osp.normpath(path) == osp.normpath(expected_path)
+
+
+@pytest.mark.parametrize('line_ending_char', ['\n', '\r\n', '\r'])
+@pytest.mark.parametrize('text', ['def fun(a, b):\n\treturn a + b',
+ 'https://www.spyder-ide.org'])
+def test_paste_text(code_editor_bot, text, line_ending_char):
+ """Test pasting text into the editor."""
+ editor = code_editor_bot[0]
+ text = text.replace(osp.os.linesep, line_ending_char)
+ cb = QApplication.clipboard()
+ cb.setText(text, mode=cb.Clipboard)
+ cursor = editor.textCursor()
+ cursor.movePosition(QTextCursor.Start)
+ editor.setTextCursor(cursor)
+ editor.paste()
+ for line_no, txt in enumerate(text.splitlines()):
+ assert editor.get_text_line(line_no) == txt
+
+
+if __name__ == "__main__":
+ pytest.main()
diff --git a/spyder/widgets/sourcecode/tests/test_comments.py b/spyder/plugins/editor/widgets/tests/test_comments.py
similarity index 98%
rename from spyder/widgets/sourcecode/tests/test_comments.py
rename to spyder/plugins/editor/widgets/tests/test_comments.py
index 499ae0f7c85..7f0684977ff 100644
--- a/spyder/widgets/sourcecode/tests/test_comments.py
+++ b/spyder/plugins/editor/widgets/tests/test_comments.py
@@ -14,7 +14,7 @@
# Local imports
from spyder.py3compat import to_text_string
-from spyder.widgets.sourcecode.codeeditor import CodeEditor
+from spyder.plugins.editor.widgets.codeeditor import CodeEditor
# --- Helper methods
diff --git a/spyder/plugins/editor/widgets/tests/test_editor.py b/spyder/plugins/editor/widgets/tests/test_editor.py
new file mode 100644
index 00000000000..d6db9d22441
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/test_editor.py
@@ -0,0 +1,788 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+
+"""
+Tests for editor.py
+"""
+
+# Standard library imports
+import os
+from sys import platform
+try:
+ from unittest.mock import Mock, MagicMock
+except ImportError:
+ from mock import Mock, MagicMock # Python 2
+
+# Third party imports
+import pytest
+from flaky import flaky
+from qtpy.QtCore import Qt
+from qtpy.QtGui import QTextCursor
+
+# Local imports
+from spyder.config.base import get_conf_path
+from spyder.plugins.editor.widgets.editor import EditorStack
+from spyder.widgets.findreplace import FindReplace
+from spyder.py3compat import PY2
+
+# Qt Test Fixtures
+#--------------------------------
+@pytest.fixture
+def base_editor_bot(qtbot):
+ editor_stack = EditorStack(None, [])
+ editor_stack.set_find_widget(Mock())
+ editor_stack.set_io_actions(Mock(), Mock(), Mock(), Mock())
+ return editor_stack
+
+
+@pytest.fixture
+def editor_bot(base_editor_bot, qtbot):
+ """
+ Set up EditorStack with CodeEditor containing some Python code.
+ The cursor is at the empty line below the code.
+ Returns tuple with EditorStack and CodeEditor.
+ """
+ editor_stack = base_editor_bot
+ text = ('a = 1\n'
+ 'print(a)\n'
+ '\n'
+ 'x = 2') # a newline is added at end
+ finfo = editor_stack.new('foo.py', 'utf-8', text)
+ finfo.newly_created = False
+ qtbot.addWidget(editor_stack)
+ return editor_stack, finfo.editor
+
+
+@pytest.fixture
+def editor_multifile_bot(base_editor_bot, qtbot):
+ """
+ Like `editor_bot`, but open multiple files with procedural content.
+ """
+ editor_stack = base_editor_bot
+ finfo_list = []
+ for idx in range(3):
+ text = ('sample_var_{idx} = 1 + {idx}\n'
+ 'print(sample_var_{idx})\n'
+ '\n'
+ 'x = {idx}').format(idx=idx)
+ finfo = editor_stack.new('spam_{idx}.py'.format(idx=idx),
+ 'utf-8', text)
+ finfo.newly_created = False
+ finfo_list.append(finfo)
+ qtbot.addWidget(editor_stack)
+ return editor_stack, finfo_list
+
+
+@pytest.fixture
+def editor_find_replace_bot(base_editor_bot, qtbot):
+ editor_stack = base_editor_bot
+ text = ('spam bacon\n'
+ 'spam sausage\n'
+ 'spam egg')
+ finfo = editor_stack.new('spam.py', 'utf-8', text)
+ find_replace = FindReplace(None, enable_replace=True)
+ editor_stack.set_find_widget(find_replace)
+ find_replace.set_editor(finfo.editor)
+ qtbot.addWidget(editor_stack)
+ qtbot.addWidget(find_replace)
+ return editor_stack, finfo.editor, find_replace
+
+
+@pytest.fixture
+def editor_cells_bot(base_editor_bot, qtbot):
+ editor_stack = base_editor_bot
+ text = ('# %%\n'
+ '# 1 cell\n'
+ '# print(1)\n'
+ '# %%\n'
+ '# 2 cell\n'
+ '# print(2)\n'
+ '# %%\n'
+ '# 3 cell\n'
+ '# print(3)\n')
+ finfo = editor_stack.new('cells.py', 'utf-8', text)
+ find_replace = FindReplace(None, enable_replace=True)
+ qtbot.addWidget(editor_stack)
+ return editor_stack, finfo.editor
+
+
+@pytest.fixture
+def editor_folding_bot(base_editor_bot, qtbot):
+ """
+ Setup CodeEditor with some text useful for folding related tests.
+ """
+ editor_stack = base_editor_bot
+ text = ('# dummy test file\n'
+ 'class a():\n' # fold-block level-0
+ ' self.b = 1\n'
+ ' print(self.b)\n'
+ ' \n'
+ )
+ finfo = editor_stack.new('foo.py', 'utf-8', text)
+
+ find_replace = FindReplace(None, enable_replace=True)
+ editor_stack.set_find_widget(find_replace)
+ find_replace.set_editor(finfo.editor)
+ qtbot.addWidget(editor_stack)
+ qtbot.addWidget(find_replace)
+ return editor_stack, finfo.editor, find_replace
+
+
+# Tests
+#-------------------------------
+def test_find_number_matches(setup_editor):
+ """Test for number matches in find/replace."""
+ editor_stack, editor = setup_editor
+ editor_stack.find_widget.case_button.setChecked(True)
+ text = ' test \nTEST \nTest \ntesT '
+ editor.set_text(text)
+
+ editor_stack.find_widget.search_text.add_text('test')
+ editor_stack.find_widget.find(changed=False, forward=True,
+ rehighlight=False,
+ multiline_replace_check=False)
+ editor_text = editor_stack.find_widget.number_matches_text.text()
+ assert editor_text == '1 of 1'
+
+ editor_stack.find_widget.search_text.add_text('fail')
+ editor_stack.find_widget.find(changed=False, forward=True,
+ rehighlight=False,
+ multiline_replace_check=False)
+ editor_text = editor_stack.find_widget.number_matches_text.text()
+ assert editor_text == 'no matches'
+
+
+def test_move_current_line_up(editor_bot):
+ editor_stack, editor = editor_bot
+
+ # Move second line up when nothing is selected.
+ editor.go_to_line(2)
+ editor.move_line_up()
+ expected_new_text = ('print(a)\n'
+ 'a = 1\n'
+ '\n'
+ 'x = 2\n')
+ assert editor.toPlainText() == expected_new_text
+
+ # Move line up when already at the top.
+ editor.move_line_up()
+ assert editor.toPlainText() == expected_new_text
+
+ # Move fourth line up when part of the line is selected.
+ editor.go_to_line(4)
+ editor.moveCursor(QTextCursor.Right, QTextCursor.MoveAnchor)
+ for i in range(2):
+ editor.moveCursor(QTextCursor.Right, QTextCursor.KeepAnchor)
+ editor.move_line_up()
+ expected_new_text = ('print(a)\n'
+ 'a = 1\n'
+ 'x = 2\n'
+ '\n')
+ assert editor.toPlainText()[:] == expected_new_text
+
+
+def test_move_current_line_down(editor_bot):
+ editor_stack, editor = editor_bot
+
+ # Move fourth line down when nothing is selected.
+ editor.go_to_line(4)
+ editor.move_line_down()
+ expected_new_text = ('a = 1\n'
+ 'print(a)\n'
+ '\n'
+ '\n'
+ 'x = 2')
+ assert editor.toPlainText() == expected_new_text
+
+ # Move line down when already at the bottom.
+ editor.move_line_down()
+ assert editor.toPlainText() == expected_new_text
+
+ # Move first line down when part of the line is selected.
+ editor.go_to_line(1)
+ editor.moveCursor(QTextCursor.Right, QTextCursor.MoveAnchor)
+ for i in range(2):
+ editor.moveCursor(QTextCursor.Right, QTextCursor.KeepAnchor)
+ editor.move_line_down()
+ expected_new_text = ('print(a)\n'
+ 'a = 1\n'
+ '\n'
+ '\n'
+ 'x = 2')
+ assert editor.toPlainText() == expected_new_text
+
+
+def test_move_multiple_lines_up(editor_bot):
+ editor_stack, editor = editor_bot
+
+ # Move second and third lines up.
+ editor.go_to_line(2)
+ cursor = editor.textCursor()
+ cursor.movePosition(QTextCursor.Down, QTextCursor.KeepAnchor)
+ cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor)
+ editor.setTextCursor(cursor)
+ editor.move_line_up()
+
+ expected_new_text = ('print(a)\n'
+ '\n'
+ 'a = 1\n'
+ 'x = 2\n')
+ assert editor.toPlainText() == expected_new_text
+
+ # Move first and second lines up (to test already at top condition).
+ editor.move_line_up()
+ assert editor.toPlainText() == expected_new_text
+
+
+def test_move_multiple_lines_down(editor_bot):
+ editor_stack, editor = editor_bot
+
+ # Move third and fourth lines down.
+ editor.go_to_line(3)
+ cursor = editor.textCursor()
+ cursor.movePosition(QTextCursor.Down, QTextCursor.KeepAnchor)
+ cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor)
+ editor.setTextCursor(cursor)
+ editor.move_line_down()
+
+ expected_new_text = ('a = 1\n'
+ 'print(a)\n'
+ '\n'
+ '\n'
+ 'x = 2')
+ assert editor.toPlainText() == expected_new_text
+
+ # Move fourht and fifth lines down (to test already at bottom condition).
+ editor.move_line_down()
+ assert editor.toPlainText() == expected_new_text
+
+
+def test_run_top_line(editor_bot, qtbot):
+ editor_stack, editor = editor_bot
+ editor.go_to_line(1) # line number is one based
+ editor.move_cursor(3)
+ with qtbot.waitSignal(editor_stack.exec_in_extconsole) as blocker:
+ editor_stack.run_selection()
+ assert blocker.signal_triggered
+ assert blocker.args[0] == 'a = 1'
+ # check cursor moves to start of next line; note line number is zero based
+ assert editor.get_cursor_line_column() == (1, 0)
+
+
+def test_run_last_nonempty_line(editor_bot, qtbot):
+ editor_stack, editor = editor_bot
+ editor.go_to_line(4)
+ with qtbot.waitSignal(editor_stack.exec_in_extconsole) as blocker:
+ editor_stack.run_selection()
+ assert blocker.signal_triggered
+ assert blocker.args[0] == 'x = 2'
+ assert editor.get_cursor_line_column() == (4, 0) # check cursor moves down
+
+
+def test_run_empty_line_in_middle(editor_bot, qtbot):
+ editor_stack, editor = editor_bot
+ editor.go_to_line(3)
+ with qtbot.assertNotEmitted(editor_stack.exec_in_extconsole):
+ editor_stack.run_selection()
+ assert editor.get_cursor_line_column() == (3, 0) # check cursor moves down
+
+
+def test_run_last_line_when_empty(editor_bot, qtbot):
+ editor_stack, editor = editor_bot
+ with qtbot.assertNotEmitted(editor_stack.exec_in_extconsole):
+ editor_stack.run_selection()
+ # check cursor doesn't move
+ assert editor.get_cursor_line_column() == (4, 0)
+
+
+def test_run_last_line_when_nonempty(editor_bot, qtbot):
+ editor_stack, editor = editor_bot
+ editor.stdkey_backspace() # delete empty line at end
+ old_text = editor.toPlainText()
+ with qtbot.waitSignal(editor_stack.exec_in_extconsole) as blocker:
+ editor_stack.run_selection()
+ assert blocker.signal_triggered
+ assert blocker.args[0] == 'x = 2'
+ expected_new_text = old_text + editor.get_line_separator()
+ # check blank line got added
+ assert editor.toPlainText() == expected_new_text
+ assert editor.get_cursor_line_column() == (4, 0) # check cursor moves down
+
+
+def test_find_replace_case_sensitive(setup_editor):
+ editor_stack, editor = setup_editor
+ editor_stack.find_widget.case_button.setChecked(True)
+ text = ' test \nTEST \nTest \ntesT '
+ editor.set_text(text)
+ editor_stack.find_widget.search_text.add_text('test')
+ editor_stack.find_widget.replace_text.add_text('pass')
+ editor_stack.find_widget.replace_find()
+ editor_stack.find_widget.replace_find()
+ editor_stack.find_widget.replace_find()
+ editor_stack.find_widget.replace_find()
+ editor_text = editor.toPlainText()
+ assert editor_text == ' pass \nTEST \nTest \ntesT '
+
+
+def test_replace_current_selected_line(editor_find_replace_bot, qtbot):
+ editor_stack, editor, finder = editor_find_replace_bot
+ expected_new_text = ('ham bacon\n'
+ 'spam sausage\n'
+ 'spam egg')
+ old_text = editor.toPlainText()
+ finder.show()
+ finder.show_replace()
+ qtbot.keyClicks(finder.search_text, 'spam')
+ qtbot.keyClicks(finder.replace_text, 'ham')
+ qtbot.keyPress(finder.replace_text, Qt.Key_Return)
+ assert editor.toPlainText()[0:-1] == expected_new_text
+
+
+def test_replace_enter_press(editor_find_replace_bot, qtbot):
+ """Test advance forward pressing Enter, and backwards with Shift+Enter."""
+ editor_stack, editor, finder = editor_find_replace_bot
+ text = ' \nspam \nspam \nspam '
+ editor.set_text(text)
+ finder.show()
+
+ finder.search_text.add_text('spam')
+
+ # search forward
+ qtbot.keyPress(finder.search_text, Qt.Key_Return)
+ assert editor.get_cursor_line_column() == (1,4)
+
+ qtbot.keyPress(finder.search_text, Qt.Key_Return)
+ assert editor.get_cursor_line_column() == (2,4)
+
+ qtbot.keyPress(finder.search_text, Qt.Key_Return)
+ assert editor.get_cursor_line_column() == (3,4)
+
+ # search backwards
+ qtbot.keyPress(finder.search_text, Qt.Key_Return, modifier=Qt.ShiftModifier)
+ assert editor.get_cursor_line_column() == (2,4)
+
+ qtbot.keyPress(finder.search_text, Qt.Key_Return, modifier=Qt.ShiftModifier)
+ assert editor.get_cursor_line_column() == (1,4)
+
+ qtbot.keyPress(finder.search_text, Qt.Key_Return, modifier=Qt.ShiftModifier)
+ assert editor.get_cursor_line_column() == (3,4)
+
+
+def test_replace_plain_regex(editor_find_replace_bot, qtbot):
+ """Test that regex reserved characters are displayed as plain text."""
+ editor_stack, editor, finder = editor_find_replace_bot
+ expected_new_text = ('.\\[()]*test bacon\n'
+ 'spam sausage\n'
+ 'spam egg')
+ finder.show()
+ finder.show_replace()
+ qtbot.keyClicks(finder.search_text, 'spam')
+ qtbot.keyClicks(finder.replace_text, r'.\[()]*test')
+ qtbot.keyPress(finder.replace_text, Qt.Key_Return)
+ assert editor.toPlainText()[0:-1] == expected_new_text
+
+
+def test_replace_invalid_regex(editor_find_replace_bot, qtbot):
+ """Assert that replacing an invalid regexp does nothing."""
+ editor_stack, editor, finder = editor_find_replace_bot
+ old_text = editor.toPlainText()
+ finder.show()
+ finder.show_replace()
+
+ # Test with invalid search_text and valid replace_text
+ qtbot.keyClicks(finder.search_text, '\\')
+ qtbot.keyClicks(finder.replace_text, 'anything')
+
+ if not finder.re_button.isChecked():
+ qtbot.mouseClick(finder.re_button, Qt.LeftButton)
+
+ qtbot.mouseClick(finder.replace_button, Qt.LeftButton)
+ assert editor.toPlainText() == old_text
+ qtbot.mouseClick(finder.replace_sel_button, Qt.LeftButton)
+ assert editor.toPlainText() == old_text
+ qtbot.mouseClick(finder.replace_all_button, Qt.LeftButton)
+ assert editor.toPlainText() == old_text
+
+ # Test with valid search_text and invalid replace_text
+ qtbot.keyClicks(finder.search_text, 'anything')
+ qtbot.keyClicks(finder.replace_text, '\\')
+
+ qtbot.mouseClick(finder.replace_button, Qt.LeftButton)
+ assert editor.toPlainText() == old_text
+ qtbot.mouseClick(finder.replace_sel_button, Qt.LeftButton)
+ assert editor.toPlainText() == old_text
+ qtbot.mouseClick(finder.replace_all_button, Qt.LeftButton)
+ assert editor.toPlainText() == old_text
+
+
+def test_selection_escape_characters(editor_find_replace_bot, qtbot):
+ editor_stack, editor, finder = editor_find_replace_bot
+ expected_new_text = ('spam bacon\n'
+ 'spam sausage\n'
+ 'spam egg\n'
+ '\\n \\t some escape characters')
+ qtbot.keyClicks(editor, '\\n \\t escape characters')
+
+ finder.show()
+ finder.show_replace()
+ qtbot.keyClicks(finder.search_text, 'escape')
+ qtbot.keyClicks(finder.replace_text, 'some escape')
+
+ # Select last line
+ cursor = editor.textCursor()
+ cursor.select(QTextCursor.LineUnderCursor)
+ assert cursor.selection().toPlainText() == "\\n \\t escape characters"
+
+ #replace
+ finder.replace_find_selection()
+ assert editor.toPlainText() == expected_new_text
+
+
+def test_advance_cell(editor_cells_bot):
+ editor_stack, editor = editor_cells_bot
+
+ # cursor at the end of the file
+ assert editor.get_cursor_line_column() == (10, 0)
+
+ # advance backwards to the begining of the 3rd cell
+ editor_stack.advance_cell(reverse=True)
+ assert editor.get_cursor_line_column() == (6, 0)
+
+ # advance backwards to 2nd cell
+ editor_stack.advance_cell(reverse=True)
+ assert editor.get_cursor_line_column() == (3, 0)
+ # advance backwards to 1st cell
+ editor_stack.advance_cell(reverse=True)
+ assert editor.get_cursor_line_column() == (0, 0)
+
+ # advance to 2nd cell
+ editor_stack.advance_cell()
+ assert editor.get_cursor_line_column() == (3, 0)
+ # advance to 3rd cell
+ editor_stack.advance_cell()
+ assert editor.get_cursor_line_column() == (6, 0)
+
+
+def test_unfold_when_searching(editor_folding_bot, qtbot):
+ editor_stack, editor, finder = editor_folding_bot
+ folding_panel = editor.panels.get('FoldingPanel')
+ line_search = editor.document().findBlockByLineNumber(3)
+
+ # fold region
+ block = editor.document().findBlockByLineNumber(1)
+ folding_panel.toggle_fold_trigger(block)
+ assert not line_search.isVisible()
+
+ # unfolded when searching
+ finder.show()
+ qtbot.keyClicks(finder.search_text, 'print')
+ qtbot.keyPress(finder.search_text, Qt.Key_Return)
+ assert line_search.isVisible()
+
+
+def test_unfold_goto(editor_folding_bot):
+ editor_stack, editor, finder = editor_folding_bot
+ folding_panel = editor.panels.get('FoldingPanel')
+ line_goto = editor.document().findBlockByLineNumber(3)
+
+ # fold region
+ block = editor.document().findBlockByLineNumber(1)
+ folding_panel.toggle_fold_trigger(block)
+ assert not line_goto.isVisible()
+
+ # unfolded when goto
+ editor.go_to_line(4)
+ assert line_goto.isVisible()
+
+
+@pytest.mark.skipif(PY2, reason="Python2 does not support unicode very well")
+def test_get_current_word(base_editor_bot, qtbot):
+ """Test getting selected valid python word."""
+ editor_stack = base_editor_bot
+ text = ('some words with non-ascii characters\n'
+ 'niño\n'
+ 'garçon\n'
+ 'α alpha greek\n'
+ '123valid_python_word')
+ finfo = editor_stack.new('foo.py', 'utf-8', text)
+ qtbot.addWidget(editor_stack)
+ editor = finfo.editor
+ editor.go_to_line(1)
+
+ # Select some
+ editor.moveCursor(QTextCursor.EndOfWord, QTextCursor.KeepAnchor)
+ assert 'some' == editor.textCursor().selectedText()
+ assert editor.get_current_word() == 'some'
+
+ # Select niño
+ editor.go_to_line(2)
+ editor.moveCursor(QTextCursor.EndOfWord, QTextCursor.KeepAnchor)
+ assert 'niño' == editor.textCursor().selectedText()
+ assert editor.get_current_word() == 'niño'
+
+ # Select garçon
+ editor.go_to_line(3)
+ editor.moveCursor(QTextCursor.EndOfWord, QTextCursor.KeepAnchor)
+ assert 'garçon' == editor.textCursor().selectedText()
+ assert editor.get_current_word() == 'garçon'
+
+ # Select α
+ editor.go_to_line(4)
+ editor.moveCursor(QTextCursor.EndOfWord, QTextCursor.KeepAnchor)
+ assert 'α' == editor.textCursor().selectedText()
+ assert editor.get_current_word() == 'α'
+
+ # Select valid_python_word, should search first valid python word
+ editor.go_to_line(5)
+ editor.moveCursor(QTextCursor.EndOfWord, QTextCursor.KeepAnchor)
+ assert '123valid_python_word' == editor.textCursor().selectedText()
+ assert editor.get_current_word() == 'valid_python_word'
+
+
+def test_tab_keypress_properly_caught_find_replace(editor_find_replace_bot, qtbot):
+ """Test that tab works in find/replace dialog. Regression test for #3674.
+ Mock test—more isolated but less flimsy."""
+ editor_stack, editor, finder = editor_find_replace_bot
+ text = ' \nspam \nspam \nspam '
+ editor.set_text(text)
+ finder.show()
+ finder.show_replace()
+
+ finder.focusNextChild = MagicMock(name="focusNextChild")
+ qtbot.keyPress(finder.search_text, Qt.Key_Tab)
+ finder.focusNextChild.assert_called_once_with()
+
+
+@flaky(max_runs=3)
+@pytest.mark.skipif(platform.startswith('linux'), reason="Fails on Linux.")
+def test_tab_moves_focus_from_search_to_replace(editor_find_replace_bot, qtbot):
+ """Test that tab works in find/replace dialog. Regression test for #3674.
+ "Real world" test—more comprehensive but potentially less robust."""
+ editor_stack, editor, finder = editor_find_replace_bot
+ text = ' \nspam \nspam \nspam '
+ editor.set_text(text)
+ finder.show()
+ finder.show_replace()
+
+ qtbot.wait(100)
+ finder.search_text.setFocus()
+ qtbot.wait(100)
+ assert finder.search_text.hasFocus()
+ assert not finder.replace_text.hasFocus()
+ qtbot.keyPress(finder.search_text, Qt.Key_Tab)
+ qtbot.wait(100)
+ assert not finder.search_text.hasFocus()
+ assert finder.replace_text.hasFocus()
+
+
+@flaky(max_runs=3)
+@pytest.mark.skipif(not os.name == 'nt', reason="Fails on Linux and macOS.")
+def test_tab_copies_find_to_replace(editor_find_replace_bot, qtbot):
+ """Check that text in the find box is copied to the replace box on tab
+ keypress. Regression test #4482."""
+ editor_stack, editor, finder = editor_find_replace_bot
+ finder.show()
+ finder.show_replace()
+ finder.search_text.setFocus()
+ finder.search_text.set_current_text('This is some test text!')
+ qtbot.keyClick(finder.search_text, Qt.Key_Tab)
+ qtbot.wait(500)
+ assert finder.replace_text.currentText() == 'This is some test text!'
+
+
+def test_get_autosave_filename(editor_bot):
+ """
+ Test filename returned by `get_autosave_filename`.
+
+ Test a consistent and unique name for the autosave file is returned.
+ """
+ editor_stack, editor = editor_bot
+ autosave = editor_stack.autosave
+ expected = os.path.join(get_conf_path('autosave'), 'foo.py')
+ assert autosave.get_autosave_filename('foo.py') == expected
+ editor_stack.new('ham/foo.py', 'utf-8', '')
+ expected2 = os.path.join(get_conf_path('autosave'), 'foo-1.py')
+ assert autosave.get_autosave_filename('foo.py') == expected
+ assert autosave.get_autosave_filename('ham/foo.py') == expected2
+
+
+def test_autosave_all(editor_bot, mocker):
+ """
+ Test that `autosave_all()` calls autosave() on all open buffers.
+
+ The `editor_bot` fixture is constructed with one open file and the test
+ opens another one with `new()`, so autosave should be called twice.
+ """
+ editor_stack, editor = editor_bot
+ editor_stack.new('ham.py', 'utf-8', '')
+ mocker.patch.object(editor_stack.autosave, 'autosave')
+ editor_stack.autosave.autosave_all()
+ expected_calls = [mocker.call(0), mocker.call(1)]
+ assert editor_stack.autosave.autosave.call_args_list == expected_calls
+
+
+def test_autosave(editor_bot):
+ """Test that autosave() saves text to correct file."""
+ editor_stack, editor = editor_bot
+ editor_stack.autosave.autosave(0)
+ contents = open(os.path.join(get_conf_path('autosave'), 'foo.py')).read()
+ assert contents.startswith('a = 1')
+
+
+def test_autosave_saves_only_if_changed(editor_bot, mocker):
+ """
+ Test that autosave() only saves text if text has changed.
+
+ The `editor_bot` fixture changes the text, so the first call to
+ `autosave()` should indeed autosave. The text is not changed after call #1,
+ so call #2 should not autosave. After call #2 we change the text, so call
+ #3 should again autosave.
+ """
+ editor_stack, editor = editor_bot
+ mocker.patch.object(editor_stack, '_write_to_file')
+ editor_stack.autosave.autosave(0) # call #1, should write
+ assert editor_stack._write_to_file.call_count == 1
+ editor_stack.autosave.autosave(0) # call #2, should not write
+ assert editor_stack._write_to_file.call_count == 1
+ editor.set_text('ham\n')
+ editor_stack.autosave.autosave(0) # call #3, should write
+ assert editor_stack._write_to_file.call_count == 2
+
+
+def test_autosave_does_not_save_new_files(editor_bot, mocker):
+ """Test that autosave() does not save newly created files."""
+ editor_stack, editor = editor_bot
+ editor_stack.data[0].newly_created = True
+ mocker.patch.object(editor_stack, '_write_to_file')
+ editor_stack.autosave.autosave(0)
+ editor_stack._write_to_file.assert_not_called()
+
+
+@pytest.mark.parametrize('filename', ['ham.py', 'ham.txt'])
+def test_autosave_does_not_save_after_open(base_editor_bot, mocker, qtbot,
+ filename):
+ """
+ Test that autosave() does not save files immediately after opening.
+
+ Files should only be autosaved after the user made changes.
+ Editors use different highlighters depending on the filename, so we test
+ both Python and text files. The latter covers issue #8654.
+ """
+ editor_stack = base_editor_bot
+ txt = 'spam\n'
+ editor_stack.create_new_editor(filename, 'ascii', txt, set_current=True)
+ mocker.patch.object(editor_stack, '_write_to_file')
+ qtbot.wait(100) # Wait for PygmentsSH.makeCharlist() if applicable
+ editor_stack.autosave.autosave(0)
+ editor_stack._write_to_file.assert_not_called()
+
+
+def test_autosave_does_not_save_after_reload(base_editor_bot, mocker):
+ """
+ Test that autosave() does not save files immediately after reloading.
+
+ Spyder reload the file if it has changed on disk. In that case, there is
+ no need to autosave because the contents in Spyder are identical to the
+ contents on disk.
+ """
+ editor_stack = base_editor_bot
+ txt = 'spam\n'
+ editor_stack.create_new_editor('ham.py', 'ascii', txt, set_current=True)
+ mocker.patch.object(editor_stack, '_write_to_file')
+ mocker.patch('spyder.plugins.editor.widgets.editor.encoding.read',
+ return_value=(txt, 'ascii'))
+ editor_stack.reload(0)
+ editor_stack.autosave.autosave(0)
+ editor_stack._write_to_file.assert_not_called()
+
+
+def test_autosave_updates_name_mapping(editor_bot, mocker, qtbot):
+ """Test that autosave() updates name_mapping."""
+ editor_stack, editor = editor_bot
+ assert editor_stack.autosave.name_mapping == {}
+ mocker.patch.object(editor_stack, '_write_to_file')
+ with qtbot.wait_signal(editor_stack.sig_option_changed) as blocker:
+ editor_stack.autosave.autosave(0)
+ expected = {'foo.py': os.path.join(get_conf_path('autosave'), 'foo.py')}
+ assert editor_stack.autosave.name_mapping == expected
+ assert blocker.args == ['autosave_mapping', expected]
+
+
+def test_autosave_handles_error(editor_bot, mocker):
+ """Test that autosave() ignores errors when writing to file."""
+ editor_stack, editor = editor_bot
+ mock_write = mocker.patch.object(editor_stack, '_write_to_file')
+ mock_dialog = mocker.patch(
+ 'spyder.plugins.editor.utils.autosave.AutosaveErrorDialog')
+ try:
+ mock_write.side_effect = PermissionError
+ except NameError: # Python 2
+ mock_write.side_effect = IOError
+ editor_stack.autosave.autosave(0)
+ assert mock_dialog.called
+
+
+def test_remove_autosave_file(editor_bot, mocker, qtbot):
+ """
+ Test that remove_autosave_file() removes the autosave file.
+
+ Also, test that it updates `name_mapping`.
+ """
+ editor_stack, editor = editor_bot
+ autosave = editor_stack.autosave
+ with qtbot.wait_signal(editor_stack.sig_option_changed) as blocker:
+ autosave.autosave(0)
+ autosave_filename = os.path.join(get_conf_path('autosave'), 'foo.py')
+ assert os.access(autosave_filename, os.R_OK)
+ expected = {'foo.py': autosave_filename}
+ assert autosave.name_mapping == expected
+ assert blocker.args == ['autosave_mapping', expected]
+ with qtbot.wait_signal(editor_stack.sig_option_changed) as blocker:
+ autosave.remove_autosave_file(editor_stack.data[0].filename)
+ assert not os.access(autosave_filename, os.R_OK)
+ assert autosave.name_mapping == {}
+ assert blocker.args == ['autosave_mapping', {}]
+ with qtbot.assert_not_emitted(editor_stack.sig_option_changed):
+ autosave.autosave(0)
+ assert not os.access(autosave_filename, os.R_OK)
+ assert autosave.name_mapping == {}
+
+
+def test_remove_all_autosave_files(editor_multifile_bot, mocker, qtbot):
+ """
+ Test that remove_all_autosave_files() removes all autosave files.
+
+ Also, test that it updates `name_mapping`.
+ """
+ editor_stack, finfo_list = editor_multifile_bot
+ autosave = editor_stack.autosave
+ autosave_basenames = []
+ autosave_filenames = []
+ expected_mapping = {}
+ with qtbot.wait_signal(editor_stack.sig_option_changed) as blocker:
+ for idx, finfo in enumerate(finfo_list):
+ autosave.autosave(idx)
+ autosave_basenames.append(os.path.basename(finfo.filename))
+ autosave_filenames.append(os.path.join(
+ get_conf_path('autosave'), autosave_basenames[idx]))
+ assert os.access(autosave_filenames[idx], os.R_OK)
+ expected_mapping[autosave_basenames[idx]] = autosave_filenames[idx]
+ assert autosave.name_mapping == expected_mapping
+ assert blocker.args == ['autosave_mapping', expected_mapping]
+ with qtbot.wait_signal(editor_stack.sig_option_changed) as blocker:
+ autosave.remove_all_autosave_files(errors='raise')
+ assert autosave.name_mapping == {}
+ assert blocker.args == ['autosave_mapping', {}]
+ for idx, autosave_filename in enumerate(autosave_filenames):
+ assert not os.access(autosave_filename, os.R_OK)
+ with qtbot.assert_not_emitted(editor_stack.sig_option_changed):
+ autosave.autosave(idx)
+ assert not os.access(autosave_filename, os.R_OK)
+ assert autosave.name_mapping == {}
+
+
+if __name__ == "__main__":
+ pytest.main()
diff --git a/spyder/plugins/editor/widgets/tests/test_editor_and_outline.py b/spyder/plugins/editor/widgets/tests/test_editor_and_outline.py
new file mode 100644
index 00000000000..5a72554a8b2
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/test_editor_and_outline.py
@@ -0,0 +1,238 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+
+"""
+Tests syncing between the EditorStack and OutlineExplorerWidget.
+"""
+
+# Standard library imports
+import os
+import os.path as osp
+import sys
+try:
+ from unittest.mock import Mock
+except ImportError:
+ from mock import Mock # Python 2
+
+# Third party imports
+import pytest
+
+# Local imports
+from spyder.plugins.editor.widgets import editor
+from spyder.plugins.outlineexplorer.widgets import OutlineExplorerWidget
+
+
+# ---- Qt Test Fixtures
+@pytest.fixture(scope="module")
+def test_files(tmpdir_factory):
+ """Create and save some python codes and text in temporary files."""
+ tmpdir = tmpdir_factory.mktemp("files")
+
+ filename1 = osp.join(tmpdir.strpath, 'foo1.py')
+ with open(filename1, 'w') as f:
+ f.write("# -*- coding: utf-8 -*-\n"
+ "def foo:\n"
+ " print(Hello World!)\n")
+
+ filename2 = osp.join(tmpdir.strpath, 'text1.txt')
+ with open(filename2, 'w') as f:
+ f.write("This is a simple text file for\n"
+ "testing the Outline Explorer.\n")
+
+ filename3 = osp.join(tmpdir.strpath, 'foo2.py')
+ with open(filename3, 'w') as f:
+ f.write("# -*- coding: utf-8 -*-\n"
+ "# ---- a comment\n")
+
+ return [filename1, filename2, filename3]
+
+
+@pytest.fixture
+def outlineexplorer(qtbot):
+ """Set up an OutlineExplorerWidget."""
+ outlineexplorer = OutlineExplorerWidget(
+ show_fullpath=False, show_all_files=True, group_cells=False,
+ show_comments=True, sort_files_alphabetically=False)
+ # Fix the size of the outline explorer to prevent an
+ # 'Unable to set geometry ' warning if the test fails.
+ outlineexplorer.setFixedSize(400, 350)
+
+ qtbot.addWidget(outlineexplorer)
+ outlineexplorer.show()
+
+ return outlineexplorer
+
+
+@pytest.fixture
+def editorstack(qtbot, outlineexplorer):
+ def _create_editorstack(files):
+ editorstack = editor.EditorStack(None, [])
+ editorstack.set_find_widget(Mock())
+ editorstack.set_io_actions(Mock(), Mock(), Mock(), Mock())
+ editorstack.analysis_timer = Mock()
+ editorstack.save_dialog_on_tests = True
+ editorstack.set_outlineexplorer(outlineexplorer)
+
+ qtbot.addWidget(editorstack)
+ editorstack.show()
+
+ for index, file in enumerate(files):
+ focus = index == 0
+ editorstack.load(file, set_current=focus)
+ return editorstack
+ return _create_editorstack
+
+
+# ---- Test all files mode
+def test_load_files(editorstack, outlineexplorer, test_files):
+ """
+ Test that the content of the outline explorer is updated correctly
+ after a file is loaded in the editor.
+ """
+ editorstack = editorstack([])
+ treewidget = outlineexplorer.treewidget
+
+ # Load the test files one by one and assert the content of the
+ # outline explorer.
+ expected_result = [['foo1.py'],
+ ['foo1.py', 'text1.txt'],
+ ['foo1.py', 'text1.txt', 'foo2.py']]
+ for index, file in enumerate(test_files):
+ editorstack.load(file)
+ assert editorstack.get_current_filename() == file
+ editorstack.get_stack_index() == index
+
+ results = [item.text(0) for item in treewidget.get_visible_items()]
+ assert results == expected_result[index]
+ assert editorstack.get_stack_index() == index
+
+
+def test_close_editor(editorstack, outlineexplorer, test_files):
+ """
+ Test that the content of the outline explorer is empty after the
+ editorstack has been closed.
+
+ Regression test for issue #7798.
+ """
+ editorstack = editorstack(test_files)
+ treewidget = outlineexplorer.treewidget
+ assert treewidget.get_visible_items()
+
+ # Close the editor and assert that the outline explorer tree is empty.
+ editorstack.close()
+ assert not treewidget.get_visible_items()
+
+
+def test_close_a_file(editorstack, outlineexplorer, test_files):
+ """
+ Test that the content of the outline explorer is updated corrrectly
+ after a file has been closed in the editorstack.
+
+ Regression test for issue #7798.
+ """
+ editorstack = editorstack(test_files)
+ treewidget = outlineexplorer.treewidget
+
+ # Close 'foo2.py' and assert that the content of the outline explorer
+ # tree has been updated.
+ editorstack.close_file(index=1)
+ results = [item.text(0) for item in treewidget.get_visible_items()]
+ assert results == ['foo1.py', 'foo2.py']
+
+
+def test_sort_file_alphabetically(editorstack, outlineexplorer, test_files):
+ """
+ Test that the option to sort the files in alphabetical order in the
+ outline explorer is working as expected.
+
+ This feature was introduced in PR #8015
+ """
+ editorstack = editorstack(test_files)
+ treewidget = outlineexplorer.treewidget
+ results = [item.text(0) for item in treewidget.get_visible_items()]
+ assert results == ['foo1.py', 'text1.txt', 'foo2.py']
+
+ # Set the option to sort files alphabetically to True.
+ treewidget.toggle_sort_files_alphabetically(True)
+ results = [item.text(0) for item in treewidget.get_visible_items()]
+ assert results == ['foo1.py', 'foo2.py', 'text1.txt']
+
+
+def test_sync_file_order(editorstack, outlineexplorer, test_files):
+ """
+ Test that the order of the files in the Outline Explorer is updated when
+ tabs are moved in the EditorStack.
+
+ This feature was introduced in PR #8015
+ """
+ editorstack = editorstack(test_files)
+ treewidget = outlineexplorer.treewidget
+ results = [item.text(0) for item in treewidget.get_visible_items()]
+ assert results == ['foo1.py', 'text1.txt', 'foo2.py']
+
+ # Switch tab 1 with tab 2.
+ editorstack.tabs.tabBar().moveTab(0, 1)
+ results = [item.text(0) for item in treewidget.get_visible_items()]
+ assert results == ['text1.txt', 'foo1.py', 'foo2.py']
+
+
+# ---- Test single file mode
+def test_toggle_off_show_all_files(editorstack, outlineexplorer, test_files):
+ """
+ Test that toggling off the option to show all files in the Outline Explorer
+ hide all root file items but the one corresponding to the currently
+ selected Editor and assert that the remaning root file item is
+ expanded correctly.
+ """
+ editorstack = editorstack(test_files)
+ treewidget = outlineexplorer.treewidget
+ assert editorstack.get_stack_index() == 0
+
+ # Untoggle show all files option.
+ treewidget.toggle_show_all_files(False)
+ results = [item.text(0) for item in treewidget.get_visible_items()]
+ assert results == ['foo1.py', 'foo']
+
+
+@pytest.mark.skipif(sys.platform.startswith('linux'), reason="Fails on Linux")
+def test_single_file_sync(editorstack, outlineexplorer, test_files, qtbot):
+ """
+ Test that the content of the Outline Explorer is updated correctly
+ when the current Editor in the Editorstack changes.
+ """
+ editorstack = editorstack(test_files)
+ treewidget = outlineexplorer.treewidget
+ treewidget.toggle_show_all_files(False)
+ assert editorstack.get_stack_index() == 0
+
+ # Select the last file in the Editorstack.
+ with qtbot.waitSignal(editorstack.editor_focus_changed):
+ editorstack.tabs.setCurrentIndex(2)
+ results = [item.text(0) for item in treewidget.get_visible_items()]
+ assert results == ['foo2.py', '---- a comment']
+
+
+def test_toggle_on_show_all_files(editorstack, outlineexplorer, test_files):
+ """
+ Test that toggling back the option to show all files, after the
+ order of the files in the Editorstack was changed while it was in single
+ file mode, show all the root file items in the correct order.
+ """
+ editorstack = editorstack(test_files)
+ treewidget = outlineexplorer.treewidget
+ treewidget.toggle_show_all_files(False)
+
+ # Move the first file to the second position in the tabbar of the
+ # Editorstack and toggle back the show all files option.
+ editorstack.tabs.tabBar().moveTab(0, 1)
+ treewidget.toggle_show_all_files(True)
+ results = [item.text(0) for item in treewidget.get_visible_items()]
+ assert results == ['text1.txt', 'foo1.py', 'foo', 'foo2.py']
+
+
+if __name__ == "__main__":
+ import os
+ pytest.main([os.path.basename(__file__), '-vv', '-rw'])
diff --git a/spyder/plugins/editor/widgets/tests/test_editor_sort_tabs.py b/spyder/plugins/editor/widgets/tests/test_editor_sort_tabs.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/spyder/widgets/tests/test_editorsplitter.py b/spyder/plugins/editor/widgets/tests/test_editorsplitter.py
similarity index 78%
rename from spyder/widgets/tests/test_editorsplitter.py
rename to spyder/plugins/editor/widgets/tests/test_editorsplitter.py
index 922923c18b9..f758a8147e4 100644
--- a/spyder/widgets/tests/test_editorsplitter.py
+++ b/spyder/plugins/editor/widgets/tests/test_editorsplitter.py
@@ -11,38 +11,95 @@
# Standard library imports
try:
from unittest.mock import Mock
+ import pathlib
except ImportError:
from mock import Mock # Python 2
+ import pathlib2 as pathlib
+
+import os
+import os.path as osp
+from functools import partial
# Third party imports
import pytest
-from qtpy import PYQT4
from qtpy.QtCore import Qt
# Local imports
-from spyder.widgets.editor import EditorStack, EditorSplitter
+from spyder.plugins.editor.widgets.editor import EditorStack, EditorSplitter
# ---- Qt Test Fixtures
-@pytest.fixture
-def base_editor_bot(qtbot):
+def editor_stack():
editor_stack = EditorStack(None, [])
- editor_stack.set_introspector(Mock())
editor_stack.set_find_widget(Mock())
editor_stack.set_io_actions(Mock(), Mock(), Mock(), Mock())
- return editor_stack, qtbot
+ return editor_stack
@pytest.fixture
def editor_splitter_bot(qtbot):
"""Create editor splitter."""
- es = editor_splitter = EditorSplitter(None, Mock(), [], first=True)
+ es = EditorSplitter(None, Mock(), [], first=True)
qtbot.addWidget(es)
es.show()
return es
+@pytest.fixture
+def editor_splitter_lsp(qtbot_module, lsp_manager, request):
+ text = """
+ import sys
+ """
+
+ def report_file_open(options):
+ filename = options['filename']
+ language = options['language']
+ callback = options['codeeditor']
+ lsp_manager.register_file(
+ language.lower(), filename, callback)
+ settings = lsp_manager.main.editor.lsp_editor_settings['python']
+ callback.start_lsp_services(settings)
+
+ with qtbot_module.waitSignal(
+ callback.lsp_response_signal, timeout=30000):
+ callback.document_did_open()
+
+ def register_editorstack(editorstack):
+ editorstack.perform_lsp_request.connect(lsp_manager.send_request)
+ editorstack.sig_open_file.connect(report_file_open)
+ settings = lsp_manager.main.editor.lsp_editor_settings['python']
+ editorstack.notify_server_ready('python', settings)
+
+ def clone(editorstack, template=None):
+ # editorstack.clone_from(template)
+ editor_stack = EditorStack(None, [])
+ editor_stack.set_find_widget(Mock())
+ editor_stack.set_io_actions(Mock(), Mock(), Mock(), Mock())
+ # Emulate "cloning"
+ editorsplitter.editorstack.new('test.py', 'utf-8', text)
+
+ mock_plugin = Mock()
+ editorsplitter = EditorSplitter(
+ None, mock_plugin, [], register_editorstack_cb=register_editorstack)
+
+ editorsplitter.editorstack.set_find_widget(Mock())
+ editorsplitter.editorstack.set_io_actions(Mock(), Mock(), Mock(), Mock())
+ editorsplitter.editorstack.new('test.py', 'utf-8', text)
+
+ mock_plugin.clone_editorstack.side_effect = partial(
+ clone, template=editorsplitter.editorstack)
+ qtbot_module.addWidget(editorsplitter)
+ editorsplitter.show()
+
+ def teardown():
+ editorsplitter.hide()
+ editorsplitter.close()
+
+ request.addfinalizer(teardown)
+ return editorsplitter, lsp_manager
+
+
@pytest.fixture
def editor_splitter_layout_bot(editor_splitter_bot):
"""Create editor splitter for testing layouts."""
@@ -51,7 +108,6 @@ def editor_splitter_layout_bot(editor_splitter_bot):
# Allow the split() to duplicate editor stacks.
def clone(editorstack):
editorstack.close_action.setEnabled(False)
- editorstack.set_introspector(Mock())
editorstack.set_find_widget(Mock())
editorstack.set_io_actions(Mock(), Mock(), Mock(), Mock())
editorstack.new('foo.py', 'utf-8', 'a = 1\nprint(a)\n\nx = 2')
@@ -68,7 +124,6 @@ def clone(editorstack):
# ---- Tests
-
def test_init(editor_splitter_bot):
""""Test __init__."""
es = editor_splitter_bot
@@ -94,11 +149,11 @@ def test_init(editor_splitter_bot):
assert es.widget(0) == es.editorstack
-def test_close(qtbot):
+def test_close(editor_splitter_bot, qtbot):
"""Test the inteface for closing the editor splitters."""
# Split the main editorspliter once, than split the second editorsplitter
# twice.
- es = editor_splitter_bot(qtbot)
+ es = editor_splitter_bot
es.split()
esw1 = es.widget(1)
@@ -250,11 +305,11 @@ def test_get_layout_settings(editor_splitter_bot, qtbot, mocker):
assert setting['splitsettings'] == [(False, None, [])]
# Add some editors to patch output of iter_editorstacks.
- stack1 = base_editor_bot(qtbot)[0]
+ stack1 = editor_stack()
stack1.new('foo.py', 'utf-8', 'a = 1\nprint(a)\n\nx = 2')
stack1.new('layout_test.py', 'utf-8', 'spam egg\n')
- stack2 = base_editor_bot(qtbot)[0]
+ stack2 = editor_stack()
stack2.new('test.py', 'utf-8', 'test text')
mocker.patch.object(EditorSplitter, "iter_editorstacks")
@@ -301,8 +356,7 @@ def test_set_layout_settings_dont_goto(editor_splitter_layout_bot):
assert es.count() == 2 # One EditorStack and one EditorSplitter.
assert es.widget(1).count() == 2 # One EditorStack and one EditorSplitter.
assert es.widget(1).widget(1).count() == 1 # One EditorStack.
- if not PYQT4:
- assert get_settings['hexstate'] == state
+ assert get_settings['hexstate'] == state
# All the lines for each tab and split are at the last line number.
assert get_settings['splitsettings'] == [(False, 'foo.py', [5, 2, linecount]),
@@ -337,6 +391,29 @@ def test_set_layout_settings_goto(editor_splitter_layout_bot):
(False, 'foo.py', [1, 1, 1])]
+@pytest.mark.slow
+@pytest.mark.first
+@pytest.mark.skipif(os.name == 'nt',
+ reason="Makes other tests fail on Windows")
+def test_lsp_splitter_close(editor_splitter_lsp):
+ """Test for issue #9341"""
+ editorsplitter, lsp_manager = editor_splitter_lsp
+
+ editorsplitter.split()
+ lsp_files = lsp_manager.clients['python']['instance'].watched_files
+ editor = editorsplitter.editorstack.get_current_editor()
+ path = pathlib.Path(osp.abspath(editor.filename)).as_uri()
+ assert len(lsp_files[path]) == 2
+
+ editorstacks = editorsplitter.iter_editorstacks()
+ assert len(editorstacks) == 2
+
+ last_editorstack = editorstacks[0][0]
+ last_editorstack.close()
+ lsp_files = lsp_manager.clients['python']['instance'].watched_files
+ assert len(lsp_files[path]) == 1
+
+
if __name__ == "__main__":
import os.path as osp
pytest.main(['-x', osp.basename(__file__), '-v', '-rw'])
diff --git a/spyder/widgets/sourcecode/tests/test_extra_selections.py b/spyder/plugins/editor/widgets/tests/test_extra_selections.py
similarity index 96%
rename from spyder/widgets/sourcecode/tests/test_extra_selections.py
rename to spyder/plugins/editor/widgets/tests/test_extra_selections.py
index bd2ccf84db1..ce9714992a8 100644
--- a/spyder/widgets/sourcecode/tests/test_extra_selections.py
+++ b/spyder/plugins/editor/widgets/tests/test_extra_selections.py
@@ -11,7 +11,7 @@
# Local imports
from spyder.utils.qthelpers import qapplication
-from spyder.widgets.sourcecode.codeeditor import CodeEditor
+from spyder.plugins.editor.widgets.codeeditor import CodeEditor
# --- Fixtures
diff --git a/spyder/widgets/sourcecode/tests/test_folding.py b/spyder/plugins/editor/widgets/tests/test_folding.py
similarity index 90%
rename from spyder/widgets/sourcecode/tests/test_folding.py
rename to spyder/plugins/editor/widgets/tests/test_folding.py
index a9e366ff37f..7532c889c44 100644
--- a/spyder/widgets/sourcecode/tests/test_folding.py
+++ b/spyder/plugins/editor/widgets/tests/test_folding.py
@@ -14,8 +14,8 @@
# Local imports
from spyder.utils.qthelpers import qapplication
-from spyder.widgets.sourcecode.codeeditor import CodeEditor
-from spyder.widgets.sourcecode.api.folding import print_tree
+from spyder.plugins.editor.widgets.codeeditor import CodeEditor
+from spyder.plugins.editor.api.folding import print_tree
# --- Fixtures
@@ -49,7 +49,7 @@ def get_fold_levels():
# --- Tests
# -----------------------------------------------------------------------------
def test_simple_folding(get_fold_levels):
- assert get_fold_levels == [[2, 0, 'V'],
+ assert get_fold_levels == [[2, 0, 'V'],
[6, 1, 'V'],
[9, 1, 'V'],
[12, 2, 'V']]
diff --git a/spyder/plugins/editor/widgets/tests/test_goto.py b/spyder/plugins/editor/widgets/tests/test_goto.py
new file mode 100644
index 00000000000..6b1994864cf
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/test_goto.py
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+"""Tests for editor URI and mailto go to handling."""
+
+# Standard library imports
+import os
+import tempfile
+
+# Third party imports
+from qtpy.QtCore import Qt, QPoint
+from qtpy.QtGui import QTextCursor
+import pytest
+
+# Local imports
+from spyder.plugins.editor.widgets.tests.test_codeeditor import editorbot
+
+# Constants
+TEST_FOLDER = os.path.abspath(os.path.dirname(__file__))
+_, TEMPFILE_PATH = tempfile.mkstemp()
+TEST_FILE_ABS = [os.path.join(TEST_FOLDER, f) for f in
+ os.listdir(TEST_FOLDER) if f.endswith('.py')][0]
+TEST_FILE_REL = [f for f in os.listdir(TEST_FOLDER) if f.endswith('.py')][0]
+
+
+@pytest.mark.parametrize('params', [
+ # Parameter, Expected output, Full file path (or None if not file)
+ # ----------------------------------------------------------------
+ # Files that exist with absolute paths
+ ('"file://{}/"\n'.format(TEMPFILE_PATH), TEMPFILE_PATH,
+ TEMPFILE_PATH),
+ ('"file://{}/"\n'.format(TEST_FILE_ABS), TEST_FILE_ABS,
+ TEST_FILE_ABS),
+ # Files that exist with relative paths
+ ('"file://./{}/"\n'.format(TEST_FILE_REL), TEST_FILE_REL,
+ os.path.join(TEST_FOLDER, TEST_FILE_REL)),
+ # Files that do not exist
+ ('"file:///not there/"', 'file:///not there/', '/not there/'),
+ ('"file:///not_there/"', 'file:///not_there/', '/not_there/'),
+ # Urls
+ ('" https://google.com"\n', 'https://google.com', None),
+ ('# https://google.com"\n', 'https://google.com', None),
+ # Mail to
+ ('" mailto:some@email.com"\n', 'mailto:some@email.com', None),
+ ('# mailto:some@email.com\n', 'mailto:some@email.com', None),
+ # Issues
+ ('# gl:gitlab-org/gitlab-ce#62529\n',
+ 'gl:gitlab-org/gitlab-ce#62529', None),
+ ('# bb:birkenfeld/pygments-main#1516\n',
+ 'bb:birkenfeld/pygments-main#1516', None),
+ ('# gh:spyder-ide/spyder#123\n',
+ 'gh:spyder-ide/spyder#123', None),
+ ('# gh:spyder-ide/spyder#123\n',
+ 'gh:spyder-ide/spyder#123', None),
+ ]
+ )
+def test_goto_uri(qtbot, editorbot, params):
+ """Test that the uri search is working correctly."""
+ _, code_editor = editorbot
+ code_editor.show()
+
+ param, expected_output_text, full_file_path = params
+ if full_file_path:
+ code_editor.filename = full_file_path
+
+ # Set text in editor
+ code_editor.set_text(param)
+
+ # Get cursor coordinates
+ code_editor.moveCursor(QTextCursor.Start)
+ x, y = code_editor.get_coordinates('cursor')
+
+ # The `+ 23` is to put the mouse on top of the word
+ point = code_editor.calculate_real_position(QPoint(x + 23, y))
+
+ # Move cursor to end of line
+ code_editor.moveCursor(QTextCursor.End)
+
+ # Move mouse cursor on top of test word
+ qtbot.mouseMove(code_editor, point, delay=500)
+
+ with qtbot.waitSignal(code_editor.sig_uri_found, timeout=3000) as blocker:
+ qtbot.keyPress(code_editor, Qt.Key_Control, delay=500)
+ args = blocker.args
+ print(param, expected_output_text)
+ print([args])
+ output_text = args[0]
+ assert expected_output_text in output_text
diff --git a/spyder/plugins/editor/widgets/tests/test_hints_and_calltips.py b/spyder/plugins/editor/widgets/tests/test_hints_and_calltips.py
new file mode 100644
index 00000000000..903fd0ddd05
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/test_hints_and_calltips.py
@@ -0,0 +1,133 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+"""Tests for editor calltips and hover hints tooltips."""
+
+# Standard library imports
+import sys
+
+# Third party imports
+from qtpy.QtCore import Qt, QPoint
+from qtpy.QtGui import QTextCursor
+import pytest
+
+# Constants
+PY2 = sys.version[0] == '2'
+TEST_SIG = 'some_function(foo={}, hello=None)'
+TEST_DOCSTRING = "This is the test docstring."
+TEST_TEXT = """'''Testing something'''
+def {SIG}:
+ '''{DOC}'''
+
+
+some_function""".format(SIG=TEST_SIG, DOC=TEST_DOCSTRING)
+
+
+@pytest.mark.slow
+@pytest.mark.second
+def test_hide_calltip(lsp_codeeditor, qtbot):
+ """Test that calltips are hidden when a matching ')' is found."""
+ code_editor, _ = lsp_codeeditor
+
+ text = 'a = [1,2,3]\n(max'
+ # Set text to start
+ code_editor.set_text(text)
+ code_editor.go_to_line(2)
+ code_editor.move_cursor(4)
+ calltip = code_editor.calltip_widget
+ assert not calltip.isVisible()
+
+ with qtbot.waitSignal(code_editor.sig_signature_invoked, timeout=30000):
+ qtbot.keyPress(code_editor, Qt.Key_ParenLeft, delay=3000)
+
+ qtbot.waitUntil(lambda: calltip.isVisible(), timeout=3000)
+ qtbot.keyPress(code_editor, Qt.Key_ParenRight, delay=1000)
+ qtbot.keyPress(code_editor, Qt.Key_Space)
+ qtbot.waitUntil(lambda: not calltip.isVisible(), timeout=3000)
+ qtbot.keyPress(code_editor, Qt.Key_ParenRight, delay=1000)
+ qtbot.keyPress(code_editor, Qt.Key_Enter, delay=1000)
+
+
+@pytest.mark.slow
+@pytest.mark.second
+@pytest.mark.parametrize('params', [
+ # Parameter, Expected Output
+ ('dict', 'dict'),
+ ('type', 'type'),
+ ('"".format', '-> str'),
+ (TEST_TEXT, TEST_SIG)
+ ]
+ )
+def test_get_calltips(qtbot, lsp_codeeditor, params):
+ """Test that the editor is returning hints."""
+ code_editor, _ = lsp_codeeditor
+
+ param, expected_output_text = params
+
+ # Set text in editor
+ code_editor.set_text(param)
+
+ # Move cursor to end of line
+ code_editor.moveCursor(QTextCursor.End)
+
+ code_editor.calltip_widget.hide()
+ with qtbot.waitSignal(code_editor.sig_signature_invoked,
+ timeout=30000) as blocker:
+ qtbot.keyPress(code_editor, Qt.Key_ParenLeft, delay=1000)
+
+ # This is needed to leave time for the calltip to appear
+ # and make the tests succeed
+ qtbot.wait(2000)
+
+ args = blocker.args
+ print('args:', [args])
+ output_text = args[0]['signatures']['label']
+ assert expected_output_text in output_text
+ code_editor.calltip_widget.hide()
+
+
+@pytest.mark.slow
+@pytest.mark.second
+@pytest.mark.parametrize('params', [
+ # Parameter, Expected Output
+ ('dict', '' if PY2 else 'dict'),
+ ('type', 'type'),
+ ('"".format', '-> str'),
+ ('import math', 'module'),
+ (TEST_TEXT, TEST_DOCSTRING)
+ ]
+ )
+def test_get_hints(qtbot, lsp_codeeditor, params):
+ """Test that the editor is returning hover hints."""
+ code_editor, _ = lsp_codeeditor
+ param, expected_output_text = params
+
+ # Set text in editor
+ code_editor.set_text(param)
+
+ # Moe cursor to end of line
+ code_editor.moveCursor(QTextCursor.End)
+
+ # Get cursor coordinates
+ x, y = code_editor.get_coordinates('cursor')
+ # The `- 5` is to put the mouse on top of the word
+ point = code_editor.calculate_real_position(QPoint(x - 5, y))
+
+ code_editor.tooltip_widget.hide()
+ with qtbot.waitSignal(code_editor.sig_display_object_info,
+ timeout=30000) as blocker:
+ cursor = code_editor.cursorForPosition(point)
+ line, col = cursor.blockNumber(), cursor.columnNumber()
+ code_editor.request_hover(line, col)
+
+ # This is needed to leave time for the tooltip to appear
+ # and make the tests succeed
+ qtbot.wait(2000)
+
+ args = blocker.args
+ print('args:', [args])
+ output_text = args[0]
+ assert expected_output_text in output_text
+ code_editor.tooltip_widget.hide()
diff --git a/spyder/widgets/sourcecode/tests/test_indentation.py b/spyder/plugins/editor/widgets/tests/test_indentation.py
similarity index 98%
rename from spyder/widgets/sourcecode/tests/test_indentation.py
rename to spyder/plugins/editor/widgets/tests/test_indentation.py
index 137e05fd685..9bb7ed7c0a3 100644
--- a/spyder/widgets/sourcecode/tests/test_indentation.py
+++ b/spyder/plugins/editor/widgets/tests/test_indentation.py
@@ -14,7 +14,7 @@
# Local imports
from spyder.py3compat import to_text_string
-from spyder.widgets.sourcecode.codeeditor import CodeEditor
+from spyder.plugins.editor.widgets.codeeditor import CodeEditor
# --- Helper methods
diff --git a/spyder/plugins/editor/widgets/tests/test_introspection.py b/spyder/plugins/editor/widgets/tests/test_introspection.py
new file mode 100644
index 00000000000..2c587c94816
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/test_introspection.py
@@ -0,0 +1,258 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+
+"""Tests for code completion."""
+
+# Standard library imports
+import os
+import os.path as osp
+import random
+
+# Third party imports
+import pytest
+import pytestqt
+
+from qtpy.QtCore import Qt
+
+# Local imports
+from spyder.py3compat import PY2
+
+
+# Location of this file
+LOCATION = osp.realpath(osp.join(os.getcwd(), osp.dirname(__file__)))
+
+
+@pytest.mark.slow
+@pytest.mark.first
+def test_space_completion(lsp_codeeditor, qtbot):
+ """Validate completion's space character handling."""
+ code_editor, _ = lsp_codeeditor
+ completion = code_editor.completion_widget
+
+ # Set cursor to start
+ code_editor.go_to_line(1)
+
+ # Complete from numpy --> from numpy import
+ qtbot.keyClicks(code_editor, 'from numpy ')
+ with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
+ code_editor.document_did_change()
+
+ # press tab and get completions
+ with qtbot.waitSignal(completion.sig_show_completions,
+ timeout=10000) as sig:
+ qtbot.keyPress(code_editor, Qt.Key_Tab)
+ assert "import" in [x['label'] for x in sig.args[0]]
+
+ assert code_editor.toPlainText() == 'from numpy import'
+ assert not completion.isVisible()
+
+
+@pytest.mark.slow
+@pytest.mark.first
+def test_hide_widget_completion(lsp_codeeditor, qtbot):
+ """Validate hiding completion widget after a delimeter or operator."""
+ code_editor, _ = lsp_codeeditor
+ completion = code_editor.completion_widget
+
+ delimiters = ['(', ')', '[', ']', '{', '}', ',', ':', ';', '@', '=', '->',
+ '+=', '-=', '*=', '/=', '//=', '%=', '@=', '&=', '|=', '^=',
+ '>>=', '<<=', '**=']
+ # Set cursor to start
+ code_editor.go_to_line(1)
+
+ # Complete from numpy import --> from numpy import ?
+ qtbot.keyClicks(code_editor, 'from numpy import ')
+ with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
+ code_editor.document_did_change()
+
+ # press tab and get completions
+ with qtbot.waitSignal(completion.sig_show_completions,
+ timeout=10000) as sig:
+ qtbot.keyPress(code_editor, Qt.Key_Tab)
+
+ # Check the completion widget is visible
+ assert completion.isHidden() is False
+
+ # Write a random delimeter on the code editor
+ delimeter = random.choice(delimiters)
+ qtbot.keyClicks(code_editor, delimeter)
+
+ # Check the completion widget is not visible
+ assert completion.isHidden() is True
+
+
+@pytest.mark.slow
+@pytest.mark.first
+def test_completions(lsp_codeeditor, qtbot):
+ """Exercise code completion in several ways."""
+ code_editor, _ = lsp_codeeditor
+ completion = code_editor.completion_widget
+
+ # Set cursor to start
+ code_editor.go_to_line(1)
+
+ # Complete import mat--> import math
+ qtbot.keyClicks(code_editor, 'import mat')
+ with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
+ code_editor.document_did_change()
+
+ # press tab and get completions
+ with qtbot.waitSignal(completion.sig_show_completions,
+ timeout=10000) as sig:
+ qtbot.keyPress(code_editor, Qt.Key_Tab)
+ assert "math" in [x['label'] for x in sig.args[0]]
+
+ # enter should accept first completion
+ qtbot.keyPress(completion, Qt.Key_Enter, delay=300)
+ assert code_editor.toPlainText() == 'import math'
+
+ # enter for new line
+ qtbot.keyPress(code_editor, Qt.Key_Enter, delay=300)
+
+ # Complete math.d() -> math.degrees()
+ qtbot.keyClicks(code_editor, 'math.d')
+ with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
+ code_editor.document_did_change()
+
+ with qtbot.waitSignal(completion.sig_show_completions,
+ timeout=10000) as sig:
+ qtbot.keyPress(code_editor, Qt.Key_Tab)
+ assert "degrees(x)" in [x['label'] for x in sig.args[0]]
+
+ assert code_editor.toPlainText() == 'import math\nmath.degrees'
+
+ # enter for new line
+ qtbot.keyPress(code_editor, Qt.Key_Enter, delay=300)
+
+ # Complete math.d() -> math.degrees()
+ qtbot.keyClicks(code_editor, 'math.d(')
+ qtbot.keyPress(code_editor, Qt.Key_Left, delay=300)
+ qtbot.keyClicks(code_editor, 'e')
+ with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
+ code_editor.document_did_change()
+
+ with qtbot.waitSignal(completion.sig_show_completions,
+ timeout=10000) as sig:
+ qtbot.keyPress(code_editor, Qt.Key_Tab)
+ assert "degrees(x)" in [x['label'] for x in sig.args[0]]
+
+ # right for () + enter for new line
+ qtbot.keyPress(code_editor, Qt.Key_Right, delay=300)
+ qtbot.keyPress(code_editor, Qt.Key_Right, delay=300)
+ qtbot.keyPress(code_editor, Qt.Key_Enter, delay=300)
+
+ # Complete math.a ... s to math.asin
+ qtbot.keyClicks(code_editor, 'math.a')
+ with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
+ code_editor.document_did_change()
+
+ with qtbot.waitSignal(completion.sig_show_completions,
+ timeout=10000) as sig:
+ qtbot.keyPress(code_editor, Qt.Key_Tab)
+ assert "asin(x)" in [x['label'] for x in sig.args[0]]
+ # Test if the list is updated
+ assert "acos(x)" == completion.completion_list[0]['label']
+ qtbot.keyClicks(completion, 's')
+ assert "asin" == completion.item(0).text()
+ qtbot.keyPress(completion, Qt.Key_Enter, delay=300)
+
+ # enter for new line
+ qtbot.keyPress(code_editor, Qt.Key_Enter, delay=300)
+
+ # Check can get list back
+ qtbot.keyClicks(code_editor, 'math.c')
+ with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
+ code_editor.document_did_change()
+
+ with qtbot.waitSignal(completion.sig_show_completions,
+ timeout=10000) as sig:
+ qtbot.keyPress(code_editor, Qt.Key_Tab)
+ assert completion.count() == 4
+ assert "ceil(x)" in [x['label'] for x in sig.args[0]]
+ qtbot.keyClicks(completion, 'e')
+ assert completion.count() == 1
+ qtbot.keyPress(completion, Qt.Key_Backspace)
+ assert completion.count() == 4
+
+ # enter for new line
+ qtbot.keyPress(code_editor, Qt.Key_Enter, delay=300)
+
+ # Complete math.a s ... to math.asin
+ qtbot.keyClicks(code_editor, 'math.a')
+ with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
+ code_editor.document_did_change()
+
+ with qtbot.waitSignal(completion.sig_show_completions,
+ timeout=10000) as sig:
+ qtbot.keyPress(code_editor, Qt.Key_Tab)
+ qtbot.keyPress(code_editor, 's')
+ assert "asin(x)" in [x['label'] for x in sig.args[0]]
+ qtbot.keyPress(completion, Qt.Key_Enter, delay=300)
+
+ # enter for new line
+ qtbot.keyPress(code_editor, Qt.Key_Enter, delay=300)
+
+ # Complete math.a|angle s ... to math.asin|angle
+ qtbot.keyClicks(code_editor, 'math.aangle')
+ for i in range(len('angle')):
+ qtbot.keyClick(code_editor, Qt.Key_Left)
+
+ with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
+ code_editor.document_did_change()
+
+ with qtbot.waitSignal(completion.sig_show_completions,
+ timeout=10000) as sig:
+ qtbot.keyPress(code_editor, Qt.Key_Tab)
+ qtbot.keyPress(code_editor, 's')
+ assert "asin(x)" in [x['label'] for x in sig.args[0]]
+ qtbot.keyPress(completion, Qt.Key_Enter, delay=300)
+ for i in range(len('angle')):
+ qtbot.keyClick(code_editor, Qt.Key_Right)
+
+ # Check math.a doesn't emit sig_show_completions
+ qtbot.keyPress(code_editor, Qt.Key_Enter, delay=300)
+ qtbot.keyClicks(code_editor, 'math.a')
+ with qtbot.waitSignal(code_editor.lsp_response_signal, timeout=30000):
+ code_editor.document_did_change()
+
+ try:
+ with qtbot.waitSignal(completion.sig_show_completions,
+ timeout=5000) as sig:
+ qtbot.keyPress(code_editor, Qt.Key_Tab)
+ qtbot.keyPress(code_editor, Qt.Key_Backspace)
+ raise RuntimeError("The signal should not have been received!")
+ except pytestqt.exceptions.TimeoutError:
+ pass
+
+ try:
+ with qtbot.waitSignal(completion.sig_show_completions,
+ timeout=5000) as sig:
+ qtbot.keyPress(code_editor, Qt.Key_Tab)
+ qtbot.keyPress(code_editor, Qt.Key_Return)
+ raise RuntimeError("The signal should not have been received!")
+ except pytestqt.exceptions.TimeoutError:
+ pass
+
+ assert code_editor.toPlainText() == 'import math\nmath.degrees\n'\
+ 'math.degrees()\nmath.asin\n'\
+ 'math.c\nmath.asin\n'\
+ 'math.asinangle\n'\
+ 'math.\n'
+
+
+if __name__ == '__main__':
+ pytest.main(['test_introspection.py', '--run-slow'])
+
+ # Modify PYTHONPATH
+ # editor.introspector.change_extra_path([LOCATION])
+ # qtbot.wait(10000)
+ #
+ # # Type 'from test' and try to get completion
+ # with qtbot.waitSignal(completion.sig_show_completions,
+ # timeout=10000) as sig:
+ # qtbot.keyClicks(code_editor, ' test_')
+ # qtbot.keyPress(code_editor, Qt.Key_Tab)
+ # assert "test_introspection" in sig.args[0]
diff --git a/spyder/widgets/sourcecode/tests/test_panels.py b/spyder/plugins/editor/widgets/tests/test_panels.py
similarity index 80%
rename from spyder/widgets/sourcecode/tests/test_panels.py
rename to spyder/plugins/editor/widgets/tests/test_panels.py
index 6d1274a8e0b..94038e20370 100644
--- a/spyder/widgets/sourcecode/tests/test_panels.py
+++ b/spyder/plugins/editor/widgets/tests/test_panels.py
@@ -13,11 +13,11 @@
# Local imports
from spyder.utils.qthelpers import qapplication
-from spyder.widgets.sourcecode.codeeditor import CodeEditor
-from spyder.widgets.panels.linenumber import LineNumberArea
-from spyder.widgets.panels.edgeline import EdgeLine
-from spyder.widgets.panels.scrollflag import ScrollFlagArea
-from spyder.widgets.panels.indentationguides import IndentationGuide
+from spyder.plugins.editor.widgets.codeeditor import CodeEditor
+from spyder.plugins.editor.panels.linenumber import LineNumberArea
+from spyder.plugins.editor.panels.edgeline import EdgeLine
+from spyder.plugins.editor.panels.scrollflag import ScrollFlagArea
+from spyder.plugins.editor.panels.indentationguides import IndentationGuide
# --- Fixtures
diff --git a/spyder/plugins/editor/widgets/tests/test_recover.py b/spyder/plugins/editor/widgets/tests/test_recover.py
new file mode 100644
index 00000000000..58f4876bdfa
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/test_recover.py
@@ -0,0 +1,328 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Tests for recover.py"""
+
+# Standard library imports
+import os.path as osp
+import pytest
+import shutil
+
+# Third party imports
+from qtpy.QtWidgets import QDialogButtonBox, QPushButton, QTableWidget
+
+# Local imports
+from spyder.py3compat import PY2
+from spyder.plugins.editor.widgets.recover import (make_temporary_files,
+ RecoveryDialog)
+
+
+@pytest.fixture
+def recovery_env(tmpdir):
+ """Create a dir with various autosave files and cleans up afterwards."""
+ yield make_temporary_files(str(tmpdir))
+ shutil.rmtree(str(tmpdir))
+
+
+def test_recoverydialog_has_cancel_button(qtbot, tmpdir):
+ """
+ Test that RecoveryDialog has a Cancel button.
+
+ Test that a RecoveryDialog has a button in a dialog button box and that
+ this button cancels the dialog window.
+ """
+ dialog = RecoveryDialog(str(tmpdir), {})
+ qtbot.addWidget(dialog)
+ button = dialog.findChild(QDialogButtonBox).findChild(QPushButton)
+ with qtbot.waitSignal(dialog.rejected):
+ button.click()
+
+
+def test_recoverydialog_table_labels(qtbot, recovery_env):
+ """Test that table in RecoveryDialog has the correct labels."""
+ orig_dir, autosave_dir, autosave_mapping = recovery_env
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping)
+ table = dialog.findChild(QTableWidget)
+
+ def text(i, j):
+ return table.cellWidget(i, j).text()
+
+ # ham.py: Both original and autosave files exist, mentioned in mapping
+ assert osp.join(orig_dir, 'ham.py') in text(0, 0)
+ assert osp.join(autosave_dir, 'ham.py') in text(0, 1)
+
+ # spam.py: Only autosave file exists, mentioned in mapping
+ assert osp.join(orig_dir, 'spam.py') in text(1, 0)
+ assert 'no longer exists' in text(1, 0)
+ assert osp.join(autosave_dir, 'spam.py') in text(1, 1)
+
+ # eggs.py: Only original files exists, so cannot be recovered
+ # It won't be in the table, so nothing to test
+
+ # cheese.py: Only autosave file exists, not mentioned in mapping
+ assert 'not recorded' in text(2, 0)
+ assert osp.join(autosave_dir, 'cheese.py') in text(2, 1)
+
+ # Thus, there should be three rows in total
+ assert table.rowCount() == 3
+
+
+def test_recoverydialog_exec_if_nonempty_when_empty(qtbot, tmpdir, mocker):
+ """
+ Test that exec_if_nonempty does nothing if autosave dir is empty.
+
+ Specifically, test that it does not `exec_()` the dialog.
+ """
+ dialog = RecoveryDialog(str(tmpdir), {'ham': 'spam'})
+ mocker.patch.object(dialog, 'exec_')
+ assert dialog.exec_if_nonempty() == dialog.Accepted
+ dialog.exec_.assert_not_called()
+
+
+def test_recoverydialog_exec_if_nonempty_when_nonempty(
+ qtbot, recovery_env, mocker):
+ """Test that exec_if_nonempty executes dialog if autosave dir not empty."""
+ orig_dir, autosave_dir, autosave_mapping = recovery_env
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping)
+ mocker.patch.object(dialog, 'exec_', return_value='eggs')
+ assert dialog.exec_if_nonempty() == 'eggs'
+ assert dialog.exec_.called
+
+
+def test_recoverydialog_exec_if_nonempty_when_no_autosave_dir(
+ qtbot, recovery_env, mocker):
+ """
+ Test that exec_if_nonempty does nothing if autosave dir does not exist.
+
+ Specifically, test that it does not `exec_()` the dialog.
+ """
+ orig_dir, autosave_dir, autosave_mapping = recovery_env
+ shutil.rmtree(autosave_dir)
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping)
+ mocker.patch.object(dialog, 'exec_')
+ assert dialog.exec_if_nonempty() == dialog.Accepted
+ dialog.exec_.assert_not_called()
+
+
+def test_recoverydialog_restore_button(qtbot, recovery_env):
+ """
+ Test the `Restore` button in `RecoveryDialog`.
+
+ Test that after pressing the 'Restore' button, the original file is
+ replaced by the autosave file, the latter is removed, and the row in the
+ grid is deactivated.
+ """
+ orig_dir, autosave_dir, autosave_mapping = recovery_env
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping)
+ table = dialog.findChild(QTableWidget)
+ button = table.cellWidget(0, 2).findChildren(QPushButton)[0]
+ button.click()
+ with open(osp.join(orig_dir, 'ham.py')) as f:
+ assert f.read() == 'ham = "autosave"\n'
+ assert not osp.isfile(osp.join(autosave_dir, 'ham.py'))
+ for col in range(table.columnCount()):
+ assert not table.cellWidget(0, col).isEnabled()
+
+
+def test_recoverydialog_restore_when_original_does_not_exist(
+ qtbot, recovery_env):
+ """
+ Test the `Restore` button when the original file does not exist.
+
+ Test that after pressing the 'Restore' button, the autosave file is moved
+ to the location of the original file and the row in the grid is
+ deactivated.
+ """
+ orig_dir, autosave_dir, autosave_mapping = recovery_env
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping)
+ table = dialog.findChild(QTableWidget)
+ button = table.cellWidget(1, 2).findChildren(QPushButton)[0]
+ button.click()
+ with open(osp.join(orig_dir, 'spam.py')) as f:
+ assert f.read() == 'spam = "autosave"\n'
+ assert not osp.isfile(osp.join(autosave_dir, 'spam.py'))
+ for col in range(table.columnCount()):
+ assert not table.cellWidget(1, col).isEnabled()
+
+
+def test_recoverydialog_restore_when_original_not_recorded(
+ qtbot, recovery_env, mocker):
+ """
+ Test the `Restore` button when the original file name is not known.
+
+ Test that after pressing the 'Restore' button, the autosave file is moved
+ to a location specified by the user and the row in the grid is deactivated.
+ """
+ orig_dir, autosave_dir, autosave_mapping = recovery_env
+ new_name = osp.join(orig_dir, 'monty.py')
+ mocker.patch('spyder.plugins.editor.widgets.recover.getsavefilename',
+ return_value=(new_name, 'ignored'))
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping)
+ table = dialog.findChild(QTableWidget)
+ button = table.cellWidget(2, 2).findChildren(QPushButton)[0]
+ button.click()
+ with open(new_name) as f:
+ assert f.read() == 'cheese = "autosave"\n'
+ assert not osp.isfile(osp.join(autosave_dir, 'cheese.py'))
+ for col in range(table.columnCount()):
+ assert not table.cellWidget(2, col).isEnabled()
+
+
+def test_recoverydialog_restore_fallback(qtbot, recovery_env, mocker):
+ """
+ Test fallback for when os.replace() fails when recovering a file.
+
+ Test that after pressing the 'Restore' button, if os.replace() fails,
+ the fallback to copy and delete kicks in and the restore succeeds.
+ Regression test for issue #8631.
+ """
+ orig_dir, autosave_dir, autosave_mapping = recovery_env
+ if not PY2:
+ mocker.patch('spyder.plugins.editor.widgets.recover.os.replace',
+ side_effect=OSError)
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping)
+ table = dialog.findChild(QTableWidget)
+ button = table.cellWidget(0, 2).findChildren(QPushButton)[0]
+ button.click()
+ with open(osp.join(orig_dir, 'ham.py')) as f:
+ assert f.read() == 'ham = "autosave"\n'
+ assert not osp.isfile(osp.join(autosave_dir, 'ham.py'))
+ for col in range(table.columnCount()):
+ assert not table.cellWidget(0, col).isEnabled()
+
+
+def test_recoverydialog_restore_when_error(qtbot, recovery_env, mocker):
+ """
+ Test that errors during a restore action are handled gracefully.
+
+ Test that if an error arises when restoring a file, both the original and
+ the autosave files are kept unchanged, a dialog is displayed, and the row
+ in the grid is not deactivated.
+ """
+ orig_dir, autosave_dir, autosave_mapping = recovery_env
+ if not PY2:
+ mocker.patch('spyder.plugins.editor.widgets.recover.os.replace',
+ side_effect=OSError)
+ mocker.patch('spyder.plugins.editor.widgets.recover.shutil.copy2',
+ side_effect=IOError)
+ mock_QMessageBox = mocker.patch(
+ 'spyder.plugins.editor.widgets.recover.QMessageBox')
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping)
+ table = dialog.findChild(QTableWidget)
+ button = table.cellWidget(0, 2).findChildren(QPushButton)[0]
+ button.click()
+ with open(osp.join(orig_dir, 'ham.py')) as f:
+ assert f.read() == 'ham = "original"\n'
+ with open(osp.join(autosave_dir, 'ham.py')) as f:
+ assert f.read() == 'ham = "autosave"\n'
+ assert mock_QMessageBox.called
+ for col in range(table.columnCount()):
+ assert table.cellWidget(0, col).isEnabled()
+
+
+def test_recoverydialog_accepted_after_all_restored(
+ qtbot, recovery_env, mocker):
+ """
+ Test that the recovery dialog is accepted after all files are restored.
+
+ Click all `Restore` buttons and test that the dialog is accepted
+ afterwards, but not before.
+ """
+ orig_dir, autosave_dir, autosave_mapping = recovery_env
+ new_name = osp.join(orig_dir, 'monty.py')
+ mocker.patch('spyder.plugins.editor.widgets.recover.getsavefilename',
+ return_value=(new_name, 'ignored'))
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping)
+ table = dialog.findChild(QTableWidget)
+ with qtbot.assertNotEmitted(dialog.accepted):
+ for row in range(table.rowCount() - 1):
+ table.cellWidget(row, 2).findChildren(QPushButton)[0].click()
+ with qtbot.waitSignal(dialog.accepted):
+ row = table.rowCount() - 1
+ table.cellWidget(row, 2).findChildren(QPushButton)[0].click()
+
+
+def test_recoverydialog_discard_button(qtbot, recovery_env):
+ """
+ Test the `Discard` button in the recovery dialog.
+
+ Test that after pressing the 'Discard' button, the autosave file is
+ deleted, the original file unchanged, and the row in the grid is
+ deactivated.
+ """
+ orig_dir, autosave_dir, autosave_mapping = recovery_env
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping)
+ table = dialog.findChild(QTableWidget)
+ button = table.cellWidget(0, 2).findChildren(QPushButton)[1]
+ button.click()
+ assert not osp.isfile(osp.join(autosave_dir, 'ham.py'))
+ with open(osp.join(orig_dir, 'ham.py')) as f:
+ assert f.read() == 'ham = "original"\n'
+ for col in range(table.columnCount()):
+ assert not table.cellWidget(0, col).isEnabled()
+
+
+def test_recoverydialog_discard_when_error(qtbot, recovery_env, mocker):
+ """
+ Test that errors during a discard action are handled gracefully.
+
+ Test that if an error arises when discarding a file, both the original and
+ the autosave files are kept unchanged, a dialog is displayed, and the row
+ in the grid is not deactivated.
+ """
+ orig_dir, autosave_dir, autosave_mapping = recovery_env
+ mocker.patch('spyder.plugins.editor.widgets.recover.os.remove',
+ side_effect=OSError)
+ mock_QMessageBox = mocker.patch(
+ 'spyder.plugins.editor.widgets.recover.QMessageBox')
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping)
+ table = dialog.findChild(QTableWidget)
+ button = table.cellWidget(0, 2).findChildren(QPushButton)[1]
+ button.click()
+ with open(osp.join(orig_dir, 'ham.py')) as f:
+ assert f.read() == 'ham = "original"\n'
+ with open(osp.join(autosave_dir, 'ham.py')) as f:
+ assert f.read() == 'ham = "autosave"\n'
+ assert mock_QMessageBox.called
+ for col in range(table.columnCount()):
+ assert table.cellWidget(0, col).isEnabled()
+
+
+def test_recoverydialog_open_button(qtbot, recovery_env):
+ """
+ Test the `Open` button in the recovery dialog.
+
+ Test that after pressing the 'Open' button, `files_to_open` contains
+ the autosave and the original file, and the row in the grid is
+ deactivated.
+ """
+ orig_dir, autosave_dir, autosave_mapping = recovery_env
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping)
+ table = dialog.findChild(QTableWidget)
+ button = table.cellWidget(0, 2).findChildren(QPushButton)[2]
+ button.click()
+ assert dialog.files_to_open == [osp.join(orig_dir, 'ham.py'),
+ osp.join(autosave_dir, 'ham.py')]
+ for col in range(table.columnCount()):
+ assert not table.cellWidget(0, col).isEnabled()
+
+
+def test_recoverydialog_open_when_no_original(qtbot, recovery_env):
+ """
+ Test the `Open` button when the original file is not known.
+
+ Test that when the user requests to open an autosave file for which the
+ original file is not known, `files_to_open` contains only the autosave
+ file.
+ """
+ orig_dir, autosave_dir, autosave_mapping = recovery_env
+ dialog = RecoveryDialog(autosave_dir, autosave_mapping)
+ table = dialog.findChild(QTableWidget)
+ button = table.cellWidget(2, 2).findChildren(QPushButton)[2]
+ button.click()
+ assert dialog.files_to_open == [osp.join(autosave_dir, 'cheese.py')]
+ for col in range(table.columnCount()):
+ assert not table.cellWidget(2, col).isEnabled()
diff --git a/spyder/widgets/tests/test_save.py b/spyder/plugins/editor/widgets/tests/test_save.py
similarity index 81%
rename from spyder/widgets/tests/test_save.py
rename to spyder/plugins/editor/widgets/tests/test_save.py
index 047bc4bded7..fb9b528be56 100644
--- a/spyder/widgets/tests/test_save.py
+++ b/spyder/plugins/editor/widgets/tests/test_save.py
@@ -9,6 +9,7 @@
"""
# Standard library imports
+import os.path as osp
try:
from unittest.mock import Mock
except ImportError:
@@ -18,14 +19,13 @@
import pytest
# Local imports
-from spyder.widgets import editor
+from spyder.plugins.editor.widgets import editor
+from spyder.plugins.outlineexplorer.widgets import OutlineExplorerWidget
-# Helpers
-# --------------------------------
+# ---- Helpers
def add_files(editorstack):
editorstack.close_action.setEnabled(False)
- editorstack.set_introspector(Mock())
editorstack.set_find_widget(Mock())
editorstack.set_io_actions(Mock(), Mock(), Mock(), Mock())
editorstack.new('foo.py', 'utf-8', 'a = 1\n'
@@ -38,12 +38,10 @@ def add_files(editorstack):
editorstack.new(__file__, 'utf-8', text)
-# Qt Test Fixtures
-# --------------------------------
+# ---- Qt Test Fixtures
@pytest.fixture
def base_editor_bot(qtbot):
editor_stack = editor.EditorStack(None, [])
- editor_stack.set_introspector(Mock())
editor_stack.set_find_widget(Mock())
editor_stack.set_io_actions(Mock(), Mock(), Mock(), Mock())
return editor_stack, qtbot
@@ -87,8 +85,7 @@ def editor_splitter_layout_bot(editor_splitter_bot):
return es
-# Tests
-# -------------------------------
+# ---- Tests
@pytest.mark.show_save_dialog
def test_save_if_changed(editor_bot, mocker):
"""Test EditorStack.save_if_changed()."""
@@ -96,6 +93,7 @@ def test_save_if_changed(editor_bot, mocker):
save_if_changed = editor_stack.save_if_changed
mocker.patch.object(editor.QMessageBox, 'exec_')
mocker.patch.object(editor_stack, 'save')
+ mocker.patch.object(editor_stack.autosave, 'remove_autosave_file')
editor_stack.save.return_value = True
# No file changed - returns True.
@@ -104,6 +102,7 @@ def test_save_if_changed(editor_bot, mocker):
editor_stack.data[2].editor.document().setModified(False)
assert save_if_changed() is True
assert not editor_stack.save.called
+ assert not editor_stack.autosave.remove_autosave_file.called
editor_stack.data[0].editor.document().setModified(True)
editor_stack.data[1].editor.document().setModified(True)
editor_stack.data[2].editor.document().setModified(True)
@@ -112,37 +111,45 @@ def test_save_if_changed(editor_bot, mocker):
editor.QMessageBox.exec_.return_value = editor.QMessageBox.Cancel
assert save_if_changed(index=0, cancelable=True) is False
assert not editor_stack.save.called
+ assert not editor_stack.autosave.remove_autosave_file.called
assert editor_stack.tabs.currentIndex() == 0
# Yes button - return value from save().
editor.QMessageBox.exec_.return_value = editor.QMessageBox.Yes
assert save_if_changed(index=0, cancelable=True) is True
assert editor_stack.save.called
+ assert not editor_stack.autosave.remove_autosave_file.called
# YesToAll button - if any save() fails, then return False.
editor_stack.save.reset_mock()
editor.QMessageBox.exec_.return_value = editor.QMessageBox.YesToAll
assert save_if_changed() is True
assert editor_stack.save.call_count == 3
+ assert not editor_stack.autosave.remove_autosave_file.called
- # No button - returns True.
+ # No button - remove autosave, returns True.
editor_stack.save.reset_mock()
editor.QMessageBox.exec_.return_value = editor.QMessageBox.No
assert save_if_changed(index=0, cancelable=True) is True
assert not editor_stack.save.called
+ assert editor_stack.autosave.remove_autosave_file.called
- # NoToAll button - returns True.
+ # NoToAll button - remove autosave 3x, returns True.
editor_stack.save.reset_mock()
+ editor_stack.autosave.remove_autosave_file.reset_mock()
editor.QMessageBox.exec_.return_value = editor.QMessageBox.NoToAll
assert save_if_changed() is True
assert not editor_stack.save.called
+ assert editor_stack.autosave.remove_autosave_file.call_count == 3
# Tempfile doesn't show message box - always calls save().
editor.QMessageBox.exec_.reset_mock()
+ editor_stack.autosave.remove_autosave_file.reset_mock()
editor_stack.set_tempfile_path(__file__)
editor_stack.save.return_value = False
assert save_if_changed(index=2, cancelable=True) is False
assert editor_stack.save.called
+ assert not editor_stack.autosave.remove_autosave_file.called
editor.QMessageBox.exec_.assert_not_called()
@@ -154,6 +161,7 @@ def test_save(editor_bot, mocker):
mocker.patch.object(editor.os.path, 'isfile')
mocker.patch.object(editor.encoding, 'write')
mocker.patch.object(editor_stack, 'save_as')
+ mocker.patch.object(editor_stack.autosave, 'remove_autosave_file')
save_file_saved = editor_stack.file_saved
editor_stack.file_saved = Mock()
editor.encoding.write.return_value = 'utf-8'
@@ -163,6 +171,7 @@ def test_save(editor_bot, mocker):
editor_stack.data[0].newly_created = False
assert save(index=0) is True
assert not editor.encoding.write.called
+ assert not editor_stack.autosave.remove_autosave_file.called
# File modified.
editor_stack.data[0].editor.document().setModified(True)
@@ -173,13 +182,16 @@ def test_save(editor_bot, mocker):
assert save(index=0) == 'save_as_called'
editor_stack.save_as.assert_called_with(index=0)
assert not editor.encoding.write.called
+ assert not editor_stack.autosave.remove_autosave_file.called
# Force save.
editor.os.path.isfile.return_value = True
assert save(index=0, force=True)
assert editor.encoding.write.called == 1
- editor_stack.file_saved.emit.assert_called_with(str(id(editor_stack)),
- 'foo.py', 'foo.py')
+ editor_stack.file_saved.emit.assert_called_with(
+ str(id(editor_stack)), 'foo.py', 'foo.py')
+ editor_stack.autosave.remove_autosave_file.assert_called_with(
+ editor_stack.data[0].filename)
editor_stack.file_saved = save_file_saved
@@ -282,6 +294,38 @@ def test_save_as(editor_bot, mocker):
editor_stack.file_renamed_in_data = save_file_renamed_in_data
+@pytest.mark.show_save_dialog
+def test_save_as_with_outline(editor_bot, mocker, tmpdir):
+ """
+ Test EditorStack.save_as() when the outline explorer is not None.
+
+ Regression test for issue #7754.
+ """
+ editorstack, qtbot = editor_bot
+
+ # Set and assert the initial state.
+ editorstack.tabs.setCurrentIndex(1)
+ assert editorstack.get_current_filename() == 'secondtab.py'
+
+ # Add an outline explorer to the editor stack and refresh it.
+ editorstack.set_outlineexplorer(OutlineExplorerWidget())
+ qtbot.addWidget(editorstack.outlineexplorer)
+ editorstack.refresh()
+
+ # No save name.
+ mocker.patch.object(editorstack, 'select_savename', return_value=None)
+ assert editorstack.save_as() is False
+ assert editorstack.get_filenames() == ['foo.py', 'secondtab.py', __file__]
+
+ # Save secondtab.py as foo2.py in a tmpdir
+ new_filename = osp.join(tmpdir.strpath, 'foo2.py')
+ editorstack.select_savename.return_value = new_filename
+ assert not osp.exists(new_filename)
+ assert editorstack.save_as() is True
+ assert editorstack.get_filenames() == ['foo.py', new_filename, __file__]
+ assert osp.exists(new_filename)
+
+
def test_save_copy_as(editor_bot, mocker):
"""Test EditorStack.save_copy as()."""
editor_stack, qtbot = editor_bot
diff --git a/spyder/plugins/editor/widgets/tests/test_shortcuts.py b/spyder/plugins/editor/widgets/tests/test_shortcuts.py
new file mode 100644
index 00000000000..35bd9518033
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/test_shortcuts.py
@@ -0,0 +1,356 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+
+"""
+Tests for EditorStack keyboard shortcuts.
+"""
+
+# Standard library imports
+import os
+import sys
+try:
+ from unittest.mock import Mock
+except ImportError:
+ from mock import Mock # Python 2
+
+# Third party imports
+import pytest
+from qtpy.QtCore import Qt
+from qtpy.QtWidgets import QApplication
+
+# Local imports
+from spyder.plugins.editor.widgets.editor import EditorStack
+from spyder.config.gui import get_shortcut
+from spyder.plugins.editor.widgets.codeeditor import GoToLineDialog
+
+
+# ---- Qt Test Fixtures
+@pytest.fixture
+def editor_bot(qtbot):
+ """
+ Set up EditorStack with CodeEditors containing some Python code.
+ The cursor is at the empty line below the code.
+ """
+ editorstack = EditorStack(None, [])
+ editorstack.set_find_widget(Mock())
+ editorstack.set_io_actions(Mock(), Mock(), Mock(), Mock())
+ editorstack.close_action.setEnabled(False)
+ editorstack.new('foo.py', 'utf-8', 'Line1\nLine2\nLine3\nLine4')
+
+ qtbot.addWidget(editorstack)
+ editorstack.show()
+ editorstack.go_to_line(1)
+
+ return editorstack, qtbot
+
+
+# ---- Tests
+def test_default_keybinding_values():
+ """
+ Assert that the default Spyder keybindings for the keyboard shorcuts
+ are as expected. This is required because we do not use the keybindings
+ saved in Spyder's config to simulate the user keyboard action, due to
+ the fact that it is complicated to convert and pass reliably a sequence
+ of key strings to qtbot.keyClicks.
+ """
+ # Assert default keybindings.
+ assert get_shortcut('editor', 'start of document') == 'Ctrl+Home'
+ assert get_shortcut('editor', 'end of document') == 'Ctrl+End'
+ assert get_shortcut('editor', 'delete') == 'Del'
+ assert get_shortcut('editor', 'undo') == 'Ctrl+Z'
+ assert get_shortcut('editor', 'redo') == 'Ctrl+Shift+Z'
+ assert get_shortcut('editor', 'copy') == 'Ctrl+C'
+ assert get_shortcut('editor', 'paste') == 'Ctrl+V'
+ assert get_shortcut('editor', 'cut') == 'Ctrl+X'
+ assert get_shortcut('editor', 'select all') == 'Ctrl+A'
+ assert get_shortcut('editor', 'delete line') == 'Ctrl+D'
+ assert get_shortcut('editor', 'transform to lowercase') == 'Ctrl+U'
+ assert get_shortcut('editor', 'transform to uppercase') == 'Ctrl+Shift+U'
+ assert get_shortcut('editor', 'go to line') == 'Ctrl+L'
+ assert get_shortcut('editor', 'next word') == 'Ctrl+Right'
+ assert get_shortcut('editor', 'previous word') == 'Ctrl+Left'
+
+
+@pytest.mark.skipif(
+ sys.platform.startswith('linux') and os.environ.get('CI') is not None,
+ reason="It fails on Linux due to the lack of a proper X server.")
+def test_start_and_end_of_document_shortcuts(editor_bot):
+ """
+ Test that the start of document and end of document shortcut are working
+ as expected.
+ """
+ editorstack, qtbot = editor_bot
+ editor = editorstack.get_current_editor()
+
+ # Assert initial state.
+ assert editor.get_cursor_line_column() == (0, 0)
+
+ # Go to the end of the document.
+ qtbot.keyClick(editor, Qt.Key_End, modifier=Qt.ControlModifier)
+ assert editor.get_cursor_line_column() == (4, 0)
+
+ # Go to the start of the document.
+ qtbot.keyClick(editor, Qt.Key_Home, modifier=Qt.ControlModifier)
+ assert editor.get_cursor_line_column() == (0, 0)
+
+
+@pytest.mark.skipif(
+ sys.platform.startswith('linux') and os.environ.get('CI') is not None,
+ reason="It fails on Linux due to the lack of a proper X server.")
+def test_del_undo_redo_shortcuts(editor_bot):
+ """
+ Test that the undo and redo keyboard shortcuts are working as expected
+ with the default Spyder keybindings.
+
+ Regression test for issue #7743.
+ """
+ editorstack, qtbot = editor_bot
+ editor = editorstack.get_current_editor()
+
+ # Delete the first character of the first line.
+ qtbot.keyClick(editor, Qt.Key_Delete)
+ assert editor.toPlainText() == 'ine1\nLine2\nLine3\nLine4\n'
+
+ # Undo the last action with Ctrl+Z.
+ qtbot.keyClick(editor, Qt.Key_Z, modifier=Qt.ControlModifier)
+ assert editor.toPlainText() == 'Line1\nLine2\nLine3\nLine4\n'
+
+ # Redo the last action with Ctrl+Shift+Z .
+ qtbot.keyClick(editor, Qt.Key_Z,
+ modifier=Qt.ControlModifier | Qt.ShiftModifier)
+ assert editor.toPlainText() == 'ine1\nLine2\nLine3\nLine4\n'
+
+ # Undo the last action again with Ctrl+Z.
+ qtbot.keyClick(editor, Qt.Key_Z, modifier=Qt.ControlModifier)
+ assert editor.toPlainText() == 'Line1\nLine2\nLine3\nLine4\n'
+
+
+@pytest.mark.skipif(
+ sys.platform.startswith('linux') and os.environ.get('CI') is not None,
+ reason="It fails on Linux due to the lack of a proper X server.")
+def test_copy_cut_paste_shortcuts(editor_bot):
+ """
+ Test that the copy, cut, and paste keyboard shortcuts are working as
+ expected with the default Spyder keybindings.
+ """
+ editorstack, qtbot = editor_bot
+ editor = editorstack.get_current_editor()
+ QApplication.clipboard().clear()
+
+ # Select and Copy the first line in the editor.
+ qtbot.keyClick(editor, Qt.Key_End, modifier=Qt.ShiftModifier)
+ assert editor.get_selected_text() == 'Line1'
+
+ qtbot.keyClick(editor, Qt.Key_C, modifier=Qt.ControlModifier)
+ assert QApplication.clipboard().text() == 'Line1'
+
+ # Paste the selected text.
+ qtbot.keyClick(editor, Qt.Key_Home)
+ qtbot.keyClick(editor, Qt.Key_V, modifier=Qt.ControlModifier)
+ assert editor.toPlainText() == 'Line1Line1\nLine2\nLine3\nLine4\n'
+
+ # Select and Cut the first line in the editor.
+ qtbot.keyClick(editor, Qt.Key_Home)
+ qtbot.keyClick(editor, Qt.Key_End, modifier=Qt.ShiftModifier)
+ assert editor.get_selected_text() == 'Line1Line1'
+
+ qtbot.keyClick(editor, Qt.Key_X, modifier=Qt.ControlModifier)
+ assert QApplication.clipboard().text() == 'Line1Line1'
+ assert editor.toPlainText() == '\nLine2\nLine3\nLine4\n'
+
+
+@pytest.mark.skipif(
+ sys.platform.startswith('linux') and os.environ.get('CI') is not None,
+ reason="It fails on Linux due to the lack of a proper X server.")
+def test_select_all_shortcut(editor_bot):
+ """
+ Test that the select all keyboard shortcut is working as
+ expected with the default Spyder keybindings.
+ """
+ editorstack, qtbot = editor_bot
+ editor = editorstack.get_current_editor()
+
+ # Select all the text in the editor.
+ qtbot.keyClick(editor, Qt.Key_A, modifier=Qt.ControlModifier)
+ assert editor.get_selected_text() == 'Line1\nLine2\nLine3\nLine4\n'
+
+
+@pytest.mark.skipif(
+ sys.platform.startswith('linux') and os.environ.get('CI') is not None,
+ reason="It fails on Linux due to the lack of a proper X server.")
+@pytest.mark.no_xvfb
+def test_delete_line_shortcut(editor_bot):
+ """
+ Test that the delete line keyboard shortcut is working as
+ expected with the default Spyder keybindings.
+ """
+ editorstack, qtbot = editor_bot
+ editor = editorstack.get_current_editor()
+
+ # Delete the second line in the editor.
+ editor.go_to_line(2)
+ qtbot.keyClick(editor, Qt.Key_D, modifier=Qt.ControlModifier)
+ assert editor.toPlainText() == 'Line1\nLine3\nLine4\n'
+
+
+@pytest.mark.skipif(
+ sys.platform.startswith('linux') and os.environ.get('CI') is not None,
+ reason="It fails on Linux due to the lack of a proper X server.")
+@pytest.mark.no_xvfb
+def test_go_to_line_shortcut(editor_bot, mocker):
+ """
+ Test that the go to line keyboard shortcut is working
+ as expected with the default Spyder keybindings.
+ """
+ editorstack, qtbot = editor_bot
+ editor = editorstack.get_current_editor()
+ qtbot.keyClick(editor, Qt.Key_Home, modifier=Qt.ControlModifier)
+
+ # Go to line 3.
+ mocker.patch.object(GoToLineDialog, 'exec_', return_value=True)
+ mocker.patch.object(GoToLineDialog, 'get_line_number', return_value=3)
+ qtbot.keyClick(editor, Qt.Key_L, modifier=Qt.ControlModifier)
+ assert editor.get_cursor_line_column() == (2, 0)
+
+
+@pytest.mark.skipif(
+ sys.platform.startswith('linux') and os.environ.get('CI') is not None,
+ reason="It fails on Linux due to the lack of a proper X server.")
+@pytest.mark.no_xvfb
+def test_transform_to_lowercase_shortcut(editor_bot):
+ """
+ Test that the transform to lowercase shorcut is working as expected with
+ the default Spyder keybindings.
+ """
+ editorstack, qtbot = editor_bot
+ editor = editorstack.get_current_editor()
+
+ # Transform all the text to lowercase.
+ qtbot.keyClick(editor, Qt.Key_A, modifier=Qt.ControlModifier)
+ qtbot.keyClick(editor, Qt.Key_U, modifier=Qt.ControlModifier)
+ assert editor.toPlainText() == 'line1\nline2\nline3\nline4\n'
+
+
+@pytest.mark.skipif(
+ sys.platform.startswith('linux') and os.environ.get('CI') is not None,
+ reason="It fails on Linux due to the lack of a proper X server.")
+@pytest.mark.no_xvfb
+def test_transform_to_uppercase_shortcut(editor_bot):
+ """
+ Test that the transform to uppercase shorcuts is working as expected with
+ the default Spyder keybindings.
+ """
+ editorstack, qtbot = editor_bot
+ editor = editorstack.get_current_editor()
+
+ # Transform all the text to uppercase.
+ qtbot.keyClick(editor, Qt.Key_A, modifier=Qt.ControlModifier)
+ qtbot.keyClick(editor, Qt.Key_U,
+ modifier=Qt.ControlModifier | Qt.ShiftModifier)
+ assert editor.toPlainText() == 'LINE1\nLINE2\nLINE3\nLINE4\n'
+
+
+@pytest.mark.skipif(
+ sys.platform.startswith('linux') and os.environ.get('CI') is not None,
+ reason="It fails on Linux due to the lack of a proper X server.")
+@pytest.mark.no_xvfb
+def test_next_and_previous_word_shortcuts(editor_bot):
+ """
+ Test that the next word and previous word shortcuts are working as
+ expected with the default Spyder keybindings.
+ """
+ editorstack, qtbot = editor_bot
+ editor = editorstack.get_current_editor()
+
+ # Go to the next word 3 times.
+ assert editor.get_cursor_line_column() == (0, 0)
+ qtbot.keyClick(editor, Qt.Key_Right, modifier=Qt.ControlModifier)
+ assert editor.get_cursor_line_column() == (0, 5)
+ qtbot.keyClick(editor, Qt.Key_Right, modifier=Qt.ControlModifier)
+ assert editor.get_cursor_line_column() == (1, 0)
+ qtbot.keyClick(editor, Qt.Key_Right, modifier=Qt.ControlModifier)
+ assert editor.get_cursor_line_column() == (1, 5)
+
+ # Go to the previous word 3 times.
+ qtbot.keyClick(editor, Qt.Key_Left, modifier=Qt.ControlModifier)
+ assert editor.get_cursor_line_column() == (1, 0)
+ qtbot.keyClick(editor, Qt.Key_Left, modifier=Qt.ControlModifier)
+ assert editor.get_cursor_line_column() == (0, 5)
+ qtbot.keyClick(editor, Qt.Key_Left, modifier=Qt.ControlModifier)
+ assert editor.get_cursor_line_column() == (0, 0)
+
+
+@pytest.mark.skipif(sys.platform == 'darwin', reason="Not valid in macOS")
+def test_builtin_shift_del_and_ins(editor_bot):
+ """
+ Test that the builtin key sequences Ctrl+Ins, Shit+Del and Shift+Ins result
+ in copy, cut and paste actions in Windows and Linux.
+
+ Regression test for issue #5035, #4947, and #5973.
+ """
+ editorstack, qtbot = editor_bot
+ editor = editorstack.get_current_editor()
+ QApplication.clipboard().clear()
+
+ # Select the first line of the editor.
+ qtbot.keyClick(editor, Qt.Key_End, modifier=Qt.ShiftModifier)
+ assert editor.get_selected_text() == 'Line1'
+
+ # Copy the selection with Ctrl+Ins.
+ qtbot.keyClick(editor, Qt.Key_Insert, modifier=Qt.ControlModifier)
+ assert QApplication.clipboard().text() == 'Line1'
+
+ # Paste the copied text at the end of the line with Shift+Ins.
+ qtbot.keyClick(editor, Qt.Key_End)
+ qtbot.keyClick(editor, Qt.Key_Insert, modifier=Qt.ShiftModifier)
+ assert editor.toPlainText() == 'Line1Line1\nLine2\nLine3\nLine4\n'
+
+ # Select the second line in the editor again.
+ qtbot.keyClick(editor, Qt.Key_Home, modifier=Qt.ShiftModifier)
+ assert editor.get_selected_text() == 'Line1Line1'
+
+ # Cut the selection with Shift+Del.
+ qtbot.keyClick(editor, Qt.Key_Delete, modifier=Qt.ShiftModifier)
+ assert QApplication.clipboard().text() == 'Line1Line1'
+ assert editor.toPlainText() == '\nLine2\nLine3\nLine4\n'
+
+
+@pytest.mark.skipif(os.name != 'nt', reason='Only valid in Windows system')
+def test_builtin_undo_redo(editor_bot):
+ """
+ Test that the builtin key sequence Alt+Backspace, Ctrl+Y and
+ Alt+Shift+Backspace result in, respectively, an undo, redo and redo action
+ in Windows.
+ """
+ editorstack, qtbot = editor_bot
+ editor = editorstack.get_current_editor()
+
+ # Write something on a new line.
+ qtbot.keyClicks(editor, 'Something')
+ qtbot.keyClick(editor, Qt.Key_Return)
+ assert editor.toPlainText() == 'Something\nLine1\nLine2\nLine3\nLine4\n'
+
+ # Undo the last action with Alt+Backspace.
+ qtbot.keyClick(editor, Qt.Key_Backspace, modifier=Qt.AltModifier)
+ assert editor.toPlainText() == 'SomethingLine1\nLine2\nLine3\nLine4\n'
+
+ # Undo the second to last action with Alt+Backspace.
+ qtbot.keyClick(editor, Qt.Key_Backspace, modifier=Qt.AltModifier)
+ assert editor.toPlainText() == 'Line1\nLine2\nLine3\nLine4\n'
+
+ # Redo the second to last action with Alt+Shift+Backspace.
+ qtbot.keyClick(editor, Qt.Key_Backspace,
+ modifier=Qt.AltModifier | Qt.ShiftModifier)
+ assert editor.toPlainText() == 'SomethingLine1\nLine2\nLine3\nLine4\n'
+
+ # Redo the last action with Ctrl+Y.
+ qtbot.keyClick(editor, Qt.Key_Y, modifier=Qt.ControlModifier)
+ assert editor.toPlainText() == 'Something\nLine1\nLine2\nLine3\nLine4\n'
+
+
+if __name__ == "__main__":
+ import os
+ pytest.main(['-x', os.path.basename(__file__), '-vv', '-rw'])
diff --git a/spyder/plugins/editor/widgets/tests/test_status.py b/spyder/plugins/editor/widgets/tests/test_status.py
new file mode 100644
index 00000000000..c35d6521383
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/test_status.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+
+"""
+Tests for status.py
+"""
+
+# Test library imports
+import pytest
+
+# Thrid party imports
+from qtpy.QtWidgets import QMainWindow
+
+# Local imports
+from spyder.plugins.editor.widgets.status import (CursorPositionStatus,
+ EncodingStatus, EOLStatus,
+ ReadWriteStatus, VCSStatus)
+
+
+@pytest.fixture
+def status_bar(qtbot):
+ """Set up StatusBarWidget."""
+ win = QMainWindow()
+ win.setWindowTitle("Status widgets test")
+ win.resize(900, 300)
+ statusbar = win.statusBar()
+ qtbot.addWidget(win)
+ return (win, statusbar)
+
+
+def test_status_bar(status_bar, qtbot):
+ """Run StatusBarWidget."""
+ win, statusbar = status_bar
+ swidgets = []
+ for klass in (ReadWriteStatus, EOLStatus, EncodingStatus,
+ CursorPositionStatus, VCSStatus):
+ swidget = klass(win, statusbar)
+ swidgets.append(swidget)
+ assert win
+ assert len(swidgets) == 5
+
+
+if __name__ == "__main__":
+ pytest.main()
diff --git a/spyder/plugins/editor/widgets/tests/test_warnings.py b/spyder/plugins/editor/widgets/tests/test_warnings.py
new file mode 100644
index 00000000000..73951af2533
--- /dev/null
+++ b/spyder/plugins/editor/widgets/tests/test_warnings.py
@@ -0,0 +1,242 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+
+"""Tests for editor codeanalysis warnings."""
+
+# Stdlib imports
+import os
+
+# Third party imports
+import pytest
+from qtpy.QtCore import Qt
+
+# Local imports
+from spyder.config.main import CONF
+
+
+TEXT = ("def some_function():\n" # D100, D103: Missing docstring
+ " \n" # W293 trailing spaces
+ " a = 1 # a comment\n" # E261 two spaces before inline comment
+ "\n"
+ " a += s\n" # Undefined variable s
+ " return a\n")
+
+
+@pytest.mark.slow
+@pytest.mark.second
+def test_ignore_warnings(qtbot, lsp_codeeditor):
+ """Test that the editor is ignoring some warnings."""
+ editor, manager = lsp_codeeditor
+
+ # Set text in editor
+ editor.set_text(TEXT)
+
+ CONF.set('lsp-server', 'pydocstyle/ignore', 'D100')
+ CONF.set('lsp-server', 'pycodestyle/ignore', 'E261')
+ manager.update_server_list()
+ qtbot.wait(2000)
+
+ # Notify changes
+ with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
+ editor.document_did_change()
+
+ # Get current warnings
+ warnings = editor.get_current_warnings()
+
+ expected = [['D103: Missing docstring in public function', 1],
+ ['W293 blank line contains whitespace', 2],
+ ["undefined name 's'", 5]]
+
+ CONF.set('lsp-server', 'pydocstyle/ignore', '')
+ CONF.set('lsp-server', 'pycodestyle/ignore', '')
+ manager.update_server_list()
+ qtbot.wait(2000)
+
+ assert warnings == expected
+
+
+@pytest.mark.slow
+@pytest.mark.second
+def test_adding_warnings(qtbot, lsp_codeeditor):
+ """Test that warnings are saved in the editor blocks."""
+ editor, _ = lsp_codeeditor
+
+ # Set text in editor
+ editor.set_text(TEXT)
+
+ # Notify changes
+ with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
+ editor.document_did_change()
+
+ block = editor.textCursor().block()
+ line_count = editor.document().blockCount()
+
+ warnings = []
+ for i in range(line_count):
+ data = block.userData()
+ if data:
+ for analysis in data.code_analysis:
+ warnings.append((i+1, analysis[-1]))
+ block = block.next()
+
+ expected_warnings = {1: ['D100', 'D103'],
+ 2: ['W293'],
+ 3: ['E261'],
+ 5: ['undefined name']}
+ for i, warning in warnings:
+ assert any([expected in warning for expected in expected_warnings[i]])
+
+
+@pytest.mark.slow
+@pytest.mark.second
+def test_move_warnings(qtbot, lsp_codeeditor):
+ """Test that moving to next/previous warnings is working."""
+ editor, _ = lsp_codeeditor
+
+ # Set text in editor
+ editor.set_text(TEXT)
+
+ # Notify changes
+ with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
+ editor.document_did_change()
+
+ # Move between warnings
+ editor.go_to_next_warning()
+ assert 2 == editor.get_cursor_line_number()
+
+ editor.go_to_next_warning()
+ assert 3 == editor.get_cursor_line_number()
+
+ editor.go_to_previous_warning()
+ assert 2 == editor.get_cursor_line_number()
+
+ # Test cycling behaviour
+ editor.go_to_line(5)
+ editor.go_to_next_warning()
+ assert 1 == editor.get_cursor_line_number()
+
+ editor.go_to_previous_warning()
+ assert 5 == editor.get_cursor_line_number()
+
+
+@pytest.mark.slow
+@pytest.mark.second
+def test_get_warnings(qtbot, lsp_codeeditor):
+ """Test that the editor is returning the right list of warnings."""
+ editor, _ = lsp_codeeditor
+
+ # Set text in editor
+ editor.set_text(TEXT)
+
+ # Notify changes
+ with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
+ editor.document_did_change()
+
+ # Get current warnings
+ warnings = editor.get_current_warnings()
+
+ expected = [['D100: Missing docstring in public module', 1],
+ ['D103: Missing docstring in public function', 1],
+ ['W293 blank line contains whitespace', 2],
+ ['E261 at least two spaces before inline comment', 3],
+ ["undefined name 's'", 5]]
+
+ assert warnings == expected
+
+
+@pytest.mark.slow
+@pytest.mark.second
+def test_update_warnings_after_delete_line(qtbot, lsp_codeeditor):
+ """
+ Test that code style warnings are correctly updated after deleting a line
+ in the Editor.
+
+ Regression test for #9299.
+ """
+ editor, _ = lsp_codeeditor
+ editor.set_text(TEXT)
+
+ # Notify changes.
+ with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
+ editor.document_did_change()
+
+ # Delete the blank line that is causing the W293 warning on line 2.
+ editor.go_to_line(2)
+ editor.delete_line()
+
+ # Wait for the lsp_response_signal.
+ qtbot.waitSignal(editor.lsp_response_signal, timeout=30000)
+
+ # Assert that the W293 warning is gone.
+ expected = [['D100: Missing docstring in public module', 1],
+ ['D103: Missing docstring in public function', 1],
+ ['E261 at least two spaces before inline comment', 2],
+ ["undefined name 's'", 4]]
+ assert editor.get_current_warnings() == expected
+
+
+@pytest.mark.slow
+@pytest.mark.second
+def test_update_warnings_after_closequotes(qtbot, lsp_codeeditor):
+ """
+ Test that code errors are correctly updated after activating closequotes
+ in the Editor.
+
+ Regression test for #9323.
+ """
+ editor, _ = lsp_codeeditor
+ editor.textCursor().insertText("print('test)\n")
+
+ expected = [['EOL while scanning string literal', 1]]
+
+ # Notify changes.
+ with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
+ editor.document_did_change()
+
+ assert editor.get_current_warnings() == expected
+
+ # Wait for the lsp_response_signal.
+ with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
+ # Add a single quote to fix the error
+ editor.move_cursor(-2)
+ qtbot.keyPress(editor, Qt.Key_Apostrophe)
+ assert editor.toPlainText() == "print('test')\n"
+
+ # Assert that the error is gone.
+ expected = [['D100: Missing docstring in public module', 1]]
+ assert editor.get_current_warnings() == expected
+
+
+@pytest.mark.slow
+@pytest.mark.second
+def test_update_warnings_after_closebrackets(qtbot, lsp_codeeditor):
+ """
+ Test that code errors are correctly updated after activating closebrackets
+ in the Editor.
+
+ Regression test for #9323.
+ """
+ editor, _ = lsp_codeeditor
+ editor.textCursor().insertText("print('test'\n")
+
+ expected = [['unexpected EOF while parsing', 1]]
+
+ # Notify changes.
+ with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
+ editor.document_did_change()
+
+ assert editor.get_current_warnings() == expected
+
+ # Wait for the lsp_response_signal.
+ with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000):
+ # Add a bracket to fix the error
+ editor.move_cursor(-1)
+ qtbot.keyPress(editor, Qt.Key_ParenRight)
+ assert editor.toPlainText() == "print('test')\n"
+
+ # Assert that the error is gone.
+ expected = [['D100: Missing docstring in public module', 1]]
+ assert editor.get_current_warnings() == expected
diff --git a/spyder/plugins/explorer.py b/spyder/plugins/explorer.py
deleted file mode 100644
index 41812da1648..00000000000
--- a/spyder/plugins/explorer.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright © Spyder Project Contributors
-# Licensed under the terms of the MIT License
-# (see spyder/__init__.py for details)
-
-"""Files and Directories Explorer Plugin"""
-
-# pylint: disable=C0103
-# pylint: disable=R0903
-# pylint: disable=R0911
-# pylint: disable=R0201
-
-# Standard library imports
-import os.path as osp
-
-# Third party imports
-from qtpy.QtWidgets import QVBoxLayout
-
-# Local imports
-from spyder.config.base import _
-from spyder.api.plugins import SpyderPluginWidget
-from spyder.utils.qthelpers import add_actions, MENU_SEPARATOR
-from spyder.widgets.explorer import ExplorerWidget
-
-class Explorer(SpyderPluginWidget):
- """File and Directories Explorer DockWidget."""
-
- CONF_SECTION = 'explorer'
-
- def __init__(self, parent=None):
- """Initialization."""
- SpyderPluginWidget.__init__(self, parent)
-
- # Initialize plugin
- self.initialize_plugin()
-
- self.fileexplorer = ExplorerWidget(
- self,
- name_filters=self.get_option('name_filters'),
- show_all=self.get_option('show_all'),
- show_icontext=self.get_option('show_icontext'),
- options_button=self.options_button)
-
- layout = QVBoxLayout()
- layout.addWidget(self.fileexplorer)
- self.setLayout(layout)
-
- #------ SpyderPluginWidget API ---------------------------------------------
- def get_plugin_title(self):
- """Return widget title"""
- return _("File explorer")
-
- def get_focus_widget(self):
- """
- Return the widget to give focus to when
- this plugin's dockwidget is raised on top-level
- """
- return self.fileexplorer.treewidget
-
- def get_plugin_actions(self):
- """Return a list of actions related to plugin"""
- return []
-
- def register_plugin(self):
- """Register plugin in Spyder's main window"""
- ipyconsole = self.main.ipyconsole
- treewidget = self.fileexplorer.treewidget
- undock = [MENU_SEPARATOR, self.undock_action]
-
- self.main.add_dockwidget(self)
- self.fileexplorer.sig_open_file.connect(self.main.open_file)
- add_actions(self.fileexplorer.menu, undock)
-
- treewidget.sig_edit.connect(self.main.editor.load)
- treewidget.sig_removed.connect(self.main.editor.removed)
- treewidget.sig_removed_tree.connect(self.main.editor.removed_tree)
- treewidget.sig_renamed.connect(self.main.editor.renamed)
- treewidget.sig_renamed_tree.connect(self.main.editor.renamed_tree)
- treewidget.sig_create_module.connect(self.main.editor.new)
- treewidget.sig_new_file.connect(lambda t: self.main.editor.new(text=t))
- treewidget.sig_open_interpreter.connect(
- ipyconsole.create_client_from_path)
- treewidget.redirect_stdio.connect(
- self.main.redirect_internalshell_stdio)
- treewidget.sig_run.connect(
- lambda fname:
- ipyconsole.run_script(fname, osp.dirname(fname), '', False, False,
- False, True))
- treewidget.sig_open_dir.connect(
- lambda dirname:
- self.main.workingdirectory.chdir(dirname,
- refresh_explorer=False,
- refresh_console=True))
-
- self.main.editor.open_dir.connect(self.chdir)
-
- # Signal "set_explorer_cwd(QString)" will refresh only the
- # contents of path passed by the signal in explorer:
- self.main.workingdirectory.set_explorer_cwd.connect(
- lambda directory: self.refresh_plugin(new_path=directory,
- force_current=True))
-
- def refresh_plugin(self, new_path=None, force_current=True):
- """Refresh explorer widget"""
- self.fileexplorer.treewidget.update_history(new_path)
- self.fileexplorer.treewidget.refresh(new_path,
- force_current=force_current)
-
- def closing_plugin(self, cancelable=False):
- """Perform actions before parent main window is closed"""
- return True
-
- #------ Public API ---------------------------------------------------------
- def chdir(self, directory):
- """Set working directory"""
- self.fileexplorer.treewidget.chdir(directory)
diff --git a/spyder/plugins/explorer/__init__.py b/spyder/plugins/explorer/__init__.py
new file mode 100644
index 00000000000..94415a2fda6
--- /dev/null
+++ b/spyder/plugins/explorer/__init__.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+spyder.plugins.explorer
+=======================
+
+Files and Directories Explorer Plugin.
+"""
diff --git a/spyder/plugins/explorer/plugin.py b/spyder/plugins/explorer/plugin.py
new file mode 100644
index 00000000000..66ef174eb64
--- /dev/null
+++ b/spyder/plugins/explorer/plugin.py
@@ -0,0 +1,129 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Files and Directories Explorer Plugin"""
+
+# pylint: disable=C0103
+# pylint: disable=R0903
+# pylint: disable=R0911
+# pylint: disable=R0201
+
+# Standard library imports
+import os.path as osp
+
+# Third party imports
+from qtpy.QtWidgets import QVBoxLayout
+
+# Local imports
+from spyder.config.base import _
+from spyder.api.plugins import SpyderPluginWidget
+from spyder.utils.qthelpers import add_actions, MENU_SEPARATOR
+from spyder.plugins.explorer.widgets import ExplorerWidget
+
+class Explorer(SpyderPluginWidget):
+ """File and Directories Explorer DockWidget."""
+
+ CONF_SECTION = 'explorer'
+
+ def __init__(self, parent=None):
+ """Initialization."""
+ SpyderPluginWidget.__init__(self, parent)
+
+ self.fileexplorer = ExplorerWidget(
+ self,
+ name_filters=self.get_option('name_filters'),
+ show_all=self.get_option('show_all'),
+ show_icontext=self.get_option('show_icontext'),
+ options_button=self.options_button,
+ single_click_to_open=self.get_option('single_click_to_open'),
+ )
+
+ # Initialize plugin
+ self.initialize_plugin()
+
+ layout = QVBoxLayout()
+ layout.addWidget(self.fileexplorer)
+ self.setLayout(layout)
+
+ self.fileexplorer.sig_option_changed.connect(
+ self._update_config_options)
+
+ #------ SpyderPluginWidget API ---------------------------------------------
+ def get_plugin_title(self):
+ """Return widget title"""
+ return _("Files")
+
+ def get_focus_widget(self):
+ """
+ Return the widget to give focus to when
+ this plugin's dockwidget is raised on top-level
+ """
+ return self.fileexplorer.treewidget
+
+ def get_plugin_actions(self):
+ """Return a list of actions related to plugin"""
+ return self.fileexplorer.treewidget.common_actions
+
+ def register_plugin(self):
+ """Register plugin in Spyder's main window"""
+ ipyconsole = self.main.ipyconsole
+ treewidget = self.fileexplorer.treewidget
+
+ self.main.add_dockwidget(self)
+ self.fileexplorer.sig_open_file.connect(self.main.open_file)
+ self.register_widget_shortcuts(treewidget)
+
+ treewidget.sig_edit.connect(self.main.editor.load)
+ treewidget.sig_removed.connect(self.main.editor.removed)
+ treewidget.sig_removed_tree.connect(self.main.editor.removed_tree)
+ treewidget.sig_renamed.connect(self.main.editor.renamed)
+ treewidget.sig_renamed_tree.connect(self.main.editor.renamed_tree)
+ treewidget.sig_create_module.connect(self.main.editor.new)
+ treewidget.sig_new_file.connect(lambda t: self.main.editor.new(text=t))
+ treewidget.sig_open_interpreter.connect(
+ ipyconsole.create_client_from_path)
+ treewidget.redirect_stdio.connect(
+ self.main.redirect_internalshell_stdio)
+ treewidget.sig_run.connect(
+ lambda fname:
+ ipyconsole.run_script(fname, osp.dirname(fname), '', False, False,
+ False, True))
+ treewidget.sig_open_dir.connect(
+ lambda dirname:
+ self.main.workingdirectory.chdir(dirname,
+ refresh_explorer=False,
+ refresh_console=True))
+
+ self.main.editor.open_dir.connect(self.chdir)
+
+ # Signal "set_explorer_cwd(QString)" will refresh only the
+ # contents of path passed by the signal in explorer:
+ self.main.workingdirectory.set_explorer_cwd.connect(
+ lambda directory: self.refresh_plugin(new_path=directory,
+ force_current=True))
+
+ def refresh_plugin(self, new_path=None, force_current=True):
+ """Refresh explorer widget"""
+ self.fileexplorer.treewidget.update_history(new_path)
+ self.fileexplorer.treewidget.refresh(new_path,
+ force_current=force_current)
+
+ def closing_plugin(self, cancelable=False):
+ """Perform actions before parent main window is closed"""
+ return True
+
+ def on_first_registration(self):
+ """Action to be performed on first plugin registration"""
+ self.main.tabify_plugins(self.main.variableexplorer, self)
+
+ #------ Public API ---------------------------------------------------------
+ def chdir(self, directory):
+ """Set working directory"""
+ self.fileexplorer.treewidget.chdir(directory)
+
+ def _update_config_options(self, option, value):
+ """Update the config options of the explorer to make them permanent."""
+ self.set_option(option, value)
diff --git a/spyder/plugins/explorer/tests/__init__.py b/spyder/plugins/explorer/tests/__init__.py
new file mode 100644
index 00000000000..9ac07f46de1
--- /dev/null
+++ b/spyder/plugins/explorer/tests/__init__.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Explorer Tests"""
diff --git a/spyder/plugins/explorer/tests/conftest.py b/spyder/plugins/explorer/tests/conftest.py
new file mode 100644
index 00000000000..65448caf2ea
--- /dev/null
+++ b/spyder/plugins/explorer/tests/conftest.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+
+"""
+Fixture to create files folders.
+"""
+
+# Standard imports
+import os
+import os.path as osp
+
+# Third party imports
+import pytest
+
+# Local imports
+from spyder.py3compat import to_text_string
+
+
+@pytest.fixture(params=[['script.py', 'dir1/dir2/dir3/dir4'],
+ ['script.py', 'script1.py', 'testdir/dir1/script2.py'],
+ ['subdir/innerdir/dir3/text.txt', 'dir1/dir2/dir3',
+ 'dir1/dir2/dir3/file.txt',
+ 'dir1/dir2/dir3/dir4/python.py']])
+def create_folders_files(tmpdir, request):
+ """A project directory with dirs and files for testing."""
+ project_dir = to_text_string(tmpdir.mkdir('project'))
+ destination_dir = to_text_string(tmpdir.mkdir('destination'))
+ top_folder = osp.join(project_dir, 'top_folder_in_proj')
+ if not osp.exists(top_folder):
+ os.mkdir(top_folder)
+ list_paths = []
+ for item in request.param:
+ if osp.splitext(item)[1]:
+ if osp.split(item)[0]:
+ dirs, fname = osp.split(item)
+ dirpath = osp.join(top_folder, dirs)
+ if not osp.exists(dirpath):
+ os.makedirs(dirpath)
+ item_path = osp.join(dirpath, fname)
+ else:
+ item_path = osp.join(top_folder, item)
+ else:
+ dirpath = osp.join(top_folder, item)
+ if not osp.exists(dirpath):
+ os.makedirs(dirpath)
+ item_path = dirpath
+ if not osp.isdir(item_path):
+ with open(item_path, 'w') as fh:
+ fh.write("File Path:\n" + str(item_path).replace(os.sep, '/'))
+ list_paths.append(item_path)
+ return list_paths, project_dir, destination_dir, top_folder
diff --git a/spyder/plugins/explorer/tests/test_explorer.py b/spyder/plugins/explorer/tests/test_explorer.py
new file mode 100644
index 00000000000..38fe5b56778
--- /dev/null
+++ b/spyder/plugins/explorer/tests/test_explorer.py
@@ -0,0 +1,175 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+
+"""
+Tests for explorer.py
+"""
+
+# Standard imports
+import os
+import os.path as osp
+
+# Third party imports
+import pytest
+from qtpy.QtCore import Qt, QPoint, QEvent
+from qtpy.QtGui import QMouseEvent
+from qtpy.QtWidgets import QApplication
+from qtpy.QtWidgets import QMessageBox
+
+# Local imports
+from spyder.plugins.explorer.widgets import (FileExplorerTest,
+ ProjectExplorerTest)
+from spyder.plugins.projects.widgets.explorer import ProjectExplorerTest as ProjectExplorerTest2
+
+
+@pytest.fixture
+def file_explorer(qtbot):
+ """Set up FileExplorerTest."""
+ widget = FileExplorerTest()
+ qtbot.addWidget(widget)
+ return widget
+
+
+@pytest.fixture
+def project_explorer(qtbot):
+ """Set up FileExplorerTest."""
+ widget = ProjectExplorerTest()
+ qtbot.addWidget(widget)
+ return widget
+
+
+@pytest.fixture(params=[FileExplorerTest, ProjectExplorerTest2])
+def explorer_with_files(qtbot, create_folders_files, request):
+ """Setup Project/File Explorer widget."""
+ cb = QApplication.clipboard()
+ paths, project_dir, destination_dir, top_folder = create_folders_files
+ explorer_orig = request.param(directory=project_dir)
+ explorer_dest = request.param(directory=destination_dir)
+ qtbot.addWidget(explorer_orig)
+ qtbot.addWidget(explorer_dest)
+ return explorer_orig, explorer_dest, paths, top_folder, cb
+
+
+def test_file_explorer(file_explorer):
+ """Run FileExplorerTest."""
+ file_explorer.resize(640, 480)
+ file_explorer.show()
+ assert file_explorer
+
+
+def test_project_explorer(project_explorer):
+ """Run ProjectExplorerTest."""
+ project_explorer.resize(640, 480)
+ project_explorer.show()
+ assert project_explorer
+
+
+@pytest.mark.parametrize('path_method', ['absolute', 'relative'])
+def test_copy_path(explorer_with_files, path_method):
+ """Test copy absolute and relative paths."""
+ project, __, file_paths, __, cb = explorer_with_files
+ explorer_directory = project.explorer.treewidget.fsmodel.rootPath()
+ copied_from = project.explorer.treewidget.parent_widget.__class__.__name__
+ project.explorer.treewidget.copy_path(fnames=file_paths,
+ method=path_method)
+ cb_output = cb.text(mode=cb.Clipboard)
+ path_list = [path.strip(',"') for path in cb_output.splitlines()]
+ assert len(path_list) == len(file_paths)
+ for path, expected_path in zip(path_list, file_paths):
+ if path_method == 'relative':
+ expected_path = osp.relpath(expected_path, explorer_directory)
+ if copied_from == 'ProjectExplorerWidget':
+ expected_path = os.sep.join(expected_path.strip(os.sep).
+ split(os.sep)[1:])
+ assert osp.normpath(path) == osp.normpath(expected_path)
+
+
+def test_copy_file(explorer_with_files):
+ """Test copy file(s)/folders(s) to clipboard."""
+ project, __, file_paths, __, cb = explorer_with_files
+ project.explorer.treewidget.copy_file_clipboard(fnames=file_paths)
+ cb_data = cb.mimeData().urls()
+ assert len(cb_data) == len(file_paths)
+ for url, expected_path in zip(cb_data, file_paths):
+ file_name = url.toLocalFile()
+ assert osp.normpath(file_name) == osp.normpath(expected_path)
+ try:
+ assert osp.isdir(file_name)
+ except AssertionError:
+ assert osp.isfile(file_name)
+ with open(file_name, 'r') as fh:
+ text = fh.read()
+ assert text == "File Path:\n" + str(file_name)
+
+
+def test_save_file(explorer_with_files):
+ """Test save file(s)/folders(s) from clipboard."""
+ project, dest, file_paths, __, __ = explorer_with_files
+ project.explorer.treewidget.copy_file_clipboard(fnames=file_paths)
+ dest.explorer.treewidget.save_file_clipboard(fnames=[dest.directory])
+ for item in file_paths:
+ destination_item = osp.join(dest.directory, osp.basename(item))
+ assert osp.exists(destination_item)
+ if osp.isfile(destination_item):
+ with open(destination_item, 'r') as fh:
+ text = fh.read()
+ assert text == "File Path:\n" + str(item).replace(os.sep, '/')
+
+
+def test_delete_file(explorer_with_files, mocker):
+ """Test delete file(s)/folders(s)."""
+ project, __, __, top_folder, __ = explorer_with_files
+ mocker.patch.object(QMessageBox, 'warning', return_value=QMessageBox.Yes)
+ project.explorer.treewidget.delete(fnames=[top_folder])
+ assert not osp.exists(top_folder)
+
+
+def test_single_click_to_open(qtbot, file_explorer):
+ """Test single and double click open option for the file explorer."""
+ file_explorer.show()
+
+ treewidget = file_explorer.explorer.treewidget
+ model = treewidget.model()
+ cwd = os.getcwd()
+ qtbot.keyClick(treewidget, Qt.Key_Up) # To focus and select the 1st item
+ initial_index = treewidget.currentIndex() # To keep a reference
+
+ def run_test_helper(single_click, initial_index):
+ # Reset the widget
+ treewidget.setCurrentIndex(initial_index)
+ file_explorer.label3.setText('')
+ file_explorer.label1.setText('')
+
+ for i in range(4): # 4 items inside `/spyder/plugins/explorer/`
+ qtbot.keyClick(treewidget, Qt.Key_Down)
+ index = treewidget.currentIndex()
+ path = model.data(index)
+ if path:
+ full_path = os.path.join(cwd, path)
+ # Skip folder to avoid changing the view for single click case
+ if os.path.isfile(full_path):
+ rect = treewidget.visualRect(index)
+ pos = rect.center()
+ qtbot.mouseClick(treewidget.viewport(), Qt.LeftButton, pos=pos)
+
+ if single_click:
+ assert full_path == file_explorer.label1.text()
+ else:
+ assert full_path != file_explorer.label1.text()
+
+ # Test single click to open
+ treewidget.set_single_click_to_open(True)
+ assert 'True' in file_explorer.label3.text()
+ run_test_helper(single_click=True, initial_index=initial_index)
+
+ # Test double click to open
+ treewidget.set_single_click_to_open(False)
+ assert 'False' in file_explorer.label3.text()
+ run_test_helper(single_click=False, initial_index=initial_index)
+
+
+if __name__ == "__main__":
+ pytest.main()
diff --git a/spyder/plugins/explorer/widgets.py b/spyder/plugins/explorer/widgets.py
new file mode 100644
index 00000000000..2182dcc6495
--- /dev/null
+++ b/spyder/plugins/explorer/widgets.py
@@ -0,0 +1,1547 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Files and Directories Explorer"""
+
+# pylint: disable=C0103
+# pylint: disable=R0903
+# pylint: disable=R0911
+# pylint: disable=R0201
+
+# Standard library imports
+from __future__ import with_statement
+import os
+import os.path as osp
+import re
+import shutil
+import subprocess
+import sys
+import mimetypes as mime
+
+# Third party imports
+from qtpy.compat import getsavefilename, getexistingdirectory
+from qtpy.QtCore import (QDir, QFileInfo, QMimeData, QSize,
+ QSortFilterProxyModel, Qt, QTimer, QUrl,
+ Signal, Slot)
+from qtpy.QtGui import QDrag, QIcon, QKeySequence
+from qtpy.QtWidgets import (QFileSystemModel, QHBoxLayout, QFileIconProvider,
+ QInputDialog, QLabel, QLineEdit, QMenu,
+ QMessageBox, QToolButton, QTreeView, QVBoxLayout,
+ QWidget, QApplication)
+# Local imports
+from spyder.config.base import _, get_home_dir, get_image_path
+from spyder.config.gui import is_dark_interface, config_shortcut, get_shortcut
+from spyder.py3compat import (str_lower, to_binary_string,
+ to_text_string)
+from spyder.utils import icon_manager as ima
+from spyder.utils import encoding, misc, programs, vcs
+from spyder.utils.qthelpers import (add_actions, create_action, file_uri,
+ create_plugin_layout)
+from spyder.utils.misc import getcwd_or_home
+
+try:
+ from nbconvert import PythonExporter as nbexporter
+except:
+ nbexporter = None # analysis:ignore
+
+
+def open_file_in_external_explorer(filename):
+ if sys.platform == "darwin":
+ subprocess.call(["open", "-R", filename])
+ elif os.name == 'nt':
+ subprocess.call(["explorer", "/select,", filename])
+ else:
+ filename=os.path.dirname(filename)
+ subprocess.call(["xdg-open", filename])
+
+def show_in_external_file_explorer(fnames=None):
+ """Show files in external file explorer
+
+ Args:
+ fnames (list): Names of files to show.
+ """
+ if not isinstance(fnames, (tuple, list)):
+ fnames = [fnames]
+ for fname in fnames:
+ open_file_in_external_explorer(fname)
+
+def fixpath(path):
+ """Normalize path fixing case, making absolute and removing symlinks"""
+ norm = osp.normcase if os.name == 'nt' else osp.normpath
+ return norm(osp.abspath(osp.realpath(path)))
+
+
+def create_script(fname):
+ """Create a new Python script"""
+ text = os.linesep.join(["# -*- coding: utf-8 -*-", "", ""])
+ try:
+ encoding.write(to_text_string(text), fname, 'utf-8')
+ except EnvironmentError as error:
+ QMessageBox.critical(_("Save Error"),
+ _("Unable to save file '%s'"
+ "
Error message:
%s"
+ ) % (osp.basename(fname), str(error)))
+
+def listdir(path, include=r'.', exclude=r'\.pyc$|^\.', show_all=False,
+ folders_only=False):
+ """List files and directories"""
+ namelist = []
+ dirlist = [to_text_string(osp.pardir)]
+ for item in os.listdir(to_text_string(path)):
+ if re.search(exclude, item) and not show_all:
+ continue
+ if osp.isdir(osp.join(path, item)):
+ dirlist.append(item)
+ elif folders_only:
+ continue
+ elif re.search(include, item) or show_all:
+ namelist.append(item)
+ return sorted(dirlist, key=str_lower) + \
+ sorted(namelist, key=str_lower)
+
+
+def has_subdirectories(path, include, exclude, show_all):
+ """Return True if path has subdirectories"""
+ try:
+ # > 1 because of '..'
+ return len( listdir(path, include, exclude,
+ show_all, folders_only=True) ) > 1
+ except (IOError, OSError):
+ return False
+
+
+class IconProvider(QFileIconProvider):
+ """Project tree widget icon provider"""
+
+ def __init__(self, treeview):
+ super(IconProvider, self).__init__()
+ self.treeview = treeview
+
+ @Slot(int)
+ @Slot(QFileInfo)
+ def icon(self, icontype_or_qfileinfo):
+ """Reimplement Qt method"""
+ if isinstance(icontype_or_qfileinfo, QFileIconProvider.IconType):
+ return super(IconProvider, self).icon(icontype_or_qfileinfo)
+ else:
+ qfileinfo = icontype_or_qfileinfo
+ fname = osp.normpath(to_text_string(qfileinfo.absoluteFilePath()))
+ return ima.get_icon_by_extension(fname, scale_factor=1.0)
+
+class DirView(QTreeView):
+ """Base file/directory tree view"""
+ sig_edit = Signal(str)
+ sig_removed = Signal(str)
+ sig_removed_tree = Signal(str)
+ sig_renamed = Signal(str, str)
+ sig_renamed_tree = Signal(str, str)
+ sig_create_module = Signal(str)
+ sig_run = Signal(str)
+ sig_new_file = Signal(str)
+ sig_open_interpreter = Signal(str)
+ redirect_stdio = Signal(bool)
+
+ def __init__(self, parent=None):
+ super(DirView, self).__init__(parent)
+ self.parent_widget = parent
+
+ # Options
+ self.name_filters = ['*.py']
+ self.show_all = None
+ self.single_click_to_open = False
+
+ self.menu = None
+ self.common_actions = None
+ self.__expanded_state = None
+ self._to_be_loaded = None
+ self.fsmodel = None
+ self.setup_fs_model()
+ self._scrollbar_positions = None
+ self.setSelectionMode(self.ExtendedSelection)
+ self.shortcuts = self.create_shortcuts()
+
+ #---- Model
+ def setup_fs_model(self):
+ """Setup filesystem model"""
+ filters = QDir.AllDirs | QDir.Files | QDir.Drives | QDir.NoDotAndDotDot
+ self.fsmodel = QFileSystemModel(self)
+ self.fsmodel.setFilter(filters)
+ self.fsmodel.setNameFilterDisables(False)
+
+ def install_model(self):
+ """Install filesystem model"""
+ self.setModel(self.fsmodel)
+
+ def setup_view(self):
+ """Setup view"""
+ self.install_model()
+ self.fsmodel.directoryLoaded.connect(
+ lambda: self.resizeColumnToContents(0))
+ self.setAnimated(False)
+ self.setSortingEnabled(True)
+ self.sortByColumn(0, Qt.AscendingOrder)
+ self.fsmodel.modelReset.connect(self.reset_icon_provider)
+ self.reset_icon_provider()
+ # Disable the view of .spyproject.
+ self.filter_directories()
+
+ def set_single_click_to_open(self, value):
+ """Set single click to open items."""
+ self.single_click_to_open = value
+ self.parent_widget.sig_option_changed.emit('single_click_to_open',
+ value)
+
+ def set_name_filters(self, name_filters):
+ """Set name filters"""
+ self.name_filters = name_filters
+ self.fsmodel.setNameFilters(name_filters)
+
+ def set_show_all(self, state):
+ """Toggle 'show all files' state"""
+ if state:
+ self.fsmodel.setNameFilters([])
+ else:
+ self.fsmodel.setNameFilters(self.name_filters)
+
+ def get_filename(self, index):
+ """Return filename associated with *index*"""
+ if index:
+ return osp.normpath(to_text_string(self.fsmodel.filePath(index)))
+
+ def get_index(self, filename):
+ """Return index associated with filename"""
+ return self.fsmodel.index(filename)
+
+ def get_selected_filenames(self):
+ """Return selected filenames"""
+ if self.selectionMode() == self.ExtendedSelection:
+ if self.selectionModel() is None:
+ return []
+ return [self.get_filename(idx) for idx in
+ self.selectionModel().selectedRows()]
+ else:
+ return [self.get_filename(self.currentIndex())]
+
+ def get_dirname(self, index):
+ """Return dirname associated with *index*"""
+ fname = self.get_filename(index)
+ if fname:
+ if osp.isdir(fname):
+ return fname
+ else:
+ return osp.dirname(fname)
+
+ #---- Tree view widget
+ def setup(self, name_filters=['*.py', '*.pyw'], show_all=False,
+ single_click_to_open=False):
+ """Setup tree widget"""
+ self.setup_view()
+
+ self.set_name_filters(name_filters)
+ self.show_all = show_all
+ self.single_click_to_open = single_click_to_open
+
+ # Setup context menu
+ self.menu = QMenu(self)
+ self.common_actions = self.setup_common_actions()
+
+ def reset_icon_provider(self):
+ """Reset file system model icon provider
+ The purpose of this is to refresh files/directories icons"""
+ self.fsmodel.setIconProvider(IconProvider(self))
+
+ #---- Context menu
+ def setup_common_actions(self):
+ """Setup context menu common actions"""
+ # Filters
+ filters_action = create_action(self, _("Edit filename filters..."),
+ None, ima.icon('filter'),
+ triggered=self.edit_filter)
+ # Show all files
+ all_action = create_action(self, _("Show all files"),
+ toggled=self.toggle_all)
+ all_action.setChecked(self.show_all)
+ self.toggle_all(self.show_all)
+
+ # Show all files
+ single_click_to_open = create_action(
+ self,
+ _("Single click to open"),
+ toggled=self.set_single_click_to_open,
+ )
+ single_click_to_open.setChecked(self.single_click_to_open)
+ return [filters_action, all_action, single_click_to_open]
+
+ @Slot()
+ def edit_filter(self):
+ """Edit name filters"""
+ filters, valid = QInputDialog.getText(self, _('Edit filename filters'),
+ _('Name filters:'),
+ QLineEdit.Normal,
+ ", ".join(self.name_filters))
+ if valid:
+ filters = [f.strip() for f in to_text_string(filters).split(',')]
+ self.parent_widget.sig_option_changed.emit('name_filters', filters)
+ self.set_name_filters(filters)
+
+ @Slot(bool)
+ def toggle_all(self, checked):
+ """Toggle all files mode"""
+ self.parent_widget.sig_option_changed.emit('show_all', checked)
+ self.show_all = checked
+ self.set_show_all(checked)
+
+ def create_file_new_actions(self, fnames):
+ """Return actions for submenu 'New...'"""
+ if not fnames:
+ return []
+ new_file_act = create_action(self, _("File..."),
+ icon=ima.icon('filenew'),
+ triggered=lambda:
+ self.new_file(fnames[-1]))
+ new_module_act = create_action(self, _("Module..."),
+ icon=ima.icon('spyder'),
+ triggered=lambda:
+ self.new_module(fnames[-1]))
+ new_folder_act = create_action(self, _("Folder..."),
+ icon=ima.icon('folder_new'),
+ triggered=lambda:
+ self.new_folder(fnames[-1]))
+ new_package_act = create_action(self, _("Package..."),
+ icon=ima.icon('package_new'),
+ triggered=lambda:
+ self.new_package(fnames[-1]))
+ return [new_file_act, new_folder_act, None,
+ new_module_act, new_package_act]
+
+ def create_file_import_actions(self, fnames):
+ """Return actions for submenu 'Import...'"""
+ return []
+
+ def create_file_manage_actions(self, fnames):
+ """Return file management actions"""
+ only_files = all([osp.isfile(_fn) for _fn in fnames])
+ only_modules = all([osp.splitext(_fn)[1] in ('.py', '.pyw', '.ipy')
+ for _fn in fnames])
+ only_notebooks = all([osp.splitext(_fn)[1] == '.ipynb'
+ for _fn in fnames])
+ only_valid = all([encoding.is_text_file(_fn) for _fn in fnames])
+ run_action = create_action(self, _("Run"), icon=ima.icon('run'),
+ triggered=self.run)
+ edit_action = create_action(self, _("Edit"), icon=ima.icon('edit'),
+ triggered=self.clicked)
+ move_action = create_action(self, _("Move..."),
+ icon="move.png",
+ triggered=self.move)
+ delete_action = create_action(self, _("Delete..."),
+ icon=ima.icon('editdelete'),
+ triggered=self.delete)
+ rename_action = create_action(self, _("Rename..."),
+ icon=ima.icon('rename'),
+ triggered=self.rename)
+ open_external_action = create_action(self, _("Open With OS"),
+ triggered=self.open_external)
+ ipynb_convert_action = create_action(self, _("Convert to Python script"),
+ icon=ima.icon('python'),
+ triggered=self.convert_notebooks)
+ copy_file_clipboard_action = (
+ create_action(self, _("Copy"),
+ QKeySequence(get_shortcut('explorer', 'copy file')),
+ icon=ima.icon('editcopy'),
+ triggered=self.copy_file_clipboard))
+ save_file_clipboard_action = (
+ create_action(self, _("Paste"),
+ QKeySequence(get_shortcut('explorer', 'paste file')),
+ icon=ima.icon('editpaste'),
+ triggered=self.save_file_clipboard))
+ copy_absolute_path_action = (
+ create_action(self, _("Copy Absolute Path"), QKeySequence(
+ get_shortcut('explorer', 'copy absolute path')),
+ triggered=self.copy_absolute_path))
+ copy_relative_path_action = (
+ create_action(self, _("Copy Relative Path"), QKeySequence(
+ get_shortcut('explorer', 'copy relative path')),
+ triggered=self.copy_relative_path))
+
+ actions = []
+ if only_modules:
+ actions.append(run_action)
+ if only_valid and only_files:
+ actions.append(edit_action)
+
+ if sys.platform == 'darwin':
+ text=_("Show in Finder")
+ else:
+ text=_("Show in Folder")
+ external_fileexp_action = create_action(
+ self, text, triggered=self.show_in_external_file_explorer)
+ actions += [delete_action, rename_action]
+ basedir = fixpath(osp.dirname(fnames[0]))
+ if all([fixpath(osp.dirname(_fn)) == basedir for _fn in fnames]):
+ actions.append(move_action)
+ actions += [None]
+ actions += [copy_file_clipboard_action, save_file_clipboard_action,
+ copy_absolute_path_action, copy_relative_path_action]
+ if not QApplication.clipboard().mimeData().hasUrls():
+ save_file_clipboard_action.setDisabled(True)
+ actions += [None]
+ if only_files:
+ actions.append(open_external_action)
+ actions.append(external_fileexp_action)
+ actions.append([None])
+ if only_notebooks and nbexporter is not None:
+ actions.append(ipynb_convert_action)
+
+ # VCS support is quite limited for now, so we are enabling the VCS
+ # related actions only when a single file/folder is selected:
+ dirname = fnames[0] if osp.isdir(fnames[0]) else osp.dirname(fnames[0])
+ if len(fnames) == 1 and vcs.is_vcs_repository(dirname):
+ commit_slot = lambda : self.vcs_command([dirname], 'commit')
+ browse_slot = lambda : self.vcs_command([dirname], 'browse')
+ vcs_ci = create_action(self, _("Commit"),
+ icon=ima.icon('vcs_commit'),
+ triggered=commit_slot)
+ vcs_log = create_action(self, _("Browse repository"),
+ icon=ima.icon('vcs_browse'),
+ triggered=browse_slot)
+ actions += [None, vcs_ci, vcs_log]
+
+ return actions
+
+ def create_folder_manage_actions(self, fnames):
+ """Return folder management actions"""
+ actions = []
+ if os.name == 'nt':
+ _title = _("Open command prompt here")
+ else:
+ _title = _("Open terminal here")
+ _title = _("Open IPython console here")
+ action = create_action(self, _title,
+ triggered=lambda:
+ self.open_interpreter(fnames))
+ actions.append(action)
+ return actions
+
+ def create_context_menu_actions(self):
+ """Create context menu actions"""
+ actions = []
+ fnames = self.get_selected_filenames()
+ new_actions = self.create_file_new_actions(fnames)
+ if len(new_actions) > 1:
+ # Creating a submenu only if there is more than one entry
+ new_act_menu = QMenu(_('New'), self)
+ add_actions(new_act_menu, new_actions)
+ actions.append(new_act_menu)
+ else:
+ actions += new_actions
+ import_actions = self.create_file_import_actions(fnames)
+ if len(import_actions) > 1:
+ # Creating a submenu only if there is more than one entry
+ import_act_menu = QMenu(_('Import'), self)
+ add_actions(import_act_menu, import_actions)
+ actions.append(import_act_menu)
+ else:
+ actions += import_actions
+ if actions:
+ actions.append(None)
+ if fnames:
+ actions += self.create_file_manage_actions(fnames)
+ if actions:
+ actions.append(None)
+ if fnames and all([osp.isdir(_fn) for _fn in fnames]):
+ actions += self.create_folder_manage_actions(fnames)
+ return actions
+
+ def update_menu(self):
+ """Update context menu"""
+ self.menu.clear()
+ add_actions(self.menu, self.create_context_menu_actions())
+
+ #---- Events
+ def viewportEvent(self, event):
+ """Reimplement Qt method"""
+
+ # Prevent Qt from crashing or showing warnings like:
+ # "QSortFilterProxyModel: index from wrong model passed to
+ # mapFromSource", probably due to the fact that the file system model
+ # is being built. See Issue 1250.
+ #
+ # This workaround was inspired by the following KDE bug:
+ # https://bugs.kde.org/show_bug.cgi?id=172198
+ #
+ # Apparently, this is a bug from Qt itself.
+ self.executeDelayedItemsLayout()
+
+ return QTreeView.viewportEvent(self, event)
+
+ def contextMenuEvent(self, event):
+ """Override Qt method"""
+ # Needed to handle not initialized menu.
+ # See issue 6975
+ try:
+ self.update_menu()
+ self.menu.popup(event.globalPos())
+ except AttributeError:
+ pass
+
+ def keyPressEvent(self, event):
+ """Reimplement Qt method"""
+ if event.key() in (Qt.Key_Enter, Qt.Key_Return):
+ self.clicked()
+ elif event.key() == Qt.Key_F2:
+ self.rename()
+ elif event.key() == Qt.Key_Delete:
+ self.delete()
+ elif event.key() == Qt.Key_Backspace:
+ self.go_to_parent_directory()
+ else:
+ QTreeView.keyPressEvent(self, event)
+
+ def mouseDoubleClickEvent(self, event):
+ """Reimplement Qt method"""
+ QTreeView.mouseDoubleClickEvent(self, event)
+ self.clicked()
+
+ def mouseReleaseEvent(self, event):
+ """Reimplement Qt method."""
+ QTreeView.mouseReleaseEvent(self, event)
+ if self.single_click_to_open:
+ self.clicked()
+
+ @Slot()
+ def clicked(self):
+ """Selected item was double-clicked or enter/return was pressed"""
+ fnames = self.get_selected_filenames()
+ for fname in fnames:
+ if osp.isdir(fname):
+ self.directory_clicked(fname)
+ else:
+ self.open([fname])
+
+ def directory_clicked(self, dirname):
+ """Directory was just clicked"""
+ pass
+
+ #---- Drag
+ def dragEnterEvent(self, event):
+ """Drag and Drop - Enter event"""
+ event.setAccepted(event.mimeData().hasFormat("text/plain"))
+
+ def dragMoveEvent(self, event):
+ """Drag and Drop - Move event"""
+ if (event.mimeData().hasFormat("text/plain")):
+ event.setDropAction(Qt.MoveAction)
+ event.accept()
+ else:
+ event.ignore()
+
+ def startDrag(self, dropActions):
+ """Reimplement Qt Method - handle drag event"""
+ data = QMimeData()
+ data.setUrls([QUrl(fname) for fname in self.get_selected_filenames()])
+ drag = QDrag(self)
+ drag.setMimeData(data)
+ drag.exec_()
+
+ #---- File/Directory actions
+ @Slot()
+ def open(self, fnames=None):
+ """Open files with the appropriate application"""
+ if fnames is None:
+ fnames = self.get_selected_filenames()
+ for fname in fnames:
+ if osp.isfile(fname) and encoding.is_text_file(fname):
+ self.parent_widget.sig_open_file.emit(fname)
+ else:
+ self.open_outside_spyder([fname])
+
+ @Slot()
+ def open_external(self, fnames=None):
+ """Open files with default application"""
+ if fnames is None:
+ fnames = self.get_selected_filenames()
+ for fname in fnames:
+ self.open_outside_spyder([fname])
+
+ def open_outside_spyder(self, fnames):
+ """Open file outside Spyder with the appropriate application
+ If this does not work, opening unknown file in Spyder, as text file"""
+ for path in sorted(fnames):
+ path = file_uri(path)
+ ok = programs.start_file(path)
+ if not ok:
+ self.sig_edit.emit(path)
+
+ def open_interpreter(self, fnames):
+ """Open interpreter"""
+ for path in sorted(fnames):
+ self.sig_open_interpreter.emit(path)
+
+ @Slot()
+ def run(self, fnames=None):
+ """Run Python scripts"""
+ if fnames is None:
+ fnames = self.get_selected_filenames()
+ for fname in fnames:
+ self.sig_run.emit(fname)
+
+ def remove_tree(self, dirname):
+ """Remove whole directory tree
+ Reimplemented in project explorer widget"""
+ while osp.exists(dirname):
+ try:
+ shutil.rmtree(dirname, onerror=misc.onerror)
+ except Exception as e:
+ # This handles a Windows problem with shutil.rmtree.
+ # See issue #8567.
+ if type(e).__name__ == "OSError":
+ error_path = to_text_string(e.filename)
+ shutil.rmtree(error_path, ignore_errors=True)
+
+ def delete_file(self, fname, multiple, yes_to_all):
+ """Delete file"""
+ if multiple:
+ buttons = QMessageBox.Yes|QMessageBox.YesToAll| \
+ QMessageBox.No|QMessageBox.Cancel
+ else:
+ buttons = QMessageBox.Yes|QMessageBox.No
+ if yes_to_all is None:
+ answer = QMessageBox.warning(self, _("Delete"),
+ _("Do you really want "
+ "to delete %s?"
+ ) % osp.basename(fname), buttons)
+ if answer == QMessageBox.No:
+ return yes_to_all
+ elif answer == QMessageBox.Cancel:
+ return False
+ elif answer == QMessageBox.YesToAll:
+ yes_to_all = True
+ try:
+ if osp.isfile(fname):
+ misc.remove_file(fname)
+ self.sig_removed.emit(fname)
+ else:
+ self.remove_tree(fname)
+ self.sig_removed_tree.emit(fname)
+ return yes_to_all
+ except EnvironmentError as error:
+ action_str = _('delete')
+ QMessageBox.critical(self, _("Project Explorer"),
+ _("Unable to %s %s"
+ "
Error message:
%s"
+ ) % (action_str, fname, to_text_string(error)))
+ return False
+
+ @Slot()
+ def delete(self, fnames=None):
+ """Delete files"""
+ if fnames is None:
+ fnames = self.get_selected_filenames()
+ multiple = len(fnames) > 1
+ yes_to_all = None
+ for fname in fnames:
+ spyproject_path = osp.join(fname,'.spyproject')
+ if osp.isdir(fname) and osp.exists(spyproject_path):
+ QMessageBox.information(self, _('File Explorer'),
+ _("The current directory contains a "
+ "project.
"
+ "If you want to delete"
+ " the project, please go to "
+ "Projects » Delete "
+ "Project"))
+ else:
+ yes_to_all = self.delete_file(fname, multiple, yes_to_all)
+ if yes_to_all is not None and not yes_to_all:
+ # Canceled
+ break
+
+ def convert_notebook(self, fname):
+ """Convert an IPython notebook to a Python script in editor"""
+ try:
+ script = nbexporter().from_filename(fname)[0]
+ except Exception as e:
+ QMessageBox.critical(self, _('Conversion error'),
+ _("It was not possible to convert this "
+ "notebook. The error is:\n\n") + \
+ to_text_string(e))
+ return
+ self.sig_new_file.emit(script)
+
+ @Slot()
+ def convert_notebooks(self):
+ """Convert IPython notebooks to Python scripts in editor"""
+ fnames = self.get_selected_filenames()
+ if not isinstance(fnames, (tuple, list)):
+ fnames = [fnames]
+ for fname in fnames:
+ self.convert_notebook(fname)
+
+ def rename_file(self, fname):
+ """Rename file"""
+ path, valid = QInputDialog.getText(self, _('Rename'),
+ _('New name:'), QLineEdit.Normal,
+ osp.basename(fname))
+ if valid:
+ path = osp.join(osp.dirname(fname), to_text_string(path))
+ if path == fname:
+ return
+ if osp.exists(path):
+ if QMessageBox.warning(self, _("Rename"),
+ _("Do you really want to rename %s and "
+ "overwrite the existing file %s?"
+ ) % (osp.basename(fname), osp.basename(path)),
+ QMessageBox.Yes|QMessageBox.No) == QMessageBox.No:
+ return
+ try:
+ misc.rename_file(fname, path)
+ if osp.isfile(fname):
+ self.sig_renamed.emit(fname, path)
+ else:
+ self.sig_renamed_tree.emit(fname, path)
+ return path
+ except EnvironmentError as error:
+ QMessageBox.critical(self, _("Rename"),
+ _("Unable to rename file %s"
+ "
Error message:
%s"
+ ) % (osp.basename(fname), to_text_string(error)))
+
+ @Slot()
+ def show_in_external_file_explorer(self, fnames=None):
+ """Show file in external file explorer"""
+ if fnames is None:
+ fnames = self.get_selected_filenames()
+ show_in_external_file_explorer(fnames)
+
+ @Slot()
+ def rename(self, fnames=None):
+ """Rename files"""
+ if fnames is None:
+ fnames = self.get_selected_filenames()
+ if not isinstance(fnames, (tuple, list)):
+ fnames = [fnames]
+ for fname in fnames:
+ self.rename_file(fname)
+
+ @Slot()
+ def move(self, fnames=None, directory=None):
+ """Move files/directories"""
+ if fnames is None:
+ fnames = self.get_selected_filenames()
+ orig = fixpath(osp.dirname(fnames[0]))
+ while True:
+ self.redirect_stdio.emit(False)
+ if directory is None:
+ folder = getexistingdirectory(self, _("Select directory"),
+ orig)
+ else:
+ folder = directory
+ self.redirect_stdio.emit(True)
+ if folder:
+ folder = fixpath(folder)
+ if folder != orig:
+ break
+ else:
+ return
+ for fname in fnames:
+ basename = osp.basename(fname)
+ try:
+ misc.move_file(fname, osp.join(folder, basename))
+ except EnvironmentError as error:
+ QMessageBox.critical(self, _("Error"),
+ _("Unable to move %s"
+ "
Error message:
%s"
+ ) % (basename, to_text_string(error)))
+
+ def create_new_folder(self, current_path, title, subtitle, is_package):
+ """Create new folder"""
+ if current_path is None:
+ current_path = ''
+ if osp.isfile(current_path):
+ current_path = osp.dirname(current_path)
+ name, valid = QInputDialog.getText(self, title, subtitle,
+ QLineEdit.Normal, "")
+ if valid:
+ dirname = osp.join(current_path, to_text_string(name))
+ try:
+ os.mkdir(dirname)
+ except EnvironmentError as error:
+ QMessageBox.critical(self, title,
+ _("Unable "
+ "to create folder %s"
+ "
Error message:
%s"
+ ) % (dirname, to_text_string(error)))
+ finally:
+ if is_package:
+ fname = osp.join(dirname, '__init__.py')
+ try:
+ with open(fname, 'wb') as f:
+ f.write(to_binary_string('#'))
+ return dirname
+ except EnvironmentError as error:
+ QMessageBox.critical(self, title,
+ _("Unable "
+ "to create file %s"
+ "
Error message:
%s"
+ ) % (fname,
+ to_text_string(error)))
+
+ def new_folder(self, basedir):
+ """New folder"""
+ title = _('New folder')
+ subtitle = _('Folder name:')
+ self.create_new_folder(basedir, title, subtitle, is_package=False)
+
+ def new_package(self, basedir):
+ """New package"""
+ title = _('New package')
+ subtitle = _('Package name:')
+ self.create_new_folder(basedir, title, subtitle, is_package=True)
+
+ def create_new_file(self, current_path, title, filters, create_func):
+ """Create new file
+ Returns True if successful"""
+ if current_path is None:
+ current_path = ''
+ if osp.isfile(current_path):
+ current_path = osp.dirname(current_path)
+ self.redirect_stdio.emit(False)
+ fname, _selfilter = getsavefilename(self, title, current_path, filters)
+ self.redirect_stdio.emit(True)
+ if fname:
+ try:
+ create_func(fname)
+ return fname
+ except EnvironmentError as error:
+ QMessageBox.critical(self, _("New file"),
+ _("Unable to create file %s"
+ "
Error message:
%s"
+ ) % (fname, to_text_string(error)))
+
+ def new_file(self, basedir):
+ """New file"""
+ title = _("New file")
+ filters = _("All files")+" (*)"
+ def create_func(fname):
+ """File creation callback"""
+ if osp.splitext(fname)[1] in ('.py', '.pyw', '.ipy'):
+ create_script(fname)
+ else:
+ with open(fname, 'wb') as f:
+ f.write(to_binary_string(''))
+ fname = self.create_new_file(basedir, title, filters, create_func)
+ if fname is not None:
+ self.open([fname])
+
+ def new_module(self, basedir):
+ """New module"""
+ title = _("New module")
+ filters = _("Python scripts")+" (*.py *.pyw *.ipy)"
+
+ def create_func(fname):
+ self.sig_create_module.emit(fname)
+
+ self.create_new_file(basedir, title, filters, create_func)
+
+ def go_to_parent_directory(self):
+ pass
+
+ def copy_path(self, fnames=None, method="absolute"):
+ """Copy absolute or relative path to given file(s)/folders(s)."""
+ cb = QApplication.clipboard()
+ explorer_dir = self.fsmodel.rootPath()
+ if fnames is None:
+ fnames = self.get_selected_filenames()
+ if not isinstance(fnames, (tuple, list)):
+ fnames = [fnames]
+ fnames = [_fn.replace(os.sep, "/") for _fn in fnames]
+ if len(fnames) > 1:
+ if method == "absolute":
+ clipboard_files = ',\n'.join('"' + _fn + '"' for _fn in fnames)
+ elif method == "relative":
+ clipboard_files = ',\n'.join('"' +
+ osp.relpath(_fn, explorer_dir).
+ replace(os.sep, "/") + '"'
+ for _fn in fnames)
+ else:
+ if method == "absolute":
+ clipboard_files = fnames[0]
+ elif method == "relative":
+ clipboard_files = (osp.relpath(fnames[0], explorer_dir).
+ replace(os.sep, "/"))
+ copied_from = self.parent_widget.__class__.__name__
+ if copied_from == 'ProjectExplorerWidget' and method == 'relative':
+ clipboard_files = [path.strip(',"') for path in
+ clipboard_files.splitlines()]
+ clipboard_files = ['/'.join(path.strip('/').split('/')[1:]) for
+ path in clipboard_files]
+ if len(clipboard_files) > 1:
+ clipboard_files = ',\n'.join('"' + _fn + '"' for _fn in
+ clipboard_files)
+ else:
+ clipboard_files = clipboard_files[0]
+ cb.setText(clipboard_files, mode=cb.Clipboard)
+
+ @Slot()
+ def copy_absolute_path(self):
+ """Copy absolute paths of named files/directories to the clipboard."""
+ self.copy_path(method="absolute")
+
+ @Slot()
+ def copy_relative_path(self):
+ """Copy relative paths of named files/directories to the clipboard."""
+ self.copy_path(method="relative")
+
+ @Slot()
+ def copy_file_clipboard(self, fnames=None):
+ """Copy file(s)/folders(s) to clipboard."""
+ if fnames is None:
+ fnames = self.get_selected_filenames()
+ if not isinstance(fnames, (tuple, list)):
+ fnames = [fnames]
+ try:
+ file_content = QMimeData()
+ file_content.setUrls([QUrl.fromLocalFile(_fn) for _fn in fnames])
+ cb = QApplication.clipboard()
+ cb.setMimeData(file_content, mode=cb.Clipboard)
+ except Exception as e:
+ QMessageBox.critical(self,
+ _('File/Folder copy error'),
+ _("Cannot copy this type of file(s) or "
+ "folder(s). The error was:\n\n")
+ + to_text_string(e))
+
+ @Slot()
+ def save_file_clipboard(self, fnames=None):
+ """Paste file from clipboard into file/project explorer directory."""
+ if fnames is None:
+ fnames = self.get_selected_filenames()
+ if not isinstance(fnames, (tuple, list)):
+ fnames = [fnames]
+ if len(fnames) >= 1:
+ try:
+ selected_item = osp.commonpath(fnames)
+ except AttributeError:
+ # py2 does not have commonpath
+ if len(fnames) > 1:
+ selected_item = osp.normpath(
+ osp.dirname(osp.commonprefix(fnames)))
+ else:
+ selected_item = fnames[0]
+ if osp.isfile(selected_item):
+ parent_path = osp.dirname(selected_item)
+ else:
+ parent_path = osp.normpath(selected_item)
+ cb_data = QApplication.clipboard().mimeData()
+ if cb_data.hasUrls():
+ urls = cb_data.urls()
+ for url in urls:
+ source_name = url.toLocalFile()
+ base_name = osp.basename(source_name)
+ if osp.isfile(source_name):
+ try:
+ while base_name in os.listdir(parent_path):
+ file_no_ext, file_ext = osp.splitext(base_name)
+ end_number = re.search(r'\d+$', file_no_ext)
+ if end_number:
+ new_number = int(end_number.group()) + 1
+ else:
+ new_number = 1
+ left_string = re.sub(r'\d+$', '', file_no_ext)
+ left_string += str(new_number)
+ base_name = left_string + file_ext
+ destination = osp.join(parent_path, base_name)
+ else:
+ destination = osp.join(parent_path, base_name)
+ shutil.copy(source_name, destination)
+ except Exception as e:
+ QMessageBox.critical(self, _('Error pasting file'),
+ _("Unsupported copy operation"
+ ". The error was:\n\n")
+ + to_text_string(e))
+ else:
+ try:
+ while base_name in os.listdir(parent_path):
+ end_number = re.search(r'\d+$', base_name)
+ if end_number:
+ new_number = int(end_number.group()) + 1
+ else:
+ new_number = 1
+ left_string = re.sub(r'\d+$', '', base_name)
+ base_name = left_string + str(new_number)
+ destination = osp.join(parent_path, base_name)
+ else:
+ destination = osp.join(parent_path, base_name)
+ if osp.realpath(destination).startswith(
+ osp.realpath(source_name) + os.sep):
+ QMessageBox.critical(self,
+ _('Recursive copy'),
+ _("Source is an ancestor"
+ " of destination"
+ " folder."))
+ continue
+ shutil.copytree(source_name, destination)
+ except Exception as e:
+ QMessageBox.critical(self,
+ _('Error pasting folder'),
+ _("Unsupported copy"
+ " operation. The error was:"
+ "\n\n") + to_text_string(e))
+ else:
+ QMessageBox.critical(self, _("No file in clipboard"),
+ _("No file in the clipboard. Please copy"
+ " a file to the clipboard first."))
+ else:
+ if QApplication.clipboard().mimeData().hasUrls():
+ QMessageBox.critical(self, _('Blank area'),
+ _("Cannot paste in the blank area."))
+ else:
+ pass
+
+ def create_shortcuts(self):
+ """Create shortcuts for this file explorer."""
+ # Configurable
+ copy_clipboard_file = config_shortcut(self.copy_file_clipboard,
+ context='explorer',
+ name='copy file', parent=self)
+ paste_clipboard_file = config_shortcut(self.save_file_clipboard,
+ context='explorer',
+ name='paste file', parent=self)
+ copy_absolute_path = config_shortcut(self.copy_absolute_path,
+ context='explorer',
+ name='copy absolute path',
+ parent=self)
+ copy_relative_path = config_shortcut(self.copy_relative_path,
+ context='explorer',
+ name='copy relative path',
+ parent=self)
+ return [copy_clipboard_file, paste_clipboard_file, copy_absolute_path,
+ copy_relative_path]
+
+ def get_shortcut_data(self):
+ """
+ Return shortcut data, a list of tuples (shortcut, text, default).
+ shortcut (QShortcut or QAction instance)
+ text (string): action/shortcut description
+ default (string): default key sequence
+ """
+ return [sc.data for sc in self.shortcuts]
+
+ #----- VCS actions
+ def vcs_command(self, fnames, action):
+ """VCS action (commit, browse)"""
+ try:
+ for path in sorted(fnames):
+ vcs.run_vcs_tool(path, action)
+ except vcs.ActionToolNotFound as error:
+ msg = _("For %s support, please install one of the
"
+ "following tools:
%s")\
+ % (error.vcsname, ', '.join(error.tools))
+ QMessageBox.critical(self, _("Error"),
+ _("""Unable to find external program.
%s""")
+ % to_text_string(msg))
+
+ #----- Settings
+ def get_scrollbar_position(self):
+ """Return scrollbar positions"""
+ return (self.horizontalScrollBar().value(),
+ self.verticalScrollBar().value())
+
+ def set_scrollbar_position(self, position):
+ """Set scrollbar positions"""
+ # Scrollbars will be restored after the expanded state
+ self._scrollbar_positions = position
+ if self._to_be_loaded is not None and len(self._to_be_loaded) == 0:
+ self.restore_scrollbar_positions()
+
+ def restore_scrollbar_positions(self):
+ """Restore scrollbar positions once tree is loaded"""
+ hor, ver = self._scrollbar_positions
+ self.horizontalScrollBar().setValue(hor)
+ self.verticalScrollBar().setValue(ver)
+
+ def get_expanded_state(self):
+ """Return expanded state"""
+ self.save_expanded_state()
+ return self.__expanded_state
+
+ def set_expanded_state(self, state):
+ """Set expanded state"""
+ self.__expanded_state = state
+ self.restore_expanded_state()
+
+ def save_expanded_state(self):
+ """Save all items expanded state"""
+ model = self.model()
+ # If model is not installed, 'model' will be None: this happens when
+ # using the Project Explorer without having selected a workspace yet
+ if model is not None:
+ self.__expanded_state = []
+ for idx in model.persistentIndexList():
+ if self.isExpanded(idx):
+ self.__expanded_state.append(self.get_filename(idx))
+
+ def restore_directory_state(self, fname):
+ """Restore directory expanded state"""
+ root = osp.normpath(to_text_string(fname))
+ if not osp.exists(root):
+ # Directory has been (re)moved outside Spyder
+ return
+ for basename in os.listdir(root):
+ path = osp.normpath(osp.join(root, basename))
+ if osp.isdir(path) and path in self.__expanded_state:
+ self.__expanded_state.pop(self.__expanded_state.index(path))
+ if self._to_be_loaded is None:
+ self._to_be_loaded = []
+ self._to_be_loaded.append(path)
+ self.setExpanded(self.get_index(path), True)
+ if not self.__expanded_state:
+ self.fsmodel.directoryLoaded.disconnect(self.restore_directory_state)
+
+ def follow_directories_loaded(self, fname):
+ """Follow directories loaded during startup"""
+ if self._to_be_loaded is None:
+ return
+ path = osp.normpath(to_text_string(fname))
+ if path in self._to_be_loaded:
+ self._to_be_loaded.remove(path)
+ if self._to_be_loaded is not None and len(self._to_be_loaded) == 0:
+ self.fsmodel.directoryLoaded.disconnect(
+ self.follow_directories_loaded)
+ if self._scrollbar_positions is not None:
+ # The tree view need some time to render branches:
+ QTimer.singleShot(50, self.restore_scrollbar_positions)
+
+ def restore_expanded_state(self):
+ """Restore all items expanded state"""
+ if self.__expanded_state is not None:
+ # In the old project explorer, the expanded state was a dictionnary:
+ if isinstance(self.__expanded_state, list):
+ self.fsmodel.directoryLoaded.connect(
+ self.restore_directory_state)
+ self.fsmodel.directoryLoaded.connect(
+ self.follow_directories_loaded)
+
+ def filter_directories(self):
+ """Filter the directories to show"""
+ index = self.get_index('.spyproject')
+ if index is not None:
+ self.setRowHidden(index.row(), index.parent(), True)
+
+class ProxyModel(QSortFilterProxyModel):
+ """Proxy model: filters tree view"""
+ def __init__(self, parent):
+ super(ProxyModel, self).__init__(parent)
+ self.root_path = None
+ self.path_list = []
+ self.setDynamicSortFilter(True)
+
+ def setup_filter(self, root_path, path_list):
+ """Setup proxy model filter parameters"""
+ self.root_path = osp.normpath(to_text_string(root_path))
+ self.path_list = [osp.normpath(to_text_string(p)) for p in path_list]
+ self.invalidateFilter()
+
+ def sort(self, column, order=Qt.AscendingOrder):
+ """Reimplement Qt method"""
+ self.sourceModel().sort(column, order)
+
+ def filterAcceptsRow(self, row, parent_index):
+ """Reimplement Qt method"""
+ if self.root_path is None:
+ return True
+ index = self.sourceModel().index(row, 0, parent_index)
+ path = osp.normcase(osp.normpath(
+ to_text_string(self.sourceModel().filePath(index))))
+ if osp.normcase(self.root_path).startswith(path):
+ # This is necessary because parent folders need to be scanned
+ return True
+ else:
+ for p in [osp.normcase(p) for p in self.path_list]:
+ if path == p or path.startswith(p+os.sep):
+ return True
+ else:
+ return False
+
+ def data(self, index, role):
+ """Show tooltip with full path only for the root directory"""
+ if role == Qt.ToolTipRole:
+ root_dir = self.path_list[0].split(osp.sep)[-1]
+ if index.data() == root_dir:
+ return osp.join(self.root_path, root_dir)
+ return QSortFilterProxyModel.data(self, index, role)
+
+class FilteredDirView(DirView):
+ """Filtered file/directory tree view"""
+ def __init__(self, parent=None):
+ super(FilteredDirView, self).__init__(parent)
+ self.proxymodel = None
+ self.setup_proxy_model()
+ self.root_path = None
+
+ #---- Model
+ def setup_proxy_model(self):
+ """Setup proxy model"""
+ self.proxymodel = ProxyModel(self)
+ self.proxymodel.setSourceModel(self.fsmodel)
+
+ def install_model(self):
+ """Install proxy model"""
+ if self.root_path is not None:
+ self.setModel(self.proxymodel)
+
+ def set_root_path(self, root_path):
+ """Set root path"""
+ self.root_path = root_path
+ self.install_model()
+ index = self.fsmodel.setRootPath(root_path)
+ self.proxymodel.setup_filter(self.root_path, [])
+ self.setRootIndex(self.proxymodel.mapFromSource(index))
+
+ def get_index(self, filename):
+ """Return index associated with filename"""
+ index = self.fsmodel.index(filename)
+ if index.isValid() and index.model() is self.fsmodel:
+ return self.proxymodel.mapFromSource(index)
+
+ def set_folder_names(self, folder_names):
+ """Set folder names"""
+ assert self.root_path is not None
+ path_list = [osp.join(self.root_path, dirname)
+ for dirname in folder_names]
+ self.proxymodel.setup_filter(self.root_path, path_list)
+
+ def get_filename(self, index):
+ """Return filename from index"""
+ if index:
+ path = self.fsmodel.filePath(self.proxymodel.mapToSource(index))
+ return osp.normpath(to_text_string(path))
+
+ def setup_project_view(self):
+ """Setup view for projects"""
+ for i in [1, 2, 3]:
+ self.hideColumn(i)
+ self.setHeaderHidden(True)
+ # Disable the view of .spyproject.
+ self.filter_directories()
+
+
+class ExplorerTreeWidget(DirView):
+ """File/directory explorer tree widget
+ show_cd_only: Show current directory only
+ (True/False: enable/disable the option
+ None: enable the option and do not allow the user to disable it)"""
+ set_previous_enabled = Signal(bool)
+ set_next_enabled = Signal(bool)
+ sig_open_dir = Signal(str)
+
+ def __init__(self, parent=None, show_cd_only=None):
+ DirView.__init__(self, parent)
+
+ self.history = []
+ self.histindex = None
+
+ self.show_cd_only = show_cd_only
+ self.__original_root_index = None
+ self.__last_folder = None
+
+ self.menu = None
+ self.common_actions = None
+
+ # Enable drag events
+ self.setDragEnabled(True)
+
+ #---- Context menu
+ def setup_common_actions(self):
+ """Setup context menu common actions"""
+ actions = super(ExplorerTreeWidget, self).setup_common_actions()
+ if self.show_cd_only is None:
+ # Enabling the 'show current directory only' option but do not
+ # allow the user to disable it
+ self.show_cd_only = True
+ else:
+ # Show current directory only
+ cd_only_action = create_action(self,
+ _("Show current directory only"),
+ toggled=self.toggle_show_cd_only)
+ cd_only_action.setChecked(self.show_cd_only)
+ self.toggle_show_cd_only(self.show_cd_only)
+ actions.append(cd_only_action)
+ return actions
+
+ @Slot(bool)
+ def toggle_show_cd_only(self, checked):
+ """Toggle show current directory only mode"""
+ self.parent_widget.sig_option_changed.emit('show_cd_only', checked)
+ self.show_cd_only = checked
+ if checked:
+ if self.__last_folder is not None:
+ self.set_current_folder(self.__last_folder)
+ elif self.__original_root_index is not None:
+ self.setRootIndex(self.__original_root_index)
+
+ #---- Refreshing widget
+ def set_current_folder(self, folder):
+ """Set current folder and return associated model index"""
+ index = self.fsmodel.setRootPath(folder)
+ self.__last_folder = folder
+ if self.show_cd_only:
+ if self.__original_root_index is None:
+ self.__original_root_index = self.rootIndex()
+ self.setRootIndex(index)
+ return index
+
+ def get_current_folder(self):
+ return self.__last_folder
+
+ def refresh(self, new_path=None, force_current=False):
+ """Refresh widget
+ force=False: won't refresh widget if path has not changed"""
+ if new_path is None:
+ new_path = getcwd_or_home()
+ if force_current:
+ index = self.set_current_folder(new_path)
+ self.expand(index)
+ self.setCurrentIndex(index)
+ self.set_previous_enabled.emit(
+ self.histindex is not None and self.histindex > 0)
+ self.set_next_enabled.emit(self.histindex is not None and \
+ self.histindex < len(self.history)-1)
+ # Disable the view of .spyproject.
+ self.filter_directories()
+
+ #---- Events
+ def directory_clicked(self, dirname):
+ """Directory was just clicked"""
+ self.chdir(directory=dirname)
+
+ #---- Files/Directories Actions
+ @Slot()
+ def go_to_parent_directory(self):
+ """Go to parent directory"""
+ self.chdir(osp.abspath(osp.join(getcwd_or_home(), os.pardir)))
+
+ @Slot()
+ def go_to_previous_directory(self):
+ """Back to previous directory"""
+ self.histindex -= 1
+ self.chdir(browsing_history=True)
+
+ @Slot()
+ def go_to_next_directory(self):
+ """Return to next directory"""
+ self.histindex += 1
+ self.chdir(browsing_history=True)
+
+ def update_history(self, directory):
+ """Update browse history"""
+ try:
+ directory = osp.abspath(to_text_string(directory))
+ if directory in self.history:
+ self.histindex = self.history.index(directory)
+ except Exception:
+ user_directory = get_home_dir()
+ self.chdir(directory=user_directory, browsing_history=True)
+
+ def chdir(self, directory=None, browsing_history=False):
+ """Set directory as working directory"""
+ if directory is not None:
+ directory = osp.abspath(to_text_string(directory))
+ if browsing_history:
+ directory = self.history[self.histindex]
+ elif directory in self.history:
+ self.histindex = self.history.index(directory)
+ else:
+ if self.histindex is None:
+ self.history = []
+ else:
+ self.history = self.history[:self.histindex+1]
+ if len(self.history) == 0 or \
+ (self.history and self.history[-1] != directory):
+ self.history.append(directory)
+ self.histindex = len(self.history)-1
+ directory = to_text_string(directory)
+ try:
+ PermissionError
+ FileNotFoundError
+ except NameError:
+ PermissionError = OSError
+ if os.name == 'nt':
+ FileNotFoundError = WindowsError
+ else:
+ FileNotFoundError = IOError
+ try:
+ os.chdir(directory)
+ self.sig_open_dir.emit(directory)
+ self.refresh(new_path=directory, force_current=True)
+ except PermissionError:
+ QMessageBox.critical(self.parent_widget, "Error",
+ _("You don't have the right permissions to "
+ "open this directory"))
+ except FileNotFoundError:
+ # Handle renaming directories on the fly. See issue #5183
+ self.history.pop(self.histindex)
+
+
+class ExplorerWidget(QWidget):
+ """Explorer widget"""
+ sig_option_changed = Signal(str, object)
+ sig_open_file = Signal(str)
+ open_dir = Signal(str)
+
+ def __init__(self, parent=None, name_filters=['*.py', '*.pyw'],
+ show_all=False, show_cd_only=None, show_icontext=True,
+ single_click_to_open=False,
+ options_button=None):
+ QWidget.__init__(self, parent)
+
+ # Widgets
+ self.treewidget = ExplorerTreeWidget(self, show_cd_only=show_cd_only)
+ button_previous = QToolButton(self)
+ button_next = QToolButton(self)
+ button_parent = QToolButton(self)
+ self.button_menu = options_button or QToolButton(self)
+ self.action_widgets = [button_previous, button_next, button_parent,
+ self.button_menu]
+
+ # Actions
+ icontext_action = create_action(self, _("Show icons and text"),
+ toggled=self.toggle_icontext)
+ previous_action = create_action(self, text=_("Previous"),
+ icon=ima.icon('ArrowBack'),
+ triggered=self.treewidget.go_to_previous_directory)
+ next_action = create_action(self, text=_("Next"),
+ icon=ima.icon('ArrowForward'),
+ triggered=self.treewidget.go_to_next_directory)
+ parent_action = create_action(self, text=_("Parent"),
+ icon=ima.icon('ArrowUp'),
+ triggered=self.treewidget.go_to_parent_directory)
+
+ # Setup widgets
+ self.treewidget.setup(
+ name_filters=name_filters,
+ show_all=show_all,
+ single_click_to_open=single_click_to_open,
+ )
+ self.treewidget.chdir(getcwd_or_home())
+ self.treewidget.common_actions += [None, icontext_action]
+
+ button_previous.setDefaultAction(previous_action)
+ previous_action.setEnabled(False)
+
+ button_next.setDefaultAction(next_action)
+ next_action.setEnabled(False)
+
+ button_parent.setDefaultAction(parent_action)
+
+ self.toggle_icontext(show_icontext)
+ icontext_action.setChecked(show_icontext)
+
+ for widget in self.action_widgets:
+ widget.setAutoRaise(True)
+ widget.setIconSize(QSize(16, 16))
+
+ # Layouts
+ blayout = QHBoxLayout()
+ blayout.addWidget(button_previous)
+ blayout.addWidget(button_next)
+ blayout.addWidget(button_parent)
+ blayout.addStretch()
+ blayout.addWidget(self.button_menu)
+
+ layout = create_plugin_layout(blayout, self.treewidget)
+ self.setLayout(layout)
+
+ # Signals and slots
+ self.treewidget.set_previous_enabled.connect(
+ previous_action.setEnabled)
+ self.treewidget.set_next_enabled.connect(next_action.setEnabled)
+
+ @Slot(bool)
+ def toggle_icontext(self, state):
+ """Toggle icon text"""
+ self.sig_option_changed.emit('show_icontext', state)
+ for widget in self.action_widgets:
+ if widget is not self.button_menu:
+ if state:
+ widget.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
+ else:
+ widget.setToolButtonStyle(Qt.ToolButtonIconOnly)
+
+
+#==============================================================================
+# Tests
+#==============================================================================
+class FileExplorerTest(QWidget):
+ def __init__(self, directory=None):
+ QWidget.__init__(self)
+ vlayout = QVBoxLayout()
+ self.setLayout(vlayout)
+ self.explorer = ExplorerWidget(self, show_cd_only=None)
+ if directory is not None:
+ self.directory = directory
+ else:
+ self.directory = osp.dirname(osp.abspath(__file__))
+ vlayout.addWidget(self.explorer)
+
+ hlayout1 = QHBoxLayout()
+ vlayout.addLayout(hlayout1)
+ label = QLabel("Open file:")
+ label.setAlignment(Qt.AlignRight)
+ hlayout1.addWidget(label)
+ self.label1 = QLabel()
+ hlayout1.addWidget(self.label1)
+ self.explorer.sig_open_file.connect(self.label1.setText)
+
+ hlayout2 = QHBoxLayout()
+ vlayout.addLayout(hlayout2)
+ label = QLabel("Open dir:")
+ label.setAlignment(Qt.AlignRight)
+ hlayout2.addWidget(label)
+ self.label2 = QLabel()
+ hlayout2.addWidget(self.label2)
+ self.explorer.open_dir.connect(self.label2.setText)
+
+ hlayout3 = QHBoxLayout()
+ vlayout.addLayout(hlayout3)
+ label = QLabel("Option changed:")
+ label.setAlignment(Qt.AlignRight)
+ hlayout3.addWidget(label)
+ self.label3 = QLabel()
+ hlayout3.addWidget(self.label3)
+ self.explorer.sig_option_changed.connect(
+ lambda x, y: self.label3.setText('option_changed: %r, %r' % (x, y)))
+ self.explorer.open_dir.connect(
+ lambda: self.explorer.treewidget.refresh('..'))
+
+
+class ProjectExplorerTest(QWidget):
+ def __init__(self, parent=None):
+ QWidget.__init__(self, parent)
+ vlayout = QVBoxLayout()
+ self.setLayout(vlayout)
+ self.treewidget = FilteredDirView(self)
+ self.treewidget.setup_view()
+ self.treewidget.set_root_path(osp.dirname(osp.abspath(__file__)))
+ self.treewidget.set_folder_names(['variableexplorer'])
+ self.treewidget.setup_project_view()
+ vlayout.addWidget(self.treewidget)
+
+
+def test(file_explorer):
+ from spyder.utils.qthelpers import qapplication
+ app = qapplication()
+ if file_explorer:
+ test = FileExplorerTest()
+ else:
+ test = ProjectExplorerTest()
+ test.resize(640, 480)
+ test.show()
+ app.exec_()
+
+
+if __name__ == "__main__":
+ test(file_explorer=True)
+ test(file_explorer=False)
diff --git a/spyder/plugins/findinfiles.py b/spyder/plugins/findinfiles.py
deleted file mode 100644
index bf1fe57945e..00000000000
--- a/spyder/plugins/findinfiles.py
+++ /dev/null
@@ -1,207 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright © Spyder Project Contributors
-# Licensed under the terms of the MIT License
-# (see spyder/__init__.py for details)
-
-"""Find in Files Plugin"""
-
-# pylint: disable=C0103
-# pylint: disable=R0903
-# pylint: disable=R0911
-# pylint: disable=R0201
-
-# Standard library imports
-import sys
-
-# Third party imports
-from qtpy.QtCore import Signal, Slot, Qt
-from qtpy.QtGui import QKeySequence
-from qtpy.QtWidgets import QApplication, QVBoxLayout
-
-# Local imports
-from spyder.api.plugins import SpyderPluginWidget
-from spyder.config.base import _
-from spyder.config.utils import get_edit_extensions
-from spyder.utils.misc import getcwd_or_home
-from spyder.utils import icon_manager as ima
-from spyder.utils.qthelpers import create_action, MENU_SEPARATOR
-from spyder.widgets.findinfiles import FindInFilesWidget
-
-
-class FindInFiles(SpyderPluginWidget):
- """Find in files DockWidget."""
-
- CONF_SECTION = 'find_in_files'
- sig_option_changed = Signal(str, object)
- toggle_visibility = Signal(bool)
-
- def __init__(self, parent=None):
- """Initialization."""
- SpyderPluginWidget.__init__(self, parent)
-
- supported_encodings = self.get_option('supported_encodings')
- search_path = self.get_option('search_path', None)
- self.search_text_samples = self.get_option('search_text_samples')
- search_text = self.get_option('search_text')
- search_text = [txt for txt in search_text \
- if txt not in self.search_text_samples]
- search_text += self.search_text_samples
- search_text_regexp = self.get_option('search_text_regexp')
- exclude = self.get_option('exclude')
- exclude_idx = self.get_option('exclude_idx', None)
- exclude_regexp = self.get_option('exclude_regexp')
- in_python_path = self.get_option('in_python_path')
- more_options = self.get_option('more_options')
- case_sensitive = self.get_option('case_sensitive')
- path_history = self.get_option('path_history', [])
-
- self.findinfiles = FindInFilesWidget(
- self,
- search_text, search_text_regexp, search_path,
- exclude, exclude_idx, exclude_regexp,
- supported_encodings,
- in_python_path, more_options,
- case_sensitive, path_history,
- options_button=self.options_button)
-
- layout = QVBoxLayout()
- layout.addWidget(self.findinfiles)
- self.setLayout(layout)
-
- # Initialize plugin
- self.initialize_plugin()
-
- self.toggle_visibility.connect(self.toggle)
-
- def toggle(self, state):
- """Toggle widget visibility"""
- if self.dockwidget:
- self.dockwidget.setVisible(state)
-
- def refreshdir(self):
- """Refresh search directory"""
- self.findinfiles.find_options.set_directory(
- getcwd_or_home())
-
- def set_project_path(self, path):
- """Refresh current project path"""
- self.findinfiles.find_options.set_project_path(path)
-
- def set_current_opened_file(self, path):
- """Get path of current opened file in editor"""
- self.findinfiles.find_options.set_file_path(path)
-
- def unset_project_path(self):
- """Refresh current project path"""
- self.findinfiles.find_options.disable_project_search()
-
- @Slot()
- def findinfiles_callback(self):
- """Find in files callback"""
- widget = QApplication.focusWidget()
- if not self.ismaximized:
- self.dockwidget.setVisible(True)
- self.dockwidget.raise_()
- text = ''
- try:
- if widget.has_selected_text():
- text = widget.get_selected_text()
- except AttributeError:
- # This is not a text widget deriving from TextEditBaseWidget
- pass
- self.findinfiles.set_search_text(text)
- if text:
- self.findinfiles.find()
-
- #------ SpyderPluginMixin API ---------------------------------------------
- def switch_to_plugin(self):
- """Switch to plugin
- This method is called when pressing plugin's shortcut key"""
- self.findinfiles_callback() # Necessary at least with PyQt5 on Windows
- super(SpyderPluginWidget, self).switch_to_plugin()
-
- #------ SpyderPluginWidget API --------------------------------------------
- def get_plugin_title(self):
- """Return widget title"""
- return _("Find in files")
-
- def get_focus_widget(self):
- """
- Return the widget to give focus to when
- this plugin's dockwidget is raised on top-level
- """
- return self.findinfiles.find_options.search_text
-
- def get_plugin_actions(self):
- """Return a list of actions related to plugin"""
- return []
-
- def register_plugin(self):
- """Register plugin in Spyder's main window"""
- self.findinfiles.get_pythonpath_callback = \
- self.main.get_spyder_pythonpath
- self.main.add_dockwidget(self)
- self.findinfiles.result_browser.sig_edit_goto.connect(
- self.main.editor.load)
- self.findinfiles.find_options.redirect_stdio.connect(
- self.main.redirect_internalshell_stdio)
- self.main.workingdirectory.refresh_findinfiles.connect(self.refreshdir)
- self.main.projects.sig_project_loaded.connect(self.set_project_path)
- self.main.projects.sig_project_closed.connect(self.unset_project_path)
- self.main.editor.open_file_update.connect(self.set_current_opened_file)
-
- findinfiles_action = create_action(
- self, _("&Find in files"),
- icon=ima.icon('findf'),
- triggered=self.switch_to_plugin,
- shortcut=QKeySequence(self.shortcut),
- context=Qt.WidgetShortcut,
- tip=_("Search text in multiple files"))
-
- self.main.search_menu_actions += [MENU_SEPARATOR, findinfiles_action]
- self.main.search_toolbar_actions += [MENU_SEPARATOR,
- findinfiles_action]
- self.refreshdir()
-
- def refresh_plugin(self):
- """Refresh widget"""
- pass
-
- def closing_plugin(self, cancelable=False):
- """Perform actions before parent main window is closed"""
- self.findinfiles.closing_widget() # stop search thread and clean-up
- options = self.findinfiles.find_options.get_options(all=True)
- if options is not None:
- (search_text, text_re, search_path,
- exclude, exclude_idx, exclude_re,
- in_python_path, more_options, case_sensitive,
- path_history) = options
- hist_limit = 15
- search_text = search_text[:hist_limit]
- search_path = search_path[:hist_limit]
- exclude = exclude[:hist_limit]
- path_history = path_history[-hist_limit:]
- self.set_option('search_text', search_text)
- self.set_option('search_text_regexp', text_re)
- self.set_option('search_path', search_path)
- self.set_option('exclude', exclude)
- self.set_option('exclude_idx', exclude_idx)
- self.set_option('exclude_regexp', exclude_re)
- self.set_option('in_python_path', in_python_path)
- self.set_option('more_options', more_options)
- self.set_option('case_sensitive', case_sensitive)
- self.set_option('path_history', path_history)
- return True
-
-
-def test():
- from spyder.utils.qthelpers import qapplication
- app = qapplication()
- widget = FindInFiles()
- widget.show()
- sys.exit(app.exec_())
-
-
-if __name__ == '__main__':
- test()
diff --git a/spyder/plugins/findinfiles/__init__.py b/spyder/plugins/findinfiles/__init__.py
new file mode 100644
index 00000000000..27a9e1c4db5
--- /dev/null
+++ b/spyder/plugins/findinfiles/__init__.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+spyder.plugins.findinfiles.plugin.plugin
+===========
+
+Find in files plugin.
+"""
diff --git a/spyder/plugins/findinfiles/plugin.py b/spyder/plugins/findinfiles/plugin.py
new file mode 100644
index 00000000000..db5365f4ca1
--- /dev/null
+++ b/spyder/plugins/findinfiles/plugin.py
@@ -0,0 +1,204 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Find in Files Plugin"""
+
+# pylint: disable=C0103
+# pylint: disable=R0903
+# pylint: disable=R0911
+# pylint: disable=R0201
+
+# Standard library imports
+import sys
+
+# Third party imports
+from qtpy.QtCore import Signal, Slot, Qt
+from qtpy.QtGui import QKeySequence
+from qtpy.QtWidgets import QApplication, QVBoxLayout
+
+# Local imports
+from spyder.api.plugins import SpyderPluginWidget
+from spyder.config.base import _
+from spyder.config.utils import get_edit_extensions
+from spyder.utils.misc import getcwd_or_home
+from spyder.utils import icon_manager as ima
+from spyder.utils.qthelpers import create_action, MENU_SEPARATOR
+from spyder.plugins.findinfiles.widgets import FindInFilesWidget
+
+
+class FindInFiles(SpyderPluginWidget):
+ """Find in files DockWidget."""
+
+ CONF_SECTION = 'find_in_files'
+ toggle_visibility = Signal(bool)
+
+ def __init__(self, parent=None):
+ """Initialization."""
+ SpyderPluginWidget.__init__(self, parent)
+
+ supported_encodings = self.get_option('supported_encodings')
+ self.search_text_samples = self.get_option('search_text_samples')
+ search_text = self.get_option('search_text')
+ search_text = [txt for txt in search_text \
+ if txt not in self.search_text_samples]
+ search_text += self.search_text_samples
+ search_text_regexp = self.get_option('search_text_regexp')
+ exclude = self.get_option('exclude')
+ exclude_idx = self.get_option('exclude_idx', None)
+ exclude_regexp = self.get_option('exclude_regexp')
+ more_options = self.get_option('more_options')
+ case_sensitive = self.get_option('case_sensitive')
+ path_history = self.get_option('path_history', [])
+
+ self.findinfiles = FindInFilesWidget(
+ self,
+ search_text, search_text_regexp,
+ exclude, exclude_idx, exclude_regexp,
+ supported_encodings,
+ more_options,
+ case_sensitive, path_history,
+ options_button=self.options_button,
+ text_color=ima.MAIN_FG_COLOR)
+
+ layout = QVBoxLayout()
+ layout.addWidget(self.findinfiles)
+ self.setLayout(layout)
+
+ # Initialize plugin
+ self.initialize_plugin()
+
+ self.toggle_visibility.connect(self.toggle)
+
+ def toggle(self, state):
+ """Toggle widget visibility"""
+ if self.dockwidget:
+ self.dockwidget.setVisible(state)
+
+ def refreshdir(self):
+ """Refresh search directory"""
+ self.findinfiles.find_options.set_directory(
+ getcwd_or_home())
+
+ def set_project_path(self, path):
+ """Refresh current project path"""
+ self.findinfiles.find_options.set_project_path(path)
+
+ def set_current_opened_file(self, path):
+ """Get path of current opened file in editor"""
+ self.findinfiles.find_options.set_file_path(path)
+
+ def unset_project_path(self):
+ """Refresh current project path"""
+ self.findinfiles.find_options.disable_project_search()
+
+ @Slot()
+ def findinfiles_callback(self):
+ """Find in files callback"""
+ widget = QApplication.focusWidget()
+ if not self.ismaximized:
+ self.dockwidget.setVisible(True)
+ self.dockwidget.raise_()
+ text = ''
+ try:
+ if widget.has_selected_text():
+ text = widget.get_selected_text()
+ except AttributeError:
+ # This is not a text widget deriving from TextEditBaseWidget
+ pass
+ self.findinfiles.set_search_text(text)
+ if text:
+ self.findinfiles.find()
+
+ #------ SpyderPluginMixin API ---------------------------------------------
+ def switch_to_plugin(self):
+ """Switch to plugin
+ This method is called when pressing plugin's shortcut key"""
+ self.findinfiles_callback() # Necessary at least with PyQt5 on Windows
+ super(SpyderPluginWidget, self).switch_to_plugin()
+
+ #------ SpyderPluginWidget API --------------------------------------------
+ def get_plugin_title(self):
+ """Return widget title"""
+ return _("Find")
+
+ def get_focus_widget(self):
+ """
+ Return the widget to give focus to when
+ this plugin's dockwidget is raised on top-level
+ """
+ return self.findinfiles.find_options.search_text
+
+ def get_plugin_actions(self):
+ """Return a list of actions related to plugin"""
+ return self.findinfiles.result_browser.get_menu_actions()
+
+ def register_plugin(self):
+ """Register plugin in Spyder's main window"""
+ self.main.add_dockwidget(self)
+ self.findinfiles.result_browser.sig_edit_goto.connect(
+ self.main.editor.load)
+ self.findinfiles.find_options.redirect_stdio.connect(
+ self.main.redirect_internalshell_stdio)
+ self.main.workingdirectory.refresh_findinfiles.connect(self.refreshdir)
+ self.main.projects.sig_project_loaded.connect(self.set_project_path)
+ self.main.projects.sig_project_closed.connect(self.unset_project_path)
+ self.main.editor.open_file_update.connect(self.set_current_opened_file)
+
+ findinfiles_action = create_action(
+ self, _("&Find in files"),
+ icon=ima.icon('findf'),
+ triggered=self.switch_to_plugin,
+ shortcut=QKeySequence(self.shortcut),
+ context=Qt.WidgetShortcut,
+ tip=_("Search text in multiple files"))
+
+ self.main.search_menu_actions += [MENU_SEPARATOR, findinfiles_action]
+ self.main.search_toolbar_actions += [MENU_SEPARATOR,
+ findinfiles_action]
+ self.refreshdir()
+
+ def refresh_plugin(self):
+ """Refresh widget"""
+ pass
+
+ def closing_plugin(self, cancelable=False):
+ """Perform actions before parent main window is closed"""
+ self.findinfiles.closing_widget() # stop search thread and clean-up
+ options = self.findinfiles.find_options.get_options(to_save=True)
+ if options is not None:
+ (search_text, text_re,
+ exclude, exclude_idx, exclude_re,
+ more_options, case_sensitive,
+ path_history) = options
+ hist_limit = 15
+ search_text = search_text[:hist_limit]
+ exclude = exclude[:hist_limit]
+ path_history = path_history[-hist_limit:]
+ self.set_option('search_text', search_text)
+ self.set_option('search_text_regexp', text_re)
+ self.set_option('exclude', exclude)
+ self.set_option('exclude_idx', exclude_idx)
+ self.set_option('exclude_regexp', exclude_re)
+ self.set_option('more_options', more_options)
+ self.set_option('case_sensitive', case_sensitive)
+ self.set_option('path_history', path_history)
+ return True
+
+ def on_first_registration(self):
+ """Action to be performed on first plugin registration"""
+ self.main.tabify_plugins(self.main.variableexplorer, self)
+
+
+def test():
+ from spyder.utils.qthelpers import qapplication
+ app = qapplication()
+ widget = FindInFiles()
+ widget.show()
+ sys.exit(app.exec_())
+
+
+if __name__ == '__main__':
+ test()
diff --git a/spyder/utils/ipython/tests/__init__.py b/spyder/plugins/findinfiles/tests/__init__.py
similarity index 100%
rename from spyder/utils/ipython/tests/__init__.py
rename to spyder/plugins/findinfiles/tests/__init__.py
diff --git a/spyder/widgets/tests/data/ham.txt b/spyder/plugins/findinfiles/tests/data/ham.txt
similarity index 100%
rename from spyder/widgets/tests/data/ham.txt
rename to spyder/plugins/findinfiles/tests/data/ham.txt
diff --git a/spyder/widgets/tests/data/spam.cpp b/spyder/plugins/findinfiles/tests/data/spam.cpp
similarity index 100%
rename from spyder/widgets/tests/data/spam.cpp
rename to spyder/plugins/findinfiles/tests/data/spam.cpp
diff --git a/spyder/widgets/tests/data/spam.py b/spyder/plugins/findinfiles/tests/data/spam.py
similarity index 100%
rename from spyder/widgets/tests/data/spam.py
rename to spyder/plugins/findinfiles/tests/data/spam.py
diff --git a/spyder/widgets/tests/data/spam.txt b/spyder/plugins/findinfiles/tests/data/spam.txt
similarity index 100%
rename from spyder/widgets/tests/data/spam.txt
rename to spyder/plugins/findinfiles/tests/data/spam.txt
diff --git a/spyder/plugins/findinfiles/tests/test_plugin.py b/spyder/plugins/findinfiles/tests/test_plugin.py
new file mode 100644
index 00000000000..51918c5e6e0
--- /dev/null
+++ b/spyder/plugins/findinfiles/tests/test_plugin.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright © Spyder Project Contributors
+#
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+"""Test scripts for `findinfiles` plugin."""
+
+# Standard library imports
+import re
+import os
+import os.path as osp
+
+# 3rd party imports
+import pytest
+
+# Local imports
+from spyder.plugins.findinfiles.plugin import FindInFiles
+from spyder.plugins.findinfiles.widgets import SELECT_OTHER
+
+LOCATION = osp.realpath(osp.join(os.getcwd(), osp.dirname(__file__)))
+NONASCII_DIR = osp.join(LOCATION, u"èáïü Øαôå 字分误")
+if not osp.exists(NONASCII_DIR):
+ os.makedirs(NONASCII_DIR)
+
+
+@pytest.fixture
+def findinfiles(qtbot):
+ """Set up SearchInComboBox combobox."""
+ findinfiles_plugin = FindInFiles()
+ qtbot.addWidget(findinfiles_plugin)
+ return findinfiles_plugin
+
+
+# ---- Tests for FindInFiles plugin
+
+def test_closing_plugin(findinfiles, qtbot, mocker):
+ """
+ Test that the external paths listed in the combobox are saved and loaded
+ correctly from the spyder config file.
+ """
+ path_selection_combo = findinfiles.findinfiles.find_options.path_selection_combo
+ path_selection_combo.clear_external_paths()
+ assert path_selection_combo.get_external_paths() == []
+
+ # Add external paths to the path_selection_combo.
+ expected_results = [
+ LOCATION,
+ osp.dirname(LOCATION),
+ osp.dirname(osp.dirname(LOCATION)),
+ NONASCII_DIR
+ ]
+ for external_path in expected_results:
+ mocker.patch('spyder.plugins.findinfiles.widgets.getexistingdirectory',
+ return_value=external_path)
+ path_selection_combo.setCurrentIndex(SELECT_OTHER)
+ assert path_selection_combo.get_external_paths() == expected_results
+
+ findinfiles.closing_plugin()
+ assert findinfiles.get_option('path_history') == expected_results
+
+ # Close the plugin and assert that the external_path_history
+ # has been saved and loaded as expected.
+ findinfiles.close()
+ path_selection_combo = findinfiles.findinfiles.find_options.path_selection_combo
+ assert path_selection_combo.get_external_paths() == expected_results
+
+
+
+if __name__ == "__main__":
+ pytest.main(['-x', osp.basename(__file__), '-v', '-rw'])
diff --git a/spyder/plugins/findinfiles/tests/test_widgets.py b/spyder/plugins/findinfiles/tests/test_widgets.py
new file mode 100644
index 00000000000..55305866b0c
--- /dev/null
+++ b/spyder/plugins/findinfiles/tests/test_widgets.py
@@ -0,0 +1,569 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+
+"""
+Tests for findinfiles.py
+"""
+
+# Test library imports
+import os
+import os.path as osp
+
+# Third party imports
+from flaky import flaky
+import pytest
+from qtpy.QtCore import Qt
+
+# Local imports
+from spyder.plugins.findinfiles import widgets
+from spyder.plugins.findinfiles.widgets import (FindInFilesWidget, SearchInComboBox,
+ EXTERNAL_PATHS, SELECT_OTHER, CWD,
+ CLEAR_LIST, PROJECT, FILE_PATH,
+ QMessageBox)
+from spyder.py3compat import PY2
+
+LOCATION = osp.realpath(osp.join(os.getcwd(), osp.dirname(__file__)))
+NONASCII_DIR = osp.join(LOCATION, u"èáïü Øαôå 字分误")
+if not osp.exists(NONASCII_DIR):
+ os.makedirs(NONASCII_DIR)
+
+
+def process_search_results(results):
+ """
+ Transform result representation from the output of the widget to the
+ test framework comparison representation.
+ """
+ matches = {}
+ for result in results.values():
+ file, line, col = result
+ filename = osp.basename(file)
+ if filename not in matches:
+ matches[filename] = []
+ matches[filename].append((line, col))
+ matches[filename] = sorted(matches[filename])
+ return matches
+
+
+@pytest.fixture
+def findinfiles(qtbot, request):
+ """Set up find in files widget."""
+ if getattr(request, 'param', False):
+ param = request.param
+ else:
+ param = None
+
+ if param:
+ widget = FindInFilesWidget(None, **param)
+ else:
+ widget = FindInFilesWidget(None)
+
+ widget.resize(640, 480)
+ qtbot.addWidget(widget)
+ widget.show()
+ return widget
+
+
+@pytest.fixture
+def searchin_combobox(qtbot, request):
+ """Set up SearchInComboBox combobox."""
+ from spyder.plugins.findinfiles import widgets
+
+ if getattr(request, 'param', False):
+ param = request.param
+ else:
+ param = None
+
+ if param and param.get('max_history_path'):
+ widgets.MAX_PATH_HISTORY = param.get('max_history_path')
+
+ external_path_history = [
+ LOCATION,
+ osp.dirname(LOCATION),
+ osp.dirname(osp.dirname(LOCATION)),
+ osp.dirname(osp.dirname(osp.dirname(LOCATION))),
+ osp.dirname(LOCATION),
+ osp.join(LOCATION, 'path_that_does_not_exist')
+ ]
+ searchin_combobox = SearchInComboBox(external_path_history)
+ qtbot.addWidget(searchin_combobox)
+ return searchin_combobox
+
+
+def expected_results():
+ results = {'spam.txt': [(1, 0), (1, 5), (3, 22)],
+ 'spam.py': [(2, 7), (5, 1), (7, 12)],
+ 'spam.cpp': [(2, 9), (6, 15), (8, 2), (11, 4),
+ (11, 10), (13, 12)]
+ }
+ return results
+
+
+def expected_case_unsensitive_results():
+ results = {'spam.txt': [(1, 10)],
+ 'ham.txt': [(1, 0), (1, 10), (3, 0), (4, 0),
+ (5, 4), (9, 0), (10, 0)]}
+ return results
+
+
+@flaky(max_runs=5)
+def test_find_in_files_search(findinfiles, qtbot):
+ """
+ Test the find in files utility by searching a string located on a set of
+ known files.
+
+ The results of the test should be equal to the expected search result
+ values.
+ """
+ findinfiles.set_search_text("spam")
+ findinfiles.find_options.set_directory(osp.join(LOCATION, "data"))
+ findinfiles.find()
+ blocker = qtbot.waitSignal(findinfiles.sig_finished)
+ blocker.wait()
+ matches = process_search_results(findinfiles.result_browser.data)
+ assert expected_results() == matches
+
+
+@pytest.mark.parametrize('findinfiles',
+ [{'exclude': r"\.py$", 'exclude_regexp': True}],
+ indirect=True)
+def test_exclude_extension_regex(findinfiles, qtbot):
+ findinfiles.set_search_text("spam")
+ findinfiles.find_options.set_directory(osp.join(LOCATION, "data"))
+ findinfiles.find()
+ blocker = qtbot.waitSignal(findinfiles.sig_finished)
+ blocker.wait()
+ matches = process_search_results(findinfiles.result_browser.data)
+ files_filtered = True
+ for file in matches:
+ filename, ext = osp.splitext(file)
+ if ext == '.py':
+ files_filtered = False
+ break
+ assert files_filtered
+
+
+@pytest.mark.parametrize('findinfiles',
+ [{'exclude': "*.py", 'exclude_regexp': False}],
+ indirect=True)
+def test_exclude_extension_string(findinfiles, qtbot):
+ findinfiles.set_search_text("spam")
+ findinfiles.find_options.set_directory(osp.join(LOCATION, "data"))
+ findinfiles.find()
+ blocker = qtbot.waitSignal(findinfiles.sig_finished)
+ blocker.wait()
+ matches = process_search_results(findinfiles.result_browser.data)
+ files_filtered = True
+ for file in matches:
+ filename, ext = osp.splitext(file)
+ if ext == '.py':
+ files_filtered = False
+ break
+ assert files_filtered
+
+
+@pytest.mark.parametrize('findinfiles',
+ [{'exclude': "", 'exclude_regexp': True}],
+ indirect=True)
+def test_exclude_extension_empty_regex(findinfiles, qtbot):
+ findinfiles.set_search_text("spam")
+ findinfiles.find_options.set_directory(osp.join(LOCATION, "data"))
+ findinfiles.find()
+ blocker = qtbot.waitSignal(findinfiles.sig_finished)
+ blocker.wait()
+ matches = process_search_results(findinfiles.result_browser.data)
+ assert expected_results() == matches
+
+
+@pytest.mark.parametrize('findinfiles',
+ [{'exclude': "", 'exclude_regexp': False}],
+ indirect=True)
+def test_exclude_extension_string_no_regexp(findinfiles, qtbot):
+ findinfiles.set_search_text("spam")
+ findinfiles.find_options.set_directory(osp.join(LOCATION, "data"))
+ findinfiles.find()
+ blocker = qtbot.waitSignal(findinfiles.sig_finished)
+ blocker.wait()
+ matches = process_search_results(findinfiles.result_browser.data)
+ assert expected_results() == matches
+
+
+@pytest.mark.parametrize('findinfiles',
+ [{'exclude': "*.py, *.cpp", 'exclude_regexp': False}],
+ indirect=True)
+def test_exclude_extension_multiple_string(findinfiles, qtbot):
+ findinfiles.set_search_text("spam")
+ findinfiles.find_options.set_directory(osp.join(LOCATION, "data"))
+ findinfiles.find()
+ blocker = qtbot.waitSignal(findinfiles.sig_finished)
+ blocker.wait()
+ matches = process_search_results(findinfiles.result_browser.data)
+ files_filtered = True
+ for file in matches:
+ filename, ext = osp.splitext(file)
+ if ext in ['.py', '.cpp']:
+ files_filtered = False
+ break
+ assert files_filtered
+
+
+@pytest.mark.parametrize("line_input", ['nnnnn', 'ñandú'])
+def test_truncate_result_with_different_input(findinfiles, qtbot, line_input):
+ """
+ Issue: 6218 - checking if truncate_result raise UnicodeDecodeError
+ """
+
+ # with
+ slice_start = 1
+ slice_end = 2
+
+ if PY2:
+ line_input_expected = line_input.decode('utf-8')
+ else:
+ line_input_expected = line_input
+
+ expected_result = u'%s%s%s' % (
+ line_input_expected[:slice_start],
+ line_input_expected[slice_start:slice_end],
+ line_input_expected[slice_end:])
+
+ # when
+ truncated_line = findinfiles.result_browser.truncate_result(
+ line_input, slice_start, slice_end)
+
+ # then
+ assert truncated_line == expected_result
+
+
+@pytest.mark.parametrize('findinfiles',
+ [{'case_sensitive': False}],
+ indirect=True)
+def test_case_unsensitive_search(findinfiles, qtbot):
+ findinfiles.set_search_text('ham')
+ findinfiles.find_options.set_directory(osp.join(LOCATION, "data"))
+ findinfiles.find()
+ blocker = qtbot.waitSignal(findinfiles.sig_finished)
+ blocker.wait()
+ matches = process_search_results(findinfiles.result_browser.data)
+ print(matches)
+ assert expected_case_unsensitive_results() == matches
+
+
+@pytest.mark.parametrize('findinfiles',
+ [{'case_sensitive': True}],
+ indirect=True)
+def test_case_sensitive_search(findinfiles, qtbot):
+ findinfiles.set_search_text('HaM')
+ findinfiles.find_options.set_directory(osp.join(LOCATION, "data"))
+ findinfiles.find()
+ blocker = qtbot.waitSignal(findinfiles.sig_finished)
+ blocker.wait()
+ matches = process_search_results(findinfiles.result_browser.data)
+ print(matches)
+ assert matches == {'ham.txt': [(9, 0)]}
+
+
+@pytest.mark.parametrize('findinfiles',
+ [{'search_text_regexp': True}],
+ indirect=True)
+def test_search_regexp_error(findinfiles, qtbot):
+ findinfiles.set_search_text("\\")
+ findinfiles.find_options.set_directory(osp.join(LOCATION, "data"))
+ findinfiles.find()
+ tooltip = findinfiles.find_options.search_text.toolTip()
+ assert findinfiles.find_options.REGEX_ERROR in tooltip
+
+
+@pytest.mark.parametrize('findinfiles',
+ [{'exclude': "\\", 'exclude_regexp': True}],
+ indirect=True)
+def test_exclude_regexp_error(findinfiles, qtbot):
+ findinfiles.set_search_text("foo")
+ findinfiles.find_options.set_directory(osp.join(LOCATION, "data"))
+ findinfiles.find()
+ tooltip = findinfiles.find_options.exclude_pattern.toolTip()
+ assert findinfiles.find_options.REGEX_ERROR in tooltip
+
+
+# ---- Tests for SearchInComboBox
+
+def test_add_external_paths(searchin_combobox, mocker):
+ """
+ Test that the external_path_history is added correctly to the
+ combobox and test that adding new external path to the combobox
+ with the QFileDialog is working as expected.
+ """
+ searchin_combobox.show()
+
+ # Assert that the external_path_history was added correctly to the
+ # combobox
+ expected_results = [
+ LOCATION,
+ osp.dirname(osp.dirname(LOCATION)),
+ osp.dirname(osp.dirname(osp.dirname(LOCATION))),
+ osp.dirname(LOCATION)
+ ]
+ assert searchin_combobox.count() == len(expected_results)+EXTERNAL_PATHS
+ assert searchin_combobox.get_external_paths() == expected_results
+ for i, expected_result in enumerate(expected_results):
+ assert expected_result == searchin_combobox.itemText(i+EXTERNAL_PATHS)
+
+ # Add a new external path to the combobox. The new path is added at the
+ # end of the combobox.
+ new_path = NONASCII_DIR
+ mocker.patch('spyder.plugins.findinfiles.widgets.getexistingdirectory',
+ return_value=new_path)
+ searchin_combobox.setCurrentIndex(SELECT_OTHER)
+
+ expected_results.append(new_path)
+ assert searchin_combobox.count() == len(expected_results)+EXTERNAL_PATHS
+ assert searchin_combobox.get_external_paths() == expected_results
+ assert searchin_combobox.currentIndex() == searchin_combobox.count()-1
+
+ # Add an external path that is already listed in the combobox. In this
+ # case, the new path is removed from the list and is added back at the end.
+ new_path = LOCATION
+ mocker.patch('spyder.plugins.findinfiles.widgets.getexistingdirectory',
+ return_value=new_path)
+ searchin_combobox.setCurrentIndex(SELECT_OTHER)
+
+ expected_results.pop(0)
+ expected_results.append(new_path)
+ assert searchin_combobox.count() == len(expected_results)+EXTERNAL_PATHS
+ assert searchin_combobox.get_external_paths() == expected_results
+ assert searchin_combobox.currentIndex() == searchin_combobox.count()-1
+
+ # Cancel the action of adding a new external path. In this case, the
+ # expected results do not change.
+ mocker.patch('spyder.plugins.findinfiles.widgets.getexistingdirectory',
+ return_value='')
+ searchin_combobox.setCurrentIndex(SELECT_OTHER)
+
+ assert searchin_combobox.count() == len(expected_results)+EXTERNAL_PATHS
+ assert searchin_combobox.get_external_paths() == expected_results
+ assert searchin_combobox.currentIndex() == CWD
+
+
+def test_clear_this_list(searchin_combobox, mocker):
+ """
+ Test the option in the searchin combobox to clear the list of
+ external paths.
+ """
+ searchin_combobox.show()
+
+ # Cancel the Clear the list action and assert the result.
+ mocker.patch.object(QMessageBox, 'question', return_value=QMessageBox.No)
+ searchin_combobox.setCurrentIndex(CLEAR_LIST)
+
+ expected_results = [
+ LOCATION,
+ osp.dirname(osp.dirname(LOCATION)),
+ osp.dirname(osp.dirname(osp.dirname(LOCATION))),
+ osp.dirname(LOCATION)
+ ]
+ assert searchin_combobox.count() == len(expected_results)+EXTERNAL_PATHS
+ assert searchin_combobox.get_external_paths() == expected_results
+ assert searchin_combobox.currentIndex() == CWD
+
+ # Clear the list of external paths and assert that the list of
+ # external paths is empty.
+ mocker.patch.object(QMessageBox, 'question', return_value=QMessageBox.Yes)
+ searchin_combobox.setCurrentIndex(CLEAR_LIST)
+
+ assert searchin_combobox.count() == EXTERNAL_PATHS
+ assert searchin_combobox.get_external_paths() == []
+ assert searchin_combobox.currentIndex() == CWD
+
+
+def test_delete_path(searchin_combobox, qtbot, mocker):
+ """
+ Test that the selected external path in the combobox view is removed
+ correctly when the Delete key is pressed.
+ """
+ searchin_combobox.show()
+
+ expected_results = [
+ LOCATION,
+ osp.dirname(osp.dirname(LOCATION)),
+ osp.dirname(osp.dirname(osp.dirname(LOCATION))),
+ osp.dirname(LOCATION)
+ ]
+
+ searchin_combobox.showPopup()
+ assert searchin_combobox.currentIndex() == CWD
+ assert searchin_combobox.view().currentIndex().row() == CWD
+
+ # Assert that the delete action does nothing when the selected item in
+ # the combobox view is not an external path.
+ for i in range(EXTERNAL_PATHS):
+ searchin_combobox.view().setCurrentIndex(
+ searchin_combobox.model().index(i, 0))
+ qtbot.keyPress(searchin_combobox.view(), Qt.Key_Delete)
+
+ assert searchin_combobox.count() == len(expected_results)+EXTERNAL_PATHS
+ assert searchin_combobox.get_external_paths() == expected_results
+ assert searchin_combobox.currentIndex() == CWD
+
+ # Delete the first external path in the list.
+ searchin_combobox.view().setCurrentIndex(
+ searchin_combobox.model().index(EXTERNAL_PATHS, 0))
+ qtbot.keyPress(searchin_combobox.view(), Qt.Key_Delete)
+
+ expected_results.pop(0)
+ assert searchin_combobox.count() == len(expected_results)+EXTERNAL_PATHS
+ assert searchin_combobox.get_external_paths() == expected_results
+ assert searchin_combobox.currentIndex() == EXTERNAL_PATHS
+ assert searchin_combobox.view().currentIndex().row() == EXTERNAL_PATHS
+
+ # Delete the second external path in the remaining list.
+ searchin_combobox.view().setCurrentIndex(
+ searchin_combobox.model().index(EXTERNAL_PATHS+1, 0))
+ qtbot.keyPress(searchin_combobox.view(), Qt.Key_Delete)
+
+ expected_results.pop(1)
+ assert searchin_combobox.count() == len(expected_results)+EXTERNAL_PATHS
+ assert searchin_combobox.get_external_paths() == expected_results
+ assert searchin_combobox.currentIndex() == EXTERNAL_PATHS+1
+ assert searchin_combobox.view().currentIndex().row() == EXTERNAL_PATHS+1
+
+ # Delete the last external path in the list.
+ searchin_combobox.view().setCurrentIndex(
+ searchin_combobox.model().index(searchin_combobox.count()-1, 0))
+ qtbot.keyPress(searchin_combobox.view(), Qt.Key_Delete)
+
+ expected_results.pop()
+ assert searchin_combobox.count() == len(expected_results)+EXTERNAL_PATHS
+ assert searchin_combobox.get_external_paths() == expected_results
+ assert searchin_combobox.currentIndex() == searchin_combobox.count()-1
+ assert (searchin_combobox.view().currentIndex().row() ==
+ searchin_combobox.count()-1)
+
+ # Delete the last remaining external path in the list.
+ searchin_combobox.view().setCurrentIndex(
+ searchin_combobox.model().index(EXTERNAL_PATHS, 0))
+ qtbot.keyPress(searchin_combobox.view(), Qt.Key_Delete)
+
+ assert searchin_combobox.count() == EXTERNAL_PATHS
+ assert searchin_combobox.get_external_paths() == []
+ assert searchin_combobox.currentIndex() == CWD
+ assert searchin_combobox.view().currentIndex().row() == CWD
+
+
+def test_set_project_path(findinfiles, qtbot):
+ """
+ Test setting the project path of the SearchInComboBox from the
+ FindInFilesWidget.
+ """
+ find_options = findinfiles.find_options
+ path_selection_combo = find_options.path_selection_combo
+ findinfiles.show()
+
+ assert path_selection_combo.model().item(PROJECT, 0).isEnabled() is False
+ assert find_options.project_path is None
+ assert path_selection_combo.project_path is None
+
+ # Set the project path to an existing directory. For the purpose of this
+ # test, it doesn't need to be a valid Spyder project path.
+ project_path = NONASCII_DIR
+ find_options.set_project_path(project_path)
+ assert path_selection_combo.model().item(PROJECT, 0).isEnabled() is True
+ assert find_options.project_path == project_path
+ assert path_selection_combo.project_path == project_path
+
+ # Disable the project path search in the widget.
+ path_selection_combo.setCurrentIndex(PROJECT)
+ find_options.disable_project_search()
+ assert path_selection_combo.model().item(PROJECT, 0).isEnabled() is False
+ assert find_options.project_path is None
+ assert path_selection_combo.project_path is None
+ assert path_selection_combo.currentIndex() == CWD
+
+
+@pytest.mark.parametrize('findinfiles',
+ [{'external_path_history': [LOCATION,
+ osp.dirname(LOCATION),
+ osp.dirname(osp.dirname(LOCATION)),
+ NONASCII_DIR]}],
+ indirect=True)
+def test_current_search_path(findinfiles, qtbot):
+ """
+ Test that the expected search path is returned for the corresponding
+ option selected in the SearchInComboBox. This test is done using the
+ FindInFilesWidget.
+ """
+ external_paths = [
+ LOCATION,
+ osp.dirname(LOCATION),
+ osp.dirname(osp.dirname(LOCATION)),
+ NONASCII_DIR
+ ]
+
+ find_options = findinfiles.find_options
+ path_selection_combo = find_options.path_selection_combo
+ findinfiles.show()
+
+ # Set the project, file, and spyder path of the SearchInComboBox.
+ # For the purpose of this test, the project path doesn't need to be a
+ # valid Spyder project path.
+
+ directory = NONASCII_DIR
+ project_path = NONASCII_DIR
+ file_path = osp.join(directory, "spam.py")
+
+ find_options.set_directory(directory)
+ assert find_options.path == directory
+ assert path_selection_combo.path == directory
+
+ find_options.set_project_path(project_path)
+ assert find_options.project_path == project_path
+ assert path_selection_combo.project_path == project_path
+
+ find_options.set_file_path(file_path)
+ assert find_options.file_path == file_path
+ assert path_selection_combo.file_path == file_path
+
+ # Assert that the good path is returned for each option selected.
+
+ # Test for the current working directory :
+ path_selection_combo.setCurrentIndex(CWD)
+ assert path_selection_combo.get_current_searchpath() == directory
+ assert path_selection_combo.is_file_search() is False
+ # Test for the project path :
+ path_selection_combo.setCurrentIndex(PROJECT)
+ assert path_selection_combo.get_current_searchpath() == project_path
+ assert path_selection_combo.is_file_search() is False
+ # Test for the file path :
+ path_selection_combo.setCurrentIndex(FILE_PATH)
+ assert path_selection_combo.get_current_searchpath() == file_path
+ assert path_selection_combo.is_file_search() is True
+ # Test for the external file path :
+ for i, path in enumerate(external_paths):
+ path_selection_combo.setCurrentIndex(EXTERNAL_PATHS+i)
+ assert path_selection_combo.get_current_searchpath() == path
+ assert path_selection_combo.is_file_search() is False
+
+
+@pytest.mark.parametrize('searchin_combobox',
+ [{'max_history_path': 3}],
+ indirect=True)
+def test_max_history(searchin_combobox, mocker):
+ """
+ Test that the specified maximum number of external path is observed.
+ """
+ searchin_combobox.show()
+
+ # In this case, the first path of the external_path_history was removed to
+ # respect the MAX_PATH_HISTORY of 3.
+ expected_results = [
+ osp.dirname(osp.dirname(LOCATION)),
+ osp.dirname(osp.dirname(osp.dirname(LOCATION))),
+ osp.dirname(LOCATION)
+ ]
+ assert searchin_combobox.count() == len(expected_results) + EXTERNAL_PATHS
+ assert searchin_combobox.get_external_paths() == expected_results
+
+
+if __name__ == "__main__":
+ pytest.main(['-x', osp.basename(__file__), '-v', '-rw'])
diff --git a/spyder/plugins/findinfiles/widgets.py b/spyder/plugins/findinfiles/widgets.py
new file mode 100644
index 00000000000..9a05e39e832
--- /dev/null
+++ b/spyder/plugins/findinfiles/widgets.py
@@ -0,0 +1,1082 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Find in files widget"""
+
+# pylint: disable=C0103
+# pylint: disable=R0903
+# pylint: disable=R0911
+# pylint: disable=R0201
+
+# Standard library imports
+from __future__ import with_statement, print_function
+import fnmatch
+import os
+import os.path as osp
+import re
+import sys
+import math
+import traceback
+
+# Third party imports
+from qtpy.compat import getexistingdirectory
+from qtpy.QtGui import QAbstractTextDocumentLayout, QTextDocument
+from qtpy.QtCore import (QEvent, QMutex, QMutexLocker, QSize, Qt, QThread,
+ Signal, Slot)
+from qtpy.QtWidgets import (QApplication, QComboBox, QHBoxLayout, QLabel,
+ QMessageBox, QSizePolicy, QStyle,
+ QStyledItemDelegate, QStyleOptionViewItem,
+ QTreeWidgetItem, QVBoxLayout, QWidget)
+
+# Local imports
+from spyder.config.base import _
+from spyder.config.main import EXCLUDE_PATTERNS
+from spyder.py3compat import to_text_string, PY2
+from spyder.utils import icon_manager as ima
+from spyder.utils.encoding import is_text_file, to_unicode_from_fs
+from spyder.utils.misc import getcwd_or_home
+from spyder.widgets.comboboxes import PatternComboBox
+from spyder.widgets.onecolumntree import OneColumnTree
+from spyder.utils.misc import regexp_error_msg
+from spyder.utils.qthelpers import create_toolbutton
+from spyder.config.gui import get_font
+from spyder.widgets.waitingspinner import QWaitingSpinner
+
+
+ON = 'on'
+OFF = 'off'
+
+CWD = 0
+PROJECT = 1
+FILE_PATH = 2
+SELECT_OTHER = 4
+CLEAR_LIST = 5
+EXTERNAL_PATHS = 7
+
+MAX_PATH_LENGTH = 60
+MAX_PATH_HISTORY = 15
+
+
+def truncate_path(text):
+ ellipsis = '...'
+ part_len = (MAX_PATH_LENGTH - len(ellipsis)) / 2.0
+ left_text = text[:int(math.ceil(part_len))]
+ right_text = text[-int(math.floor(part_len)):]
+ return left_text + ellipsis + right_text
+
+
+class SearchThread(QThread):
+ """Find in files search thread"""
+ sig_finished = Signal(bool)
+ sig_current_file = Signal(str)
+ sig_current_folder = Signal(str)
+ sig_file_match = Signal(tuple, int)
+ sig_out_print = Signal(object)
+
+ def __init__(self, parent):
+ QThread.__init__(self, parent)
+ self.mutex = QMutex()
+ self.stopped = None
+ self.results = None
+ self.pathlist = None
+ self.total_matches = None
+ self.error_flag = None
+ self.rootpath = None
+ self.exclude = None
+ self.texts = None
+ self.text_re = None
+ self.completed = None
+ self.case_sensitive = True
+ self.results = {}
+ self.total_matches = 0
+ self.is_file = False
+
+ def initialize(self, path, is_file, exclude,
+ texts, text_re, case_sensitive):
+ self.rootpath = path
+ if exclude:
+ self.exclude = re.compile(exclude)
+ self.texts = texts
+ self.text_re = text_re
+ self.is_file = is_file
+ self.stopped = False
+ self.completed = False
+ self.case_sensitive = case_sensitive
+
+ def run(self):
+ try:
+ self.filenames = []
+ if self.is_file:
+ self.find_string_in_file(self.rootpath)
+ else:
+ self.find_files_in_path(self.rootpath)
+ except Exception:
+ # Important note: we have to handle unexpected exceptions by
+ # ourselves because they won't be catched by the main thread
+ # (known QThread limitation/bug)
+ traceback.print_exc()
+ self.error_flag = _("Unexpected error: see internal console")
+ self.stop()
+ self.sig_finished.emit(self.completed)
+
+ def stop(self):
+ with QMutexLocker(self.mutex):
+ self.stopped = True
+
+ def find_files_in_path(self, path):
+ if self.pathlist is None:
+ self.pathlist = []
+ self.pathlist.append(path)
+ for path, dirs, files in os.walk(path):
+ with QMutexLocker(self.mutex):
+ if self.stopped:
+ return False
+ try:
+ for d in dirs[:]:
+ with QMutexLocker(self.mutex):
+ if self.stopped:
+ return False
+ dirname = os.path.join(path, d)
+ if (self.exclude and
+ re.search(self.exclude, dirname + os.sep)):
+ dirs.remove(d)
+ elif d == '.git' or d == '.hg':
+ dirs.remove(d)
+ for f in files:
+ with QMutexLocker(self.mutex):
+ if self.stopped:
+ return False
+ filename = os.path.join(path, f)
+ if self.exclude and re.search(self.exclude, filename):
+ continue
+ if is_text_file(filename):
+ self.find_string_in_file(filename)
+ except re.error:
+ self.error_flag = _("invalid regular expression")
+ return False
+ return True
+
+ def find_string_in_file(self, fname):
+ self.error_flag = False
+ self.sig_current_file.emit(fname)
+ try:
+ for lineno, line in enumerate(open(fname, 'rb')):
+ for text, enc in self.texts:
+ with QMutexLocker(self.mutex):
+ if self.stopped:
+ return False
+ line_search = line
+ if not self.case_sensitive:
+ line_search = line_search.lower()
+ if self.text_re:
+ found = re.search(text, line_search)
+ if found is not None:
+ break
+ else:
+ found = line_search.find(text)
+ if found > -1:
+ break
+ try:
+ line_dec = line.decode(enc)
+ except UnicodeDecodeError:
+ line_dec = line
+ if not self.case_sensitive:
+ line = line.lower()
+ if self.text_re:
+ for match in re.finditer(text, line):
+ with QMutexLocker(self.mutex):
+ if self.stopped:
+ return False
+ self.total_matches += 1
+ self.sig_file_match.emit((osp.abspath(fname),
+ lineno + 1,
+ match.start(),
+ match.end(), line_dec),
+ self.total_matches)
+ else:
+ found = line.find(text)
+ while found > -1:
+ with QMutexLocker(self.mutex):
+ if self.stopped:
+ return False
+ self.total_matches += 1
+ self.sig_file_match.emit((osp.abspath(fname),
+ lineno + 1,
+ found,
+ found + len(text), line_dec),
+ self.total_matches)
+ for text, enc in self.texts:
+ found = line.find(text, found + 1)
+ if found > -1:
+ break
+ except IOError as xxx_todo_changeme:
+ (_errno, _strerror) = xxx_todo_changeme.args
+ self.error_flag = _("permission denied errors were encountered")
+ self.completed = True
+
+ def get_results(self):
+ return self.results, self.pathlist, self.total_matches, self.error_flag
+
+
+class SearchInComboBox(QComboBox):
+ """
+ Non editable combo box handling the path locations of the FindOptions
+ widget.
+ """
+ def __init__(self, external_path_history=[], parent=None):
+ super(SearchInComboBox, self).__init__(parent)
+ self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
+ self.setToolTip(_('Search directory'))
+ self.setEditable(False)
+
+ self.path = ''
+ self.project_path = None
+ self.file_path = None
+ self.external_path = None
+
+ self.addItem(_("Current working directory"))
+ ttip = ("Search in all files and directories present on the current"
+ " Spyder path")
+ self.setItemData(0, ttip, Qt.ToolTipRole)
+
+ self.addItem(_("Project"))
+ ttip = _("Search in all files and directories present on the"
+ " current project path (if opened)")
+ self.setItemData(1, ttip, Qt.ToolTipRole)
+ self.model().item(1, 0).setEnabled(False)
+
+ self.addItem(_("File").replace('&', ''))
+ ttip = _("Search in current opened file")
+ self.setItemData(2, ttip, Qt.ToolTipRole)
+
+ self.insertSeparator(3)
+
+ self.addItem(_("Select other directory"))
+ ttip = _("Search in other folder present on the file system")
+ self.setItemData(4, ttip, Qt.ToolTipRole)
+
+ self.addItem(_("Clear this list"))
+ ttip = _("Clear the list of other directories")
+ self.setItemData(5, ttip, Qt.ToolTipRole)
+
+ self.insertSeparator(6)
+
+ for path in external_path_history:
+ self.add_external_path(path)
+
+ self.currentIndexChanged.connect(self.path_selection_changed)
+ self.view().installEventFilter(self)
+
+ def add_external_path(self, path):
+ """
+ Adds an external path to the combobox if it exists on the file system.
+ If the path is already listed in the combobox, it is removed from its
+ current position and added back at the end. If the maximum number of
+ paths is reached, the oldest external path is removed from the list.
+ """
+ if not osp.exists(path):
+ return
+ self.removeItem(self.findText(path))
+ self.addItem(path)
+ self.setItemData(self.count() - 1, path, Qt.ToolTipRole)
+ while self.count() > MAX_PATH_HISTORY + EXTERNAL_PATHS:
+ self.removeItem(EXTERNAL_PATHS)
+
+ def get_external_paths(self):
+ """Returns a list of the external paths listed in the combobox."""
+ return [to_text_string(self.itemText(i))
+ for i in range(EXTERNAL_PATHS, self.count())]
+
+ def clear_external_paths(self):
+ """Remove all the external paths listed in the combobox."""
+ while self.count() > EXTERNAL_PATHS:
+ self.removeItem(EXTERNAL_PATHS)
+
+ def get_current_searchpath(self):
+ """
+ Returns the path corresponding to the currently selected item
+ in the combobox.
+ """
+ idx = self.currentIndex()
+ if idx == CWD:
+ return self.path
+ elif idx == PROJECT:
+ return self.project_path
+ elif idx == FILE_PATH:
+ return self.file_path
+ else:
+ return self.external_path
+
+ def is_file_search(self):
+ """Returns whether the current search path is a file."""
+ if self.currentIndex() == FILE_PATH:
+ return True
+ else:
+ return False
+
+ @Slot()
+ def path_selection_changed(self):
+ """Handles when the current index of the combobox changes."""
+ idx = self.currentIndex()
+ if idx == SELECT_OTHER:
+ external_path = self.select_directory()
+ if len(external_path) > 0:
+ self.add_external_path(external_path)
+ self.setCurrentIndex(self.count() - 1)
+ else:
+ self.setCurrentIndex(CWD)
+ elif idx == CLEAR_LIST:
+ reply = QMessageBox.question(
+ self, _("Clear other directories"),
+ _("Do you want to clear the list of other directories?"),
+ QMessageBox.Yes | QMessageBox.No)
+ if reply == QMessageBox.Yes:
+ self.clear_external_paths()
+ self.setCurrentIndex(CWD)
+ elif idx >= EXTERNAL_PATHS:
+ self.external_path = to_text_string(self.itemText(idx))
+
+ @Slot()
+ def select_directory(self):
+ """Select directory"""
+ self.__redirect_stdio_emit(False)
+ directory = getexistingdirectory(
+ self, _("Select directory"), self.path)
+ if directory:
+ directory = to_unicode_from_fs(osp.abspath(directory))
+ self.__redirect_stdio_emit(True)
+ return directory
+
+ def set_project_path(self, path):
+ """
+ Sets the project path and disables the project search in the combobox
+ if the value of path is None.
+ """
+ if path is None:
+ self.project_path = None
+ self.model().item(PROJECT, 0).setEnabled(False)
+ if self.currentIndex() == PROJECT:
+ self.setCurrentIndex(CWD)
+ else:
+ path = osp.abspath(path)
+ self.project_path = path
+ self.model().item(PROJECT, 0).setEnabled(True)
+
+ def eventFilter(self, widget, event):
+ """Used to handle key events on the QListView of the combobox."""
+ if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Delete:
+ index = self.view().currentIndex().row()
+ if index >= EXTERNAL_PATHS:
+ # Remove item and update the view.
+ self.removeItem(index)
+ self.showPopup()
+ # Set the view selection so that it doesn't bounce around.
+ new_index = min(self.count() - 1, index)
+ new_index = 0 if new_index < EXTERNAL_PATHS else new_index
+ self.view().setCurrentIndex(self.model().index(new_index, 0))
+ self.setCurrentIndex(new_index)
+ return True
+ return QComboBox.eventFilter(self, widget, event)
+
+ def __redirect_stdio_emit(self, value):
+ """
+ Searches through the parent tree to see if it is possible to emit the
+ redirect_stdio signal.
+ This logic allows to test the SearchInComboBox select_directory method
+ outside of the FindInFiles plugin.
+ """
+ parent = self.parent()
+ while parent is not None:
+ try:
+ parent.redirect_stdio.emit(value)
+ except AttributeError:
+ parent = parent.parent()
+ else:
+ break
+
+
+class FindOptions(QWidget):
+ """Find widget with options"""
+ REGEX_INVALID = "background-color:rgb(255, 80, 80);"
+ REGEX_ERROR = _("Regular expression error")
+
+ find = Signal()
+ stop = Signal()
+ redirect_stdio = Signal(bool)
+
+ def __init__(self, parent, search_text, search_text_regexp,
+ exclude, exclude_idx, exclude_regexp,
+ supported_encodings, more_options,
+ case_sensitive, external_path_history, options_button=None):
+ QWidget.__init__(self, parent)
+
+ if not isinstance(search_text, (list, tuple)):
+ search_text = [search_text]
+ if not isinstance(exclude, (list, tuple)):
+ exclude = [exclude]
+ if not isinstance(external_path_history, (list, tuple)):
+ external_path_history = [external_path_history]
+
+ self.supported_encodings = supported_encodings
+
+ # Layout 1
+ hlayout1 = QHBoxLayout()
+ self.search_text = PatternComboBox(self, search_text,
+ _("Search pattern"))
+ self.edit_regexp = create_toolbutton(self,
+ icon=ima.icon('regex'),
+ tip=_('Regular expression'))
+ self.case_button = create_toolbutton(self,
+ icon=ima.icon(
+ "format_letter_case"),
+ tip=_("Case Sensitive"))
+ self.case_button.setCheckable(True)
+ self.case_button.setChecked(case_sensitive)
+ self.edit_regexp.setCheckable(True)
+ self.edit_regexp.setChecked(search_text_regexp)
+ self.more_widgets = ()
+ self.more_options = create_toolbutton(self,
+ toggled=self.toggle_more_options)
+ self.more_options.setCheckable(True)
+ self.more_options.setChecked(more_options)
+
+ self.ok_button = create_toolbutton(self, text=_("Search"),
+ icon=ima.icon('find'),
+ triggered=lambda: self.find.emit(),
+ tip=_("Start search"),
+ text_beside_icon=True)
+ self.ok_button.clicked.connect(self.update_combos)
+ self.stop_button = create_toolbutton(self, text=_("Stop"),
+ icon=ima.icon('stop'),
+ triggered=lambda:
+ self.stop.emit(),
+ tip=_("Stop search"),
+ text_beside_icon=True)
+ self.stop_button.setEnabled(False)
+ for widget in [self.search_text, self.edit_regexp, self.case_button,
+ self.ok_button, self.stop_button, self.more_options]:
+ hlayout1.addWidget(widget)
+ if options_button:
+ hlayout1.addWidget(options_button)
+
+ # Layout 2
+ hlayout2 = QHBoxLayout()
+ self.exclude_pattern = PatternComboBox(self, exclude,
+ _("Exclude pattern"))
+ if exclude_idx is not None and exclude_idx >= 0 \
+ and exclude_idx < self.exclude_pattern.count():
+ self.exclude_pattern.setCurrentIndex(exclude_idx)
+ self.exclude_regexp = create_toolbutton(self,
+ icon=ima.icon('regex'),
+ tip=_('Regular expression'))
+ self.exclude_regexp.setCheckable(True)
+ self.exclude_regexp.setChecked(exclude_regexp)
+ exclude_label = QLabel(_("Exclude:"))
+ exclude_label.setBuddy(self.exclude_pattern)
+ for widget in [exclude_label, self.exclude_pattern,
+ self.exclude_regexp]:
+ hlayout2.addWidget(widget)
+
+ # Layout 3
+ hlayout3 = QHBoxLayout()
+
+ search_on_label = QLabel(_("Search in:"))
+ self.path_selection_combo = SearchInComboBox(
+ external_path_history, parent)
+
+ hlayout3.addWidget(search_on_label)
+ hlayout3.addWidget(self.path_selection_combo)
+
+ self.search_text.valid.connect(lambda valid: self.find.emit())
+ self.exclude_pattern.valid.connect(lambda valid: self.find.emit())
+
+ vlayout = QVBoxLayout()
+ vlayout.setContentsMargins(0, 0, 0, 0)
+ vlayout.addLayout(hlayout1)
+ vlayout.addLayout(hlayout2)
+ vlayout.addLayout(hlayout3)
+ self.more_widgets = (hlayout2,)
+ self.toggle_more_options(more_options)
+ self.setLayout(vlayout)
+
+ self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
+
+ @Slot(bool)
+ def toggle_more_options(self, state):
+ for layout in self.more_widgets:
+ for index in range(layout.count()):
+ if state and self.isVisible() or not state:
+ layout.itemAt(index).widget().setVisible(state)
+ if state:
+ icon = ima.icon('options_less')
+ tip = _('Hide advanced options')
+ else:
+ icon = ima.icon('options_more')
+ tip = _('Show advanced options')
+ self.more_options.setIcon(icon)
+ self.more_options.setToolTip(tip)
+
+ def update_combos(self):
+ self.search_text.lineEdit().returnPressed.emit()
+ self.exclude_pattern.lineEdit().returnPressed.emit()
+
+ def set_search_text(self, text):
+ if text:
+ self.search_text.add_text(text)
+ self.search_text.lineEdit().selectAll()
+ self.search_text.setFocus()
+
+ def get_options(self, to_save=False):
+ """Get options"""
+ text_re = self.edit_regexp.isChecked()
+ exclude_re = self.exclude_regexp.isChecked()
+ case_sensitive = self.case_button.isChecked()
+
+ # Return current options for them to be saved when closing
+ # Spyder.
+ if to_save:
+ search_text = [to_text_string(self.search_text.itemText(index))
+ for index in range(self.search_text.count())]
+ exclude = [to_text_string(self.exclude_pattern.itemText(index))
+ for index in range(self.exclude_pattern.count())]
+ exclude_idx = self.exclude_pattern.currentIndex()
+ path_history = self.path_selection_combo.get_external_paths()
+ more_options = self.more_options.isChecked()
+ return (search_text, text_re,
+ exclude, exclude_idx,
+ exclude_re, more_options,
+ case_sensitive, path_history)
+
+ # Clear fields
+ self.search_text.lineEdit().setStyleSheet("")
+ self.exclude_pattern.lineEdit().setStyleSheet("")
+ self.search_text.setToolTip("")
+ self.exclude_pattern.setToolTip("")
+
+ utext = to_text_string(self.search_text.currentText())
+ if not utext:
+ return
+
+ try:
+ texts = [(utext.encode('utf-8'), 'utf-8')]
+ except UnicodeEncodeError:
+ texts = []
+ for enc in self.supported_encodings:
+ try:
+ texts.append((utext.encode(enc), enc))
+ except UnicodeDecodeError:
+ pass
+
+ exclude = to_text_string(self.exclude_pattern.currentText())
+
+ if not case_sensitive:
+ texts = [(text[0].lower(), text[1]) for text in texts]
+
+ file_search = self.path_selection_combo.is_file_search()
+ path = self.path_selection_combo.get_current_searchpath()
+
+ if not exclude_re:
+ items = [fnmatch.translate(item.strip())
+ for item in exclude.split(",")
+ if item.strip() != '']
+ exclude = '|'.join(items)
+
+ # Validate exclude regular expression
+ if exclude:
+ error_msg = regexp_error_msg(exclude)
+ if error_msg:
+ exclude_edit = self.exclude_pattern.lineEdit()
+ exclude_edit.setStyleSheet(self.REGEX_INVALID)
+ tooltip = self.REGEX_ERROR + u': ' + to_text_string(error_msg)
+ self.exclude_pattern.setToolTip(tooltip)
+ return None
+ else:
+ exclude = re.compile(exclude)
+
+ # Validate text regular expression
+ if text_re:
+ error_msg = regexp_error_msg(texts[0][0])
+ if error_msg:
+ self.search_text.lineEdit().setStyleSheet(self.REGEX_INVALID)
+ tooltip = self.REGEX_ERROR + u': ' + to_text_string(error_msg)
+ self.search_text.setToolTip(tooltip)
+ return None
+ else:
+ texts = [(re.compile(x[0]), x[1]) for x in texts]
+
+ return (path, file_search, exclude, texts, text_re, case_sensitive)
+
+ @property
+ def path(self):
+ return self.path_selection_combo.path
+
+ def set_directory(self, directory):
+ self.path_selection_combo.path = osp.abspath(directory)
+
+ @property
+ def project_path(self):
+ return self.path_selection_combo.project_path
+
+ def set_project_path(self, path):
+ self.path_selection_combo.set_project_path(path)
+
+ def disable_project_search(self):
+ self.path_selection_combo.set_project_path(None)
+
+ @property
+ def file_path(self):
+ return self.path_selection_combo.file_path
+
+ def set_file_path(self, path):
+ self.path_selection_combo.file_path = path
+
+ def keyPressEvent(self, event):
+ """Reimplemented to handle key events"""
+ ctrl = event.modifiers() & Qt.ControlModifier
+ shift = event.modifiers() & Qt.ShiftModifier
+ if event.key() in (Qt.Key_Enter, Qt.Key_Return):
+ self.find.emit()
+ elif event.key() == Qt.Key_F and ctrl and shift:
+ # Toggle find widgets
+ self.parent().toggle_visibility.emit(not self.isVisible())
+ else:
+ QWidget.keyPressEvent(self, event)
+
+
+class LineMatchItem(QTreeWidgetItem):
+ def __init__(self, parent, lineno, colno, match, text_color=None):
+ self.lineno = lineno
+ self.colno = colno
+ self.match = match
+ self.text_color = text_color
+ QTreeWidgetItem.__init__(self, parent, [self.__repr__()],
+ QTreeWidgetItem.Type)
+
+ def __repr__(self):
+ match = to_text_string(self.match).rstrip()
+ font = get_font()
+ _str = to_text_string("{1} ({2}): "
+ "{3}
")
+ return _str.format(font.family(), self.lineno, self.colno, match,
+ self.text_color)
+
+ def __unicode__(self):
+ return self.__repr__()
+
+ def __str__(self):
+ return self.__repr__()
+
+ def __lt__(self, x):
+ return self.lineno < x.lineno
+
+ def __ge__(self, x):
+ return self.lineno >= x.lineno
+
+
+class FileMatchItem(QTreeWidgetItem):
+ def __init__(self, parent, filename, sorting, text_color=None):
+
+ self.sorting = sorting
+ self.filename = osp.basename(filename)
+
+ title_format = to_text_string('{0}
'
+ '{1}'
+ '')
+ title = (title_format.format(osp.basename(filename),
+ osp.dirname(filename),
+ text_color))
+ QTreeWidgetItem.__init__(self, parent, [title], QTreeWidgetItem.Type)
+
+ self.setToolTip(0, filename)
+
+ def __lt__(self, x):
+ if self.sorting['status'] == ON:
+ return self.filename < x.filename
+ else:
+ return False
+
+ def __ge__(self, x):
+ if self.sorting['status'] == ON:
+ return self.filename >= x.filename
+ else:
+ return False
+
+
+class ItemDelegate(QStyledItemDelegate):
+ def __init__(self, parent):
+ QStyledItemDelegate.__init__(self, parent)
+
+ def paint(self, painter, option, index):
+ options = QStyleOptionViewItem(option)
+ self.initStyleOption(options, index)
+
+ style = (QApplication.style() if options.widget is None
+ else options.widget.style())
+
+ doc = QTextDocument()
+ doc.setDocumentMargin(0)
+ doc.setHtml(options.text)
+
+ options.text = ""
+ style.drawControl(QStyle.CE_ItemViewItem, options, painter)
+
+ ctx = QAbstractTextDocumentLayout.PaintContext()
+
+ textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options)
+ painter.save()
+
+ painter.translate(textRect.topLeft())
+ painter.setClipRect(textRect.translated(-textRect.topLeft()))
+ doc.documentLayout().draw(painter, ctx)
+ painter.restore()
+
+ def sizeHint(self, option, index):
+ options = QStyleOptionViewItem(option)
+ self.initStyleOption(options, index)
+
+ doc = QTextDocument()
+ doc.setHtml(options.text)
+ doc.setTextWidth(options.rect.width())
+
+ return QSize(doc.idealWidth(), doc.size().height())
+
+
+class ResultsBrowser(OneColumnTree):
+ sig_edit_goto = Signal(str, int, str)
+
+ def __init__(self, parent, text_color=None):
+ OneColumnTree.__init__(self, parent)
+ self.search_text = None
+ self.results = None
+ self.total_matches = None
+ self.error_flag = None
+ self.completed = None
+ self.sorting = {}
+ self.data = None
+ self.files = None
+ self.set_title('')
+ self.set_sorting(OFF)
+ self.setSortingEnabled(False)
+ self.root_items = None
+ self.text_color = text_color
+ self.sortByColumn(0, Qt.AscendingOrder)
+ self.setItemDelegate(ItemDelegate(self))
+ self.setUniformRowHeights(False)
+ self.header().sectionClicked.connect(self.sort_section)
+
+ def activated(self, item):
+ """Double-click event"""
+ itemdata = self.data.get(id(self.currentItem()))
+ if itemdata is not None:
+ filename, lineno, colno = itemdata
+ self.sig_edit_goto.emit(filename, lineno, self.search_text)
+
+ def set_sorting(self, flag):
+ """Enable result sorting after search is complete."""
+ self.sorting['status'] = flag
+ self.header().setSectionsClickable(flag == ON)
+
+ @Slot(int)
+ def sort_section(self, idx):
+ self.setSortingEnabled(True)
+
+ def clicked(self, item):
+ """Click event"""
+ self.activated(item)
+
+ def clear_title(self, search_text):
+ self.clear()
+ self.setSortingEnabled(False)
+ self.num_files = 0
+ self.data = {}
+ self.files = {}
+ self.set_sorting(OFF)
+ self.search_text = search_text
+ title = "'%s' - " % search_text
+ text = _('String not found')
+ self.set_title(title + text)
+
+ def truncate_result(self, line, start, end):
+ ellipsis = u'...'
+ max_line_length = 80
+ max_num_char_fragment = 40
+
+ html_escape_table = {
+ u"&": u"&",
+ u'"': u""",
+ u"'": u"'",
+ u">": u">",
+ u"<": u"<",
+ }
+
+ def html_escape(text):
+ """Produce entities within text."""
+ return u"".join(html_escape_table.get(c, c) for c in text)
+
+ if PY2:
+ line = to_text_string(line, encoding='utf8')
+ else:
+ line = to_text_string(line)
+ left, match, right = line[:start], line[start:end], line[end:]
+
+ if len(line) > max_line_length:
+ offset = (len(line) - len(match)) // 2
+
+ left = left.split(u' ')
+ num_left_words = len(left)
+
+ if num_left_words == 1:
+ left = left[0]
+ if len(left) > max_num_char_fragment:
+ left = ellipsis + left[-offset:]
+ left = [left]
+
+ right = right.split(u' ')
+ num_right_words = len(right)
+
+ if num_right_words == 1:
+ right = right[0]
+ if len(right) > max_num_char_fragment:
+ right = right[:offset] + ellipsis
+ right = [right]
+
+ left = left[-4:]
+ right = right[:4]
+
+ if len(left) < num_left_words:
+ left = [ellipsis] + left
+
+ if len(right) < num_right_words:
+ right = right + [ellipsis]
+
+ left = u' '.join(left)
+ right = u' '.join(right)
+
+ if len(left) > max_num_char_fragment:
+ left = ellipsis + left[-30:]
+
+ if len(right) > max_num_char_fragment:
+ right = right[:30] + ellipsis
+
+ line_match_format = (u'{{0}}'
+ '{{1}}{{2}}')
+ line_match_format = line_match_format.format(self.text_color)
+
+ left = html_escape(left)
+ right = html_escape(right)
+ match = html_escape(match)
+ trunc_line = line_match_format.format(left, match, right)
+ return trunc_line
+
+ @Slot(tuple, int)
+ def append_result(self, results, num_matches):
+ """Real-time update of search results"""
+ filename, lineno, colno, match_end, line = results
+
+ if filename not in self.files:
+ file_item = FileMatchItem(self, filename, self.sorting,
+ self.text_color)
+ file_item.setExpanded(True)
+ self.files[filename] = file_item
+ self.num_files += 1
+
+ search_text = self.search_text
+ title = "'%s' - " % search_text
+ nb_files = self.num_files
+ if nb_files == 0:
+ text = _('String not found')
+ else:
+ text_matches = _('matches in')
+ text_files = _('file')
+ if nb_files > 1:
+ text_files += 's'
+ text = "%d %s %d %s" % (num_matches, text_matches,
+ nb_files, text_files)
+ self.set_title(title + text)
+
+ file_item = self.files[filename]
+ line = self.truncate_result(line, colno, match_end)
+ item = LineMatchItem(file_item, lineno, colno, line, self.text_color)
+ self.data[id(item)] = (filename, lineno, colno)
+
+
+class FileProgressBar(QWidget):
+ """Simple progress spinner with a label"""
+
+ def __init__(self, parent):
+ QWidget.__init__(self, parent)
+
+ self.status_text = QLabel(self)
+ self.spinner = QWaitingSpinner(self, centerOnParent=False)
+ self.spinner.setNumberOfLines(12)
+ self.spinner.setInnerRadius(2)
+ layout = QHBoxLayout()
+ layout.addWidget(self.spinner)
+ layout.addWidget(self.status_text)
+ self.setLayout(layout)
+
+ @Slot(str)
+ def set_label_path(self, path, folder=False):
+ text = truncate_path(path)
+ if not folder:
+ status_str = _(u' Scanning: {0}').format(text)
+ else:
+ status_str = _(u' Searching for files in folder: {0}').format(text)
+ self.status_text.setText(status_str)
+
+ def reset(self):
+ self.status_text.setText(_(" Searching for files..."))
+
+ def showEvent(self, event):
+ """Override show event to start waiting spinner."""
+ QWidget.showEvent(self, event)
+ self.spinner.start()
+
+ def hideEvent(self, event):
+ """Override hide event to stop waiting spinner."""
+ QWidget.hideEvent(self, event)
+ self.spinner.stop()
+
+
+class FindInFilesWidget(QWidget):
+ """
+ Find in files widget
+ """
+ sig_finished = Signal()
+
+ def __init__(self, parent,
+ search_text="",
+ search_text_regexp=False,
+ exclude=EXCLUDE_PATTERNS[0],
+ exclude_idx=None,
+ exclude_regexp=False,
+ supported_encodings=("utf-8", "iso-8859-1", "cp1252"),
+ more_options=True,
+ case_sensitive=False,
+ external_path_history=[],
+ options_button=None,
+ text_color=None):
+ QWidget.__init__(self, parent)
+
+ self.setWindowTitle(_('Find in files'))
+
+ self.search_thread = None
+ self.status_bar = FileProgressBar(self)
+ self.status_bar.hide()
+
+ self.find_options = FindOptions(self, search_text,
+ search_text_regexp,
+ exclude, exclude_idx,
+ exclude_regexp,
+ supported_encodings,
+ more_options,
+ case_sensitive,
+ external_path_history,
+ options_button=options_button)
+ self.find_options.find.connect(self.find)
+ self.find_options.stop.connect(self.stop_and_reset_thread)
+
+ self.result_browser = ResultsBrowser(self, text_color=text_color)
+
+ hlayout = QHBoxLayout()
+ hlayout.addWidget(self.result_browser)
+
+ layout = QVBoxLayout()
+ left, _x, right, bottom = layout.getContentsMargins()
+ layout.setContentsMargins(left, 0, right, bottom)
+ layout.addWidget(self.find_options)
+ layout.addLayout(hlayout)
+ layout.addWidget(self.status_bar)
+ self.setLayout(layout)
+
+ def set_search_text(self, text):
+ """Set search pattern"""
+ self.find_options.set_search_text(text)
+
+ def find(self):
+ """Call the find function"""
+ options = self.find_options.get_options()
+ if options is None:
+ return
+ self.stop_and_reset_thread(ignore_results=True)
+ self.search_thread = SearchThread(self)
+ self.search_thread.sig_finished.connect(self.search_complete)
+ self.search_thread.sig_current_file.connect(
+ lambda x: self.status_bar.set_label_path(x, folder=False)
+ )
+ self.search_thread.sig_current_folder.connect(
+ lambda x: self.status_bar.set_label_path(x, folder=True)
+ )
+ self.search_thread.sig_file_match.connect(
+ self.result_browser.append_result
+ )
+ self.search_thread.sig_out_print.connect(
+ lambda x: sys.stdout.write(str(x) + "\n")
+ )
+ self.status_bar.reset()
+ self.result_browser.clear_title(
+ self.find_options.search_text.currentText())
+ self.search_thread.initialize(*options)
+ self.search_thread.start()
+ self.find_options.ok_button.setEnabled(False)
+ self.find_options.stop_button.setEnabled(True)
+ self.status_bar.show()
+
+ def stop_and_reset_thread(self, ignore_results=False):
+ """Stop current search thread and clean-up"""
+ if self.search_thread is not None:
+ if self.search_thread.isRunning():
+ if ignore_results:
+ self.search_thread.sig_finished.disconnect(
+ self.search_complete)
+ self.search_thread.stop()
+ self.search_thread.wait()
+ self.search_thread.setParent(None)
+ self.search_thread = None
+
+ def closing_widget(self):
+ """Perform actions before widget is closed"""
+ self.stop_and_reset_thread(ignore_results=True)
+
+ def search_complete(self, completed):
+ """Current search thread has finished"""
+ self.result_browser.set_sorting(ON)
+ self.find_options.ok_button.setEnabled(True)
+ self.find_options.stop_button.setEnabled(False)
+ self.status_bar.hide()
+ self.result_browser.expandAll()
+ if self.search_thread is None:
+ return
+ self.sig_finished.emit()
+ found = self.search_thread.get_results()
+ self.stop_and_reset_thread()
+ if found is not None:
+ results, pathlist, nb, error_flag = found
+ self.result_browser.show()
+
+
+def test():
+ """Run Find in Files widget test"""
+ from spyder.utils.qthelpers import qapplication
+ from os.path import dirname
+ app = qapplication()
+ widget = FindInFilesWidget(None)
+ widget.resize(640, 480)
+ widget.show()
+ external_paths = [
+ dirname(__file__),
+ dirname(dirname(__file__)),
+ dirname(dirname(dirname(__file__))),
+ dirname(dirname(dirname(dirname(__file__))))
+ ]
+ for path in external_paths:
+ widget.find_options.path_selection_combo.add_external_path(path)
+ sys.exit(app.exec_())
+
+
+if __name__ == '__main__':
+ test()
diff --git a/spyder/plugins/help.py b/spyder/plugins/help.py
deleted file mode 100644
index f9ff727db60..00000000000
--- a/spyder/plugins/help.py
+++ /dev/null
@@ -1,979 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright © Spyder Project Contributors
-# Licensed under the terms of the MIT License
-# (see spyder/__init__.py for details)
-
-"""Help Plugin"""
-
-# Standard library imports
-import re
-import os.path as osp
-import socket
-import sys
-
-# Third party imports
-from qtpy.QtCore import QThread, QUrl, Signal, Slot
-from qtpy.QtWidgets import (QActionGroup, QComboBox, QGroupBox, QHBoxLayout,
- QLabel, QLineEdit, QMenu, QMessageBox, QSizePolicy,
- QToolButton, QVBoxLayout, QWidget)
-from qtpy.QtWebEngineWidgets import QWebEnginePage, WEBENGINE
-
-# Local imports
-from spyder import dependencies
-from spyder.config.base import _, get_conf_path, get_module_source_path
-from spyder.config.fonts import DEFAULT_SMALL_DELTA
-from spyder.api.plugins import SpyderPluginWidget
-from spyder.api.preferences import PluginConfigPage
-from spyder.py3compat import get_meth_class_inst, to_text_string
-from spyder.utils import icon_manager as ima
-from spyder.utils import programs
-from spyder.utils.help.sphinxify import (CSS_PATH, generate_context,
- sphinxify, usage, warning)
-from spyder.utils.qthelpers import (add_actions, create_action,
- create_toolbutton, create_plugin_layout,
- MENU_SEPARATOR)
-from spyder.widgets.browser import FrameWebView
-from spyder.widgets.comboboxes import EditableComboBox
-from spyder.widgets.findreplace import FindReplace
-from spyder.widgets.sourcecode import codeeditor
-
-
-# Sphinx dependency
-dependencies.add("sphinx", _("Show help for objects in the Editor and "
- "Consoles in a dedicated pane"),
- required_version='>=0.6.6')
-
-
-
-class ObjectComboBox(EditableComboBox):
- """
- QComboBox handling object names
- """
- # Signals
- valid = Signal(bool, bool)
-
- def __init__(self, parent):
- EditableComboBox.__init__(self, parent)
- self.help = parent
- self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
- self.tips = {True: '', False: ''}
-
- def is_valid(self, qstr=None):
- """Return True if string is valid"""
- if not self.help.source_is_console():
- return True
- if qstr is None:
- qstr = self.currentText()
- if not re.search(r'^[a-zA-Z0-9_\.]*$', str(qstr), 0):
- return False
- objtxt = to_text_string(qstr)
- if self.help.get_option('automatic_import'):
- shell = self.help.internal_shell
- if shell is not None:
- return shell.is_defined(objtxt, force_import=True)
- shell = self.help.get_shell()
- if shell is not None:
- try:
- return shell.is_defined(objtxt)
- except socket.error:
- shell = self.help.get_shell()
- try:
- return shell.is_defined(objtxt)
- except socket.error:
- # Well... too bad!
- pass
-
- def validate_current_text(self):
- self.validate(self.currentText())
-
- def validate(self, qstr, editing=True):
- """Reimplemented to avoid formatting actions"""
- valid = self.is_valid(qstr)
- if self.hasFocus() and valid is not None:
- if editing:
- # Combo box text is being modified: invalidate the entry
- self.show_tip(self.tips[valid])
- self.valid.emit(False, False)
- else:
- # A new item has just been selected
- if valid:
- self.selected()
- else:
- self.valid.emit(False, False)
-
-
-class HelpConfigPage(PluginConfigPage):
- def setup_page(self):
- # Connections group
- connections_group = QGroupBox(_("Automatic connections"))
- connections_label = QLabel(_("This pane can automatically "
- "show an object's help information after "
- "a left parenthesis is written next to it. "
- "Below you can decide to which plugin "
- "you want to connect it to turn on this "
- "feature."))
- connections_label.setWordWrap(True)
- editor_box = self.create_checkbox(_("Editor"), 'connect/editor')
- rope_installed = programs.is_module_installed('rope')
- jedi_installed = programs.is_module_installed('jedi', '>=0.11.0')
- editor_box.setEnabled(rope_installed or jedi_installed)
- if not rope_installed and not jedi_installed:
- editor_tip = _("This feature requires the Rope or Jedi libraries.\n"
- "It seems you don't have either installed.")
- editor_box.setToolTip(editor_tip)
- ipython_box = self.create_checkbox(_("IPython Console"),
- 'connect/ipython_console')
-
- connections_layout = QVBoxLayout()
- connections_layout.addWidget(connections_label)
- connections_layout.addWidget(editor_box)
- connections_layout.addWidget(ipython_box)
- connections_group.setLayout(connections_layout)
-
- # Features group
- features_group = QGroupBox(_("Additional features"))
- math_box = self.create_checkbox(_("Render mathematical equations"),
- 'math')
- req_sphinx = programs.is_module_installed('sphinx', '>=1.1')
- math_box.setEnabled(req_sphinx)
- if not req_sphinx:
- sphinx_ver = programs.get_module_version('sphinx')
- sphinx_tip = _("This feature requires Sphinx 1.1 or superior.")
- sphinx_tip += "\n" + _("Sphinx %s is currently installed.") % sphinx_ver
- math_box.setToolTip(sphinx_tip)
-
- features_layout = QVBoxLayout()
- features_layout.addWidget(math_box)
- features_group.setLayout(features_layout)
-
- # Source code group
- sourcecode_group = QGroupBox(_("Source code"))
- wrap_mode_box = self.create_checkbox(_("Wrap lines"), 'wrap')
-
- sourcecode_layout = QVBoxLayout()
- sourcecode_layout.addWidget(wrap_mode_box)
- sourcecode_group.setLayout(sourcecode_layout)
-
- # Final layout
- vlayout = QVBoxLayout()
- vlayout.addWidget(connections_group)
- vlayout.addWidget(features_group)
- vlayout.addWidget(sourcecode_group)
- vlayout.addStretch(1)
- self.setLayout(vlayout)
-
-
-class RichText(QWidget):
- """
- WebView widget with find dialog
- """
- def __init__(self, parent):
- QWidget.__init__(self, parent)
-
- self.webview = FrameWebView(self)
- self.find_widget = FindReplace(self)
- self.find_widget.set_editor(self.webview.web_widget)
- self.find_widget.hide()
-
- layout = QVBoxLayout()
- layout.setContentsMargins(0, 0, 0, 0)
- layout.addWidget(self.webview)
- layout.addWidget(self.find_widget)
- self.setLayout(layout)
-
- def set_font(self, font, fixed_font=None):
- """Set font"""
- self.webview.set_font(font, fixed_font=fixed_font)
-
- def set_html(self, html_text, base_url):
- """Set html text"""
- self.webview.setHtml(html_text, base_url)
-
- def clear(self):
- self.set_html('', self.webview.url())
-
-
-class PlainText(QWidget):
- """
- Read-only editor widget with find dialog
- """
- # Signals
- focus_changed = Signal()
-
- def __init__(self, parent):
- QWidget.__init__(self, parent)
- self.editor = None
-
- # Read-only editor
- self.editor = codeeditor.CodeEditor(self)
- self.editor.setup_editor(linenumbers=False, language='py',
- scrollflagarea=False, edge_line=False)
- self.editor.focus_changed.connect(lambda: self.focus_changed.emit())
- self.editor.setReadOnly(True)
-
- # Find/replace widget
- self.find_widget = FindReplace(self)
- self.find_widget.set_editor(self.editor)
- self.find_widget.hide()
-
- layout = QVBoxLayout()
- layout.setContentsMargins(0, 0, 0, 0)
- layout.addWidget(self.editor)
- layout.addWidget(self.find_widget)
- self.setLayout(layout)
-
- def set_font(self, font, color_scheme=None):
- """Set font"""
- self.editor.set_font(font, color_scheme=color_scheme)
-
- def set_color_scheme(self, color_scheme):
- """Set color scheme"""
- self.editor.set_color_scheme(color_scheme)
-
- def set_text(self, text, is_code):
- self.editor.set_highlight_current_line(is_code)
- self.editor.set_occurrence_highlighting(is_code)
- if is_code:
- self.editor.set_language('py')
- else:
- self.editor.set_language(None)
- self.editor.set_text(text)
- self.editor.set_cursor_position('sof')
-
- def clear(self):
- self.editor.clear()
-
-
-class SphinxThread(QThread):
- """
- A worker thread for handling rich text rendering.
-
- Parameters
- ----------
- doc : str or dict
- A string containing a raw rst text or a dict containing
- the doc string components to be rendered.
- See spyder.utils.dochelpers.getdoc for description.
- context : dict
- A dict containing the substitution variables for the
- layout template
- html_text_no_doc : unicode
- Text to be rendered if doc string cannot be extracted.
- math_option : bool
- Use LaTeX math rendering.
-
- """
- # Signals
- error_msg = Signal(str)
- html_ready = Signal(str)
-
- def __init__(self, html_text_no_doc=''):
- super(SphinxThread, self).__init__()
- self.doc = None
- self.context = None
- self.html_text_no_doc = html_text_no_doc
- self.math_option = False
-
- def render(self, doc, context=None, math_option=False, img_path=''):
- """Start thread to render a given documentation"""
- # If the thread is already running wait for it to finish before
- # starting it again.
- if self.wait():
- self.doc = doc
- self.context = context
- self.math_option = math_option
- self.img_path = img_path
- # This causes run() to be executed in separate thread
- self.start()
-
- def run(self):
- html_text = self.html_text_no_doc
- doc = self.doc
- if doc is not None:
- if type(doc) is dict and 'docstring' in doc.keys():
- try:
- context = generate_context(name=doc['name'],
- argspec=doc['argspec'],
- note=doc['note'],
- math=self.math_option,
- img_path=self.img_path)
- html_text = sphinxify(doc['docstring'], context)
- if doc['docstring'] == '':
- if any([doc['name'], doc['argspec'], doc['note']]):
- msg = _("No further documentation available")
- html_text += ''
- else:
- msg = _("No documentation available")
- html_text += '%s' % msg
- except Exception as error:
- self.error_msg.emit(to_text_string(error))
- return
- elif self.context is not None:
- try:
- html_text = sphinxify(doc, self.context)
- except Exception as error:
- self.error_msg.emit(to_text_string(error))
- return
- self.html_ready.emit(html_text)
-
-
-class Help(SpyderPluginWidget):
- """
- Docstrings viewer widget
- """
- CONF_SECTION = 'help'
- CONFIGWIDGET_CLASS = HelpConfigPage
- LOG_PATH = get_conf_path(CONF_SECTION)
- FONT_SIZE_DELTA = DEFAULT_SMALL_DELTA
-
- # Signals
- focus_changed = Signal()
-
- def __init__(self, parent=None):
- SpyderPluginWidget.__init__(self, parent)
-
- self.internal_shell = None
- self.console = None
-
- # Initialize plugin
- self.initialize_plugin()
-
- self.no_doc_string = _("No documentation available")
-
- self._last_console_cb = None
- self._last_editor_cb = None
-
- self.plain_text = PlainText(self)
- self.rich_text = RichText(self)
-
- color_scheme = self.get_color_scheme()
- self.set_plain_text_font(self.get_plugin_font(), color_scheme)
- self.plain_text.editor.toggle_wrap_mode(self.get_option('wrap'))
-
- # Add entries to read-only editor context-menu
- self.wrap_action = create_action(self, _("Wrap lines"),
- toggled=self.toggle_wrap_mode)
- self.wrap_action.setChecked(self.get_option('wrap'))
- self.plain_text.editor.readonly_menu.addSeparator()
- add_actions(self.plain_text.editor.readonly_menu, (self.wrap_action,))
-
- self.set_rich_text_font(self.get_plugin_font('rich_text'))
-
- self.shell = None
-
- # locked = disable link with Console
- self.locked = False
- self._last_texts = [None, None]
- self._last_editor_doc = None
-
- # Object name
- layout_edit = QHBoxLayout()
- layout_edit.setContentsMargins(0, 0, 0, 0)
- txt = _("Source")
- if sys.platform == 'darwin':
- source_label = QLabel(" " + txt)
- else:
- source_label = QLabel(txt)
- layout_edit.addWidget(source_label)
- self.source_combo = QComboBox(self)
- self.source_combo.addItems([_("Console"), _("Editor")])
- self.source_combo.currentIndexChanged.connect(self.source_changed)
- if (not programs.is_module_installed('rope') and
- not programs.is_module_installed('jedi', '>=0.11.0')):
- self.source_combo.hide()
- source_label.hide()
- layout_edit.addWidget(self.source_combo)
- layout_edit.addSpacing(10)
- layout_edit.addWidget(QLabel(_("Object")))
- self.combo = ObjectComboBox(self)
- layout_edit.addWidget(self.combo)
- self.object_edit = QLineEdit(self)
- self.object_edit.setReadOnly(True)
- layout_edit.addWidget(self.object_edit)
- self.combo.setMaxCount(self.get_option('max_history_entries'))
- self.combo.addItems( self.load_history() )
- self.combo.setItemText(0, '')
- self.combo.valid.connect(lambda valid: self.force_refresh())
-
- # Plain text docstring option
- self.docstring = True
- self.rich_help = self.get_option('rich_mode', True)
- self.plain_text_action = create_action(self, _("Plain Text"),
- toggled=self.toggle_plain_text)
-
- # Source code option
- self.show_source_action = create_action(self, _("Show Source"),
- toggled=self.toggle_show_source)
-
- # Rich text option
- self.rich_text_action = create_action(self, _("Rich Text"),
- toggled=self.toggle_rich_text)
-
- # Add the help actions to an exclusive QActionGroup
- help_actions = QActionGroup(self)
- help_actions.setExclusive(True)
- help_actions.addAction(self.plain_text_action)
- help_actions.addAction(self.rich_text_action)
-
- # Automatic import option
- self.auto_import_action = create_action(self, _("Automatic import"),
- toggled=self.toggle_auto_import)
- auto_import_state = self.get_option('automatic_import')
- self.auto_import_action.setChecked(auto_import_state)
-
- # Lock checkbox
- self.locked_button = create_toolbutton(self,
- triggered=self.toggle_locked)
- layout_edit.addWidget(self.locked_button)
- self._update_lock_icon()
-
- # Option menu
- self.menu = QMenu(self)
- add_actions(self.menu, [self.rich_text_action, self.plain_text_action,
- self.show_source_action, MENU_SEPARATOR,
- self.auto_import_action, MENU_SEPARATOR,
- self.undock_action])
- self.options_button.setMenu(self.menu)
- layout_edit.addWidget(self.options_button)
-
- if self.rich_help:
- self.switch_to_rich_text()
- else:
- self.switch_to_plain_text()
- self.plain_text_action.setChecked(not self.rich_help)
- self.rich_text_action.setChecked(self.rich_help)
- self.source_changed()
-
- # Main layout
- layout = create_plugin_layout(layout_edit)
- # we have two main widgets, but only one of them is shown at a time
- layout.addWidget(self.plain_text)
- layout.addWidget(self.rich_text)
- self.setLayout(layout)
-
- # Add worker thread for handling rich text rendering
- self._sphinx_thread = SphinxThread(
- html_text_no_doc=warning(self.no_doc_string))
- self._sphinx_thread.html_ready.connect(
- self._on_sphinx_thread_html_ready)
- self._sphinx_thread.error_msg.connect(self._on_sphinx_thread_error_msg)
-
- # Handle internal and external links
- view = self.rich_text.webview
- if not WEBENGINE:
- view.page().setLinkDelegationPolicy(QWebEnginePage.DelegateAllLinks)
- view.linkClicked.connect(self.handle_link_clicks)
-
- self._starting_up = True
-
- #------ SpyderPluginWidget API ---------------------------------------------
- def on_first_registration(self):
- """Action to be performed on first plugin registration"""
- self.main.tabify_plugins(self.main.variableexplorer, self)
-
- def get_plugin_title(self):
- """Return widget title"""
- return _('Help')
-
- def get_plugin_icon(self):
- """Return widget icon"""
- return ima.icon('help')
-
- def get_focus_widget(self):
- """
- Return the widget to give focus to when
- this plugin's dockwidget is raised on top-level
- """
- self.combo.lineEdit().selectAll()
- return self.combo
-
- def get_plugin_actions(self):
- """Return a list of actions related to plugin"""
- return []
-
- def register_plugin(self):
- """Register plugin in Spyder's main window"""
- self.focus_changed.connect(self.main.plugin_focus_changed)
- self.main.add_dockwidget(self)
- self.main.console.set_help(self)
-
- self.internal_shell = self.main.console.shell
- self.console = self.main.console
-
- def closing_plugin(self, cancelable=False):
- """Perform actions before parent main window is closed"""
- return True
-
- def refresh_plugin(self):
- """Refresh widget"""
- if self._starting_up:
- self._starting_up = False
- self.switch_to_rich_text()
- self.show_intro_message()
-
- def update_font(self):
- """Update font from Preferences"""
- color_scheme = self.get_color_scheme()
- font = self.get_plugin_font()
- rich_font = self.get_plugin_font(rich_text=True)
-
- self.set_plain_text_font(font, color_scheme=color_scheme)
- self.set_rich_text_font(rich_font)
-
- def apply_plugin_settings(self, options):
- """Apply configuration file's plugin settings"""
- color_scheme_n = 'color_scheme_name'
- color_scheme_o = self.get_color_scheme()
- connect_n = 'connect_to_oi'
- wrap_n = 'wrap'
- wrap_o = self.get_option(wrap_n)
- self.wrap_action.setChecked(wrap_o)
- math_n = 'math'
- math_o = self.get_option(math_n)
-
- if color_scheme_n in options:
- self.set_plain_text_color_scheme(color_scheme_o)
- if wrap_n in options:
- self.toggle_wrap_mode(wrap_o)
- if math_n in options:
- self.toggle_math_mode(math_o)
-
- # To make auto-connection changes take place instantly
- self.main.editor.apply_plugin_settings(options=[connect_n])
- self.main.ipyconsole.apply_plugin_settings(options=[connect_n])
-
- #------ Public API (related to Help's source) -------------------------
- def source_is_console(self):
- """Return True if source is Console"""
- return self.source_combo.currentIndex() == 0
-
- def switch_to_editor_source(self):
- self.source_combo.setCurrentIndex(1)
-
- def switch_to_console_source(self):
- self.source_combo.setCurrentIndex(0)
-
- def source_changed(self, index=None):
- if self.source_is_console():
- # Console
- self.combo.show()
- self.object_edit.hide()
- self.show_source_action.setEnabled(True)
- self.auto_import_action.setEnabled(True)
- else:
- # Editor
- self.combo.hide()
- self.object_edit.show()
- self.show_source_action.setDisabled(True)
- self.auto_import_action.setDisabled(True)
- self.restore_text()
-
- def save_text(self, callback):
- if self.source_is_console():
- self._last_console_cb = callback
- else:
- self._last_editor_cb = callback
-
- def restore_text(self):
- if self.source_is_console():
- cb = self._last_console_cb
- else:
- cb = self._last_editor_cb
- if cb is None:
- if self.is_plain_text_mode():
- self.plain_text.clear()
- else:
- self.rich_text.clear()
- else:
- func = cb[0]
- args = cb[1:]
- func(*args)
- if get_meth_class_inst(func) is self.rich_text:
- self.switch_to_rich_text()
- else:
- self.switch_to_plain_text()
-
- #------ Public API (related to rich/plain text widgets) --------------------
- @property
- def find_widget(self):
- if self.plain_text.isVisible():
- return self.plain_text.find_widget
- else:
- return self.rich_text.find_widget
-
- def set_rich_text_font(self, font):
- """Set rich text mode font"""
- self.rich_text.set_font(font, fixed_font=self.get_plugin_font())
-
- def set_plain_text_font(self, font, color_scheme=None):
- """Set plain text mode font"""
- self.plain_text.set_font(font, color_scheme=color_scheme)
-
- def set_plain_text_color_scheme(self, color_scheme):
- """Set plain text mode color scheme"""
- self.plain_text.set_color_scheme(color_scheme)
-
- @Slot(bool)
- def toggle_wrap_mode(self, checked):
- """Toggle wrap mode"""
- self.plain_text.editor.toggle_wrap_mode(checked)
- self.set_option('wrap', checked)
-
- def toggle_math_mode(self, checked):
- """Toggle math mode"""
- self.set_option('math', checked)
-
- def is_plain_text_mode(self):
- """Return True if plain text mode is active"""
- return self.plain_text.isVisible()
-
- def is_rich_text_mode(self):
- """Return True if rich text mode is active"""
- return self.rich_text.isVisible()
-
- def switch_to_plain_text(self):
- """Switch to plain text mode"""
- self.rich_help = False
- self.plain_text.show()
- self.rich_text.hide()
- self.plain_text_action.setChecked(True)
-
- def switch_to_rich_text(self):
- """Switch to rich text mode"""
- self.rich_help = True
- self.plain_text.hide()
- self.rich_text.show()
- self.rich_text_action.setChecked(True)
- self.show_source_action.setChecked(False)
-
- def set_plain_text(self, text, is_code):
- """Set plain text docs"""
-
- # text is coming from utils.dochelpers.getdoc
- if type(text) is dict:
- name = text['name']
- if name:
- rst_title = ''.join(['='*len(name), '\n', name, '\n',
- '='*len(name), '\n\n'])
- else:
- rst_title = ''
-
- if text['argspec']:
- definition = ''.join(['Definition: ', name, text['argspec'],
- '\n'])
- else:
- definition = ''
-
- if text['note']:
- note = ''.join(['Type: ', text['note'], '\n\n----\n\n'])
- else:
- note = ''
-
- full_text = ''.join([rst_title, definition, note,
- text['docstring']])
- else:
- full_text = text
-
- self.plain_text.set_text(full_text, is_code)
- self.save_text([self.plain_text.set_text, full_text, is_code])
-
- def set_rich_text_html(self, html_text, base_url):
- """Set rich text"""
- self.rich_text.set_html(html_text, base_url)
- self.save_text([self.rich_text.set_html, html_text, base_url])
-
- def show_intro_message(self):
- intro_message = _("Here you can get help of any object by pressing "
- "%s in front of it, either on the Editor or the "
- "Console.%s"
- "Help can also be shown automatically after writing "
- "a left parenthesis next to an object. You can "
- "activate this behavior in %s.")
- prefs = _("Preferences > Help")
- if sys.platform == 'darwin':
- shortcut = "Cmd+I"
- else:
- shortcut = "Ctrl+I"
-
- if self.is_rich_text_mode():
- title = _("Usage")
- tutorial_message = _("New to Spyder? Read our")
- tutorial = _("tutorial")
- intro_message = intro_message % (""+shortcut+"", "
",
- ""+prefs+"")
- self.set_rich_text_html(usage(title, intro_message,
- tutorial_message, tutorial),
- QUrl.fromLocalFile(CSS_PATH))
- else:
- install_sphinx = "\n\n%s" % _("Please consider installing Sphinx "
- "to get documentation rendered in "
- "rich text.")
- intro_message = intro_message % (shortcut, "\n\n", prefs)
- intro_message += install_sphinx
- self.set_plain_text(intro_message, is_code=False)
-
- def show_rich_text(self, text, collapse=False, img_path=''):
- """Show text in rich mode"""
- self.visibility_changed(True)
- self.raise_()
- self.switch_to_rich_text()
- context = generate_context(collapse=collapse, img_path=img_path)
- self.render_sphinx_doc(text, context)
-
- def show_plain_text(self, text):
- """Show text in plain mode"""
- self.visibility_changed(True)
- self.raise_()
- self.switch_to_plain_text()
- self.set_plain_text(text, is_code=False)
-
- @Slot()
- def show_tutorial(self):
- """Show the Spyder tutorial in the Help plugin, opening it if needed"""
- if not self.dockwidget.isVisible():
- self.dockwidget.show()
- self.toggle_view_action.setChecked(True)
- tutorial_path = get_module_source_path('spyder.utils.help')
- tutorial = osp.join(tutorial_path, 'tutorial.rst')
- text = open(tutorial).read()
- self.show_rich_text(text, collapse=True)
-
- def handle_link_clicks(self, url):
- url = to_text_string(url.toString())
- if url == "spy://tutorial":
- self.show_tutorial()
- elif url.startswith('http'):
- programs.start_file(url)
- else:
- self.rich_text.webview.load(QUrl(url))
-
- #------ Public API ---------------------------------------------------------
- def force_refresh(self):
- if self.source_is_console():
- self.set_object_text(None, force_refresh=True)
- elif self._last_editor_doc is not None:
- self.set_editor_doc(self._last_editor_doc, force_refresh=True)
-
- def set_object_text(self, text, force_refresh=False, ignore_unknown=False):
- """Set object analyzed by Help"""
- if (self.locked and not force_refresh):
- return
- self.switch_to_console_source()
-
- add_to_combo = True
- if text is None:
- text = to_text_string(self.combo.currentText())
- add_to_combo = False
-
- found = self.show_help(text, ignore_unknown=ignore_unknown)
- if ignore_unknown and not found:
- return
-
- if add_to_combo:
- self.combo.add_text(text)
- if found:
- self.save_history()
-
- if self.dockwidget is not None:
- self.dockwidget.blockSignals(True)
- self.__eventually_raise_help(text, force=force_refresh)
- if self.dockwidget is not None:
- self.dockwidget.blockSignals(False)
-
- def set_editor_doc(self, doc, force_refresh=False):
- """
- Use the help plugin to show docstring dictionary computed
- with introspection plugin from the Editor plugin
- """
- if (self.locked and not force_refresh):
- return
- self.switch_to_editor_source()
- self._last_editor_doc = doc
- self.object_edit.setText(doc['obj_text'])
-
- if self.rich_help:
- self.render_sphinx_doc(doc)
- else:
- self.set_plain_text(doc, is_code=False)
-
- if self.dockwidget is not None:
- self.dockwidget.blockSignals(True)
- self.__eventually_raise_help(doc['docstring'], force=force_refresh)
- if self.dockwidget is not None:
- self.dockwidget.blockSignals(False)
-
- def __eventually_raise_help(self, text, force=False):
- index = self.source_combo.currentIndex()
- if hasattr(self.main, 'tabifiedDockWidgets'):
- # 'QMainWindow.tabifiedDockWidgets' was introduced in PyQt 4.5
- if (self.dockwidget and (force or self.dockwidget.isVisible()) and
- not self.ismaximized and
- (force or text != self._last_texts[index])):
- dockwidgets = self.main.tabifiedDockWidgets(self.dockwidget)
- if (self.console.dockwidget not in dockwidgets and
- self.main.ipyconsole is not None and
- self.main.ipyconsole.dockwidget not in dockwidgets):
- self.dockwidget.show()
- self.dockwidget.raise_()
- self._last_texts[index] = text
-
- def load_history(self, obj=None):
- """Load history from a text file in user home directory"""
- if osp.isfile(self.LOG_PATH):
- history = [line.replace('\n', '')
- for line in open(self.LOG_PATH, 'r').readlines()]
- else:
- history = []
- return history
-
- def save_history(self):
- """Save history to a text file in user home directory"""
- open(self.LOG_PATH, 'w').write("\n".join( \
- [to_text_string(self.combo.itemText(index))
- for index in range(self.combo.count())] ))
-
- @Slot(bool)
- def toggle_plain_text(self, checked):
- """Toggle plain text docstring"""
- if checked:
- self.docstring = checked
- self.switch_to_plain_text()
- self.force_refresh()
- self.set_option('rich_mode', not checked)
-
- @Slot(bool)
- def toggle_show_source(self, checked):
- """Toggle show source code"""
- if checked:
- self.switch_to_plain_text()
- self.docstring = not checked
- self.force_refresh()
- self.set_option('rich_mode', not checked)
-
- @Slot(bool)
- def toggle_rich_text(self, checked):
- """Toggle between sphinxified docstrings or plain ones"""
- if checked:
- self.docstring = not checked
- self.switch_to_rich_text()
- self.set_option('rich_mode', checked)
-
- @Slot(bool)
- def toggle_auto_import(self, checked):
- """Toggle automatic import feature"""
- self.combo.validate_current_text()
- self.set_option('automatic_import', checked)
- self.force_refresh()
-
- @Slot()
- def toggle_locked(self):
- """
- Toggle locked state
- locked = disable link with Console
- """
- self.locked = not self.locked
- self._update_lock_icon()
-
- def _update_lock_icon(self):
- """Update locked state icon"""
- icon = ima.icon('lock') if self.locked else ima.icon('lock_open')
- self.locked_button.setIcon(icon)
- tip = _("Unlock") if self.locked else _("Lock")
- self.locked_button.setToolTip(tip)
-
- def set_shell(self, shell):
- """Bind to shell"""
- self.shell = shell
-
- def get_shell(self):
- """
- Return shell which is currently bound to Help,
- or another running shell if it has been terminated
- """
- if (not hasattr(self.shell, 'get_doc') or
- (hasattr(self.shell, 'is_running') and
- not self.shell.is_running())):
- self.shell = None
- if self.main.ipyconsole is not None:
- shell = self.main.ipyconsole.get_current_shellwidget()
- if shell is not None and shell.kernel_client is not None:
- self.shell = shell
- if self.shell is None:
- self.shell = self.internal_shell
- return self.shell
-
- def render_sphinx_doc(self, doc, context=None):
- """Transform doc string dictionary to HTML and show it"""
- # Math rendering option could have changed
- if self.main.editor is not None:
- fname = self.main.editor.get_current_filename()
- dname = osp.dirname(fname)
- else:
- dname = ''
- self._sphinx_thread.render(doc, context, self.get_option('math'),
- dname)
-
- def _on_sphinx_thread_html_ready(self, html_text):
- """Set our sphinx documentation based on thread result"""
- self._sphinx_thread.wait()
- self.set_rich_text_html(html_text, QUrl.fromLocalFile(CSS_PATH))
-
- def _on_sphinx_thread_error_msg(self, error_msg):
- """ Display error message on Sphinx rich text failure"""
- self._sphinx_thread.wait()
- self.plain_text_action.setChecked(True)
- sphinx_ver = programs.get_module_version('sphinx')
- QMessageBox.critical(self,
- _('Help'),
- _("The following error occured when calling "
- "Sphinx %s.
Incompatible Sphinx "
- "version or doc string decoding failed."
- "
Error message:
%s"
- ) % (sphinx_ver, error_msg))
-
- def show_help(self, obj_text, ignore_unknown=False):
- """Show help"""
- shell = self.get_shell()
- if shell is None:
- return
- obj_text = to_text_string(obj_text)
-
- if not shell.is_defined(obj_text):
- if self.get_option('automatic_import') and \
- self.internal_shell.is_defined(obj_text, force_import=True):
- shell = self.internal_shell
- else:
- shell = None
- doc = None
- source_text = None
-
- if shell is not None:
- doc = shell.get_doc(obj_text)
- source_text = shell.get_source(obj_text)
-
- is_code = False
-
- if self.rich_help:
- self.render_sphinx_doc(doc)
- return doc is not None
- elif self.docstring:
- hlp_text = doc
- if hlp_text is None:
- hlp_text = source_text
- if hlp_text is None:
- hlp_text = self.no_doc_string
- if ignore_unknown:
- return False
- else:
- hlp_text = source_text
- if hlp_text is None:
- hlp_text = doc
- if hlp_text is None:
- hlp_text = _("No source code available.")
- if ignore_unknown:
- return False
- else:
- is_code = True
- self.set_plain_text(hlp_text, is_code=is_code)
- return True
diff --git a/spyder/plugins/help/__init__.py b/spyder/plugins/help/__init__.py
new file mode 100644
index 00000000000..9243d515bba
--- /dev/null
+++ b/spyder/plugins/help/__init__.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""
+spyder.plugins.help
+===========
+
+Help plugin using a WebView
+"""
diff --git a/spyder/plugins/help/confpage.py b/spyder/plugins/help/confpage.py
new file mode 100644
index 00000000000..4b94f1e92fa
--- /dev/null
+++ b/spyder/plugins/help/confpage.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Help Plugin Configuration Page."""
+
+# Standard library imports
+
+# Third party imports
+from qtpy.QtWidgets import QGroupBox, QVBoxLayout, QLabel
+
+# Local imports
+from spyder.config.base import _
+from spyder.api.preferences import PluginConfigPage
+from spyder.utils import programs
+
+
+class HelpConfigPage(PluginConfigPage):
+ def setup_page(self):
+ # Connections group
+ connections_group = QGroupBox(_("Automatic connections"))
+ connections_label = QLabel(_("This pane can automatically "
+ "show an object's help information after "
+ "a left parenthesis is written next to it. "
+ "Below you can decide to which plugin "
+ "you want to connect it to turn on this "
+ "feature."))
+ connections_label.setWordWrap(True)
+ editor_box = self.create_checkbox(_("Editor"), 'connect/editor')
+
+ ipython_box = self.create_checkbox(_("IPython Console"),
+ 'connect/ipython_console')
+
+ connections_layout = QVBoxLayout()
+ connections_layout.addWidget(connections_label)
+ connections_layout.addWidget(editor_box)
+ connections_layout.addWidget(ipython_box)
+ connections_group.setLayout(connections_layout)
+
+ # Features group
+ features_group = QGroupBox(_("Additional features"))
+ math_box = self.create_checkbox(_("Render mathematical equations"),
+ 'math')
+ req_sphinx = programs.is_module_installed('sphinx', '>=1.1')
+ math_box.setEnabled(req_sphinx)
+ if not req_sphinx:
+ sphinx_ver = programs.get_module_version('sphinx')
+ sphinx_tip = _("This feature requires Sphinx 1.1 or superior.")
+ sphinx_tip += "\n" + _("Sphinx %s is currently installed.") % sphinx_ver
+ math_box.setToolTip(sphinx_tip)
+
+ features_layout = QVBoxLayout()
+ features_layout.addWidget(math_box)
+ features_group.setLayout(features_layout)
+
+ # Source code group
+ sourcecode_group = QGroupBox(_("Source code"))
+ wrap_mode_box = self.create_checkbox(_("Wrap lines"), 'wrap')
+
+ sourcecode_layout = QVBoxLayout()
+ sourcecode_layout.addWidget(wrap_mode_box)
+ sourcecode_group.setLayout(sourcecode_layout)
+
+ # Final layout
+ vlayout = QVBoxLayout()
+ vlayout.addWidget(connections_group)
+ vlayout.addWidget(features_group)
+ vlayout.addWidget(sourcecode_group)
+ vlayout.addStretch(1)
+ self.setLayout(vlayout)
+
diff --git a/spyder/plugins/help/plugin.py b/spyder/plugins/help/plugin.py
new file mode 100644
index 00000000000..013ff96c847
--- /dev/null
+++ b/spyder/plugins/help/plugin.py
@@ -0,0 +1,709 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+
+"""Help Plugin"""
+
+# Standard library imports
+import os.path as osp
+import sys
+
+# Third party imports
+from qtpy.QtCore import QUrl, Signal, Slot
+from qtpy.QtWidgets import (QActionGroup, QComboBox, QHBoxLayout,
+ QLabel, QLineEdit, QMenu, QMessageBox,
+ QToolButton, QVBoxLayout)
+from qtpy.QtWebEngineWidgets import QWebEnginePage, WEBENGINE
+
+# Local imports
+from spyder import dependencies
+from spyder.config.base import _, get_conf_path, get_module_source_path
+from spyder.config.fonts import DEFAULT_SMALL_DELTA
+from spyder.api.plugins import SpyderPluginWidget
+from spyder.py3compat import get_meth_class_inst, to_text_string
+from spyder.utils import icon_manager as ima
+from spyder.utils import programs
+from spyder.plugins.help.utils.sphinxify import (CSS_PATH,
+ generate_context,
+ usage, warning)
+from spyder.utils.qthelpers import (add_actions, create_action,
+ create_toolbutton, create_plugin_layout,
+ MENU_SEPARATOR)
+from spyder.plugins.help.confpage import HelpConfigPage
+from spyder.plugins.help.utils.sphinxthread import SphinxThread
+from spyder.plugins.help.widgets import PlainText, RichText, ObjectComboBox
+
+# Sphinx dependency
+dependencies.add("sphinx", _("Show help for objects in the Editor and "
+ "Consoles in a dedicated pane"),
+ required_version='>=0.6.6')
+
+
+
+class Help(SpyderPluginWidget):
+ """
+ Docstrings viewer widget
+ """
+ CONF_SECTION = 'help'
+ CONFIGWIDGET_CLASS = HelpConfigPage
+ LOG_PATH = get_conf_path(CONF_SECTION)
+ FONT_SIZE_DELTA = DEFAULT_SMALL_DELTA
+
+ # Signals
+ focus_changed = Signal()
+
+ def __init__(self, parent=None, css_path=CSS_PATH):
+ SpyderPluginWidget.__init__(self, parent)
+
+ self.internal_shell = None
+ self.console = None
+ self.css_path = css_path
+
+ self.no_doc_string = _("No documentation available")
+
+ self._last_console_cb = None
+ self._last_editor_cb = None
+
+ self.plain_text = PlainText(self)
+ self.rich_text = RichText(self)
+
+ color_scheme = self.get_color_scheme()
+ self.set_plain_text_font(self.get_plugin_font(), color_scheme)
+ self.plain_text.editor.toggle_wrap_mode(self.get_option('wrap'))
+
+ # Add entries to read-only editor context-menu
+ self.wrap_action = create_action(self, _("Wrap lines"),
+ toggled=self.toggle_wrap_mode)
+ self.wrap_action.setChecked(self.get_option('wrap'))
+ self.plain_text.editor.readonly_menu.addSeparator()
+ add_actions(self.plain_text.editor.readonly_menu, (self.wrap_action,))
+
+ self.set_rich_text_font(self.get_plugin_font('rich_text'))
+
+ self.shell = None
+
+ # locked = disable link with Console
+ self.locked = False
+ self._last_texts = [None, None]
+ self._last_editor_doc = None
+
+ # Object name
+ layout_edit = QHBoxLayout()
+ layout_edit.setContentsMargins(0, 0, 0, 0)
+ txt = _("Source")
+ if sys.platform == 'darwin':
+ source_label = QLabel(" " + txt)
+ else:
+ source_label = QLabel(txt)
+ layout_edit.addWidget(source_label)
+ self.source_combo = QComboBox(self)
+ self.source_combo.addItems([_("Console"), _("Editor")])
+ self.source_combo.currentIndexChanged.connect(self.source_changed)
+ if (not programs.is_module_installed('rope') and
+ not programs.is_module_installed('jedi', '>=0.11.0')):
+ self.source_combo.hide()
+ source_label.hide()
+ layout_edit.addWidget(self.source_combo)
+ layout_edit.addSpacing(10)
+ layout_edit.addWidget(QLabel(_("Object")))
+ self.combo = ObjectComboBox(self)
+ layout_edit.addWidget(self.combo)
+ self.object_edit = QLineEdit(self)
+ self.object_edit.setReadOnly(True)
+ layout_edit.addWidget(self.object_edit)
+ self.combo.setMaxCount(self.get_option('max_history_entries'))
+ self.combo.addItems( self.load_history() )
+ self.combo.setItemText(0, '')
+ self.combo.valid.connect(self.force_refresh)
+
+ # Plain text docstring option
+ self.docstring = True
+ self.rich_help = self.get_option('rich_mode', True)
+ self.plain_text_action = create_action(self, _("Plain Text"),
+ toggled=self.toggle_plain_text)
+
+ # Source code option
+ self.show_source_action = create_action(self, _("Show Source"),
+ toggled=self.toggle_show_source)
+
+ # Rich text option
+ self.rich_text_action = create_action(self, _("Rich Text"),
+ toggled=self.toggle_rich_text)
+
+ # Add the help actions to an exclusive QActionGroup
+ help_actions = QActionGroup(self)
+ help_actions.setExclusive(True)
+ help_actions.addAction(self.plain_text_action)
+ help_actions.addAction(self.rich_text_action)
+
+ # Automatic import option
+ self.auto_import_action = create_action(self, _("Automatic import"),
+ toggled=self.toggle_auto_import)
+ auto_import_state = self.get_option('automatic_import')
+ self.auto_import_action.setChecked(auto_import_state)
+
+ # Lock checkbox
+ self.locked_button = create_toolbutton(self,
+ triggered=self.toggle_locked)
+ layout_edit.addWidget(self.locked_button)
+ self._update_lock_icon()
+
+ # Option menu
+ layout_edit.addWidget(self.options_button)
+
+ if self.rich_help:
+ self.switch_to_rich_text()
+ else:
+ self.switch_to_plain_text()
+ self.plain_text_action.setChecked(not self.rich_help)
+ self.rich_text_action.setChecked(self.rich_help)
+ self.source_changed()
+
+ # Main layout
+ layout = create_plugin_layout(layout_edit)
+ # we have two main widgets, but only one of them is shown at a time
+ layout.addWidget(self.plain_text)
+ layout.addWidget(self.rich_text)
+ self.setLayout(layout)
+
+ # Add worker thread for handling rich text rendering
+ self._sphinx_thread = SphinxThread(
+ html_text_no_doc=warning(self.no_doc_string,
+ css_path=self.css_path),
+ css_path=self.css_path)
+ self._sphinx_thread.html_ready.connect(
+ self._on_sphinx_thread_html_ready)
+ self._sphinx_thread.error_msg.connect(self._on_sphinx_thread_error_msg)
+
+ # Handle internal and external links
+ view = self.rich_text.webview
+ if not WEBENGINE:
+ view.page().setLinkDelegationPolicy(QWebEnginePage.DelegateAllLinks)
+ view.linkClicked.connect(self.handle_link_clicks)
+
+ # Initialize plugin
+ self.initialize_plugin()
+
+ self._starting_up = True
+
+ #------ SpyderPluginWidget API ---------------------------------------------
+ def on_first_registration(self):
+ """Action to be performed on first plugin registration"""
+ self.main.tabify_plugins(self.main.variableexplorer, self)
+
+ def get_plugin_title(self):
+ """Return widget title"""
+ return _('Help')
+
+ def get_plugin_icon(self):
+ """Return widget icon"""
+ return ima.icon('help')
+
+ def get_focus_widget(self):
+ """
+ Return the widget to give focus to when
+ this plugin's dockwidget is raised on top-level
+ """
+ self.combo.lineEdit().selectAll()
+ return self.combo
+
+ def get_plugin_actions(self):
+ """Return a list of actions related to plugin"""
+ return [self.rich_text_action, self.plain_text_action,
+ self.show_source_action, MENU_SEPARATOR,
+ self.auto_import_action]
+
+ def register_plugin(self):
+ """Register plugin in Spyder's main window"""
+ self.focus_changed.connect(self.main.plugin_focus_changed)
+ self.main.add_dockwidget(self)
+ self.main.console.set_help(self)
+
+ self.internal_shell = self.main.console.shell
+ self.console = self.main.console
+
+ def closing_plugin(self, cancelable=False):
+ """Perform actions before parent main window is closed"""
+ return True
+
+ def refresh_plugin(self):
+ """Refresh widget"""
+ if self._starting_up:
+ self._starting_up = False
+ self.switch_to_rich_text()
+ self.show_intro_message()
+
+ def update_font(self):
+ """Update font from Preferences"""
+ color_scheme = self.get_color_scheme()
+ font = self.get_plugin_font()
+ rich_font = self.get_plugin_font(rich_text=True)
+
+ self.set_plain_text_font(font, color_scheme=color_scheme)
+ self.set_rich_text_font(rich_font)
+
+ def apply_plugin_settings(self, options):
+ """Apply configuration file's plugin settings"""
+ color_scheme_n = 'color_scheme_name'
+ color_scheme_o = self.get_color_scheme()
+ connect_n = 'connect_to_oi'
+ wrap_n = 'wrap'
+ wrap_o = self.get_option(wrap_n)
+ self.wrap_action.setChecked(wrap_o)
+ math_n = 'math'
+ math_o = self.get_option(math_n)
+
+ if color_scheme_n in options:
+ self.set_plain_text_color_scheme(color_scheme_o)
+ if wrap_n in options:
+ self.toggle_wrap_mode(wrap_o)
+ if math_n in options:
+ self.toggle_math_mode(math_o)
+
+ # To make auto-connection changes take place instantly
+ self.main.editor.apply_plugin_settings(options=[connect_n])
+ self.main.ipyconsole.apply_plugin_settings(options=[connect_n])
+
+ #------ Public API (related to Help's source) -------------------------
+ def source_is_console(self):
+ """Return True if source is Console"""
+ return self.source_combo.currentIndex() == 0
+
+ def switch_to_editor_source(self):
+ self.source_combo.setCurrentIndex(1)
+
+ def switch_to_console_source(self):
+ self.source_combo.setCurrentIndex(0)
+
+ def source_changed(self, index=None):
+ if self.source_is_console():
+ # Console
+ self.combo.show()
+ self.object_edit.hide()
+ self.show_source_action.setEnabled(True)
+ self.auto_import_action.setEnabled(True)
+ else:
+ # Editor
+ self.combo.hide()
+ self.object_edit.show()
+ self.show_source_action.setDisabled(True)
+ self.auto_import_action.setDisabled(True)
+ self.restore_text()
+
+ def save_text(self, callback):
+ if self.source_is_console():
+ self._last_console_cb = callback
+ else:
+ self._last_editor_cb = callback
+
+ def restore_text(self):
+ if self.source_is_console():
+ cb = self._last_console_cb
+ else:
+ cb = self._last_editor_cb
+ if cb is None:
+ if self.is_plain_text_mode():
+ self.plain_text.clear()
+ else:
+ self.rich_text.clear()
+ else:
+ func = cb[0]
+ args = cb[1:]
+ func(*args)
+ if get_meth_class_inst(func) is self.rich_text:
+ self.switch_to_rich_text()
+ else:
+ self.switch_to_plain_text()
+
+ #------ Public API (related to rich/plain text widgets) --------------------
+ @property
+ def find_widget(self):
+ if self.plain_text.isVisible():
+ return self.plain_text.find_widget
+ else:
+ return self.rich_text.find_widget
+
+ def set_rich_text_font(self, font):
+ """Set rich text mode font"""
+ self.rich_text.set_font(font, fixed_font=self.get_plugin_font())
+
+ def set_plain_text_font(self, font, color_scheme=None):
+ """Set plain text mode font"""
+ self.plain_text.set_font(font, color_scheme=color_scheme)
+
+ def set_plain_text_color_scheme(self, color_scheme):
+ """Set plain text mode color scheme"""
+ self.plain_text.set_color_scheme(color_scheme)
+
+ @Slot(bool)
+ def toggle_wrap_mode(self, checked):
+ """Toggle wrap mode"""
+ self.plain_text.editor.toggle_wrap_mode(checked)
+ self.set_option('wrap', checked)
+
+ def toggle_math_mode(self, checked):
+ """Toggle math mode"""
+ self.set_option('math', checked)
+
+ def is_plain_text_mode(self):
+ """Return True if plain text mode is active"""
+ return self.plain_text.isVisible()
+
+ def is_rich_text_mode(self):
+ """Return True if rich text mode is active"""
+ return self.rich_text.isVisible()
+
+ def switch_to_plain_text(self):
+ """Switch to plain text mode"""
+ self.rich_help = False
+ self.plain_text.show()
+ self.rich_text.hide()
+ self.plain_text_action.setChecked(True)
+
+ def switch_to_rich_text(self):
+ """Switch to rich text mode"""
+ self.rich_help = True
+ self.plain_text.hide()
+ self.rich_text.show()
+ self.rich_text_action.setChecked(True)
+ self.show_source_action.setChecked(False)
+
+ def set_plain_text(self, text, is_code):
+ """Set plain text docs"""
+
+ # text is coming from utils.dochelpers.getdoc
+ if type(text) is dict:
+ name = text['name']
+ if name:
+ rst_title = ''.join(['='*len(name), '\n', name, '\n',
+ '='*len(name), '\n\n'])
+ else:
+ rst_title = ''
+
+ if text['argspec']:
+ definition = ''.join(['Definition: ', name, text['argspec'],
+ '\n'])
+ else:
+ definition = ''
+
+ if text['note']:
+ note = ''.join(['Type: ', text['note'], '\n\n----\n\n'])
+ else:
+ note = ''
+
+ full_text = ''.join([rst_title, definition, note,
+ text['docstring']])
+ else:
+ full_text = text
+
+ self.plain_text.set_text(full_text, is_code)
+ self.save_text([self.plain_text.set_text, full_text, is_code])
+
+ def set_rich_text_html(self, html_text, base_url):
+ """Set rich text"""
+ self.rich_text.set_html(html_text, base_url)
+ self.save_text([self.rich_text.set_html, html_text, base_url])
+
+ def show_intro_message(self):
+ intro_message = _("Here you can get help of any object by pressing "
+ "%s in front of it, either on the Editor or the "
+ "Console.%s"
+ "Help can also be shown automatically after writing "
+ "a left parenthesis next to an object. You can "
+ "activate this behavior in %s.")
+ prefs = _("Preferences > Help")
+ if sys.platform == 'darwin':
+ shortcut = "Cmd+I"
+ else:
+ shortcut = "Ctrl+I"
+
+ if self.is_rich_text_mode():
+ title = _("Usage")
+ tutorial_message = _("New to Spyder? Read our")
+ tutorial = _("tutorial")
+ intro_message = intro_message % (""+shortcut+"", "
",
+ ""+prefs+"")
+ self.set_rich_text_html(usage(title, intro_message,
+ tutorial_message, tutorial,
+ css_path=self.css_path),
+ QUrl.fromLocalFile(self.css_path))
+ else:
+ install_sphinx = "\n\n%s" % _("Please consider installing Sphinx "
+ "to get documentation rendered in "
+ "rich text.")
+ intro_message = intro_message % (shortcut, "\n\n", prefs)
+ intro_message += install_sphinx
+ self.set_plain_text(intro_message, is_code=False)
+
+ def show_rich_text(self, text, collapse=False, img_path=''):
+ """Show text in rich mode"""
+ self.switch_to_plugin()
+ self.switch_to_rich_text()
+ context = generate_context(collapse=collapse, img_path=img_path,
+ css_path=self.css_path)
+ self.render_sphinx_doc(text, context)
+
+ def show_plain_text(self, text):
+ """Show text in plain mode"""
+ self.switch_to_plugin()
+ self.switch_to_plain_text()
+ self.set_plain_text(text, is_code=False)
+
+ @Slot()
+ def show_tutorial(self):
+ """Show the Spyder tutorial in the Help plugin, opening it if needed"""
+ self.switch_to_plugin()
+ tutorial_path = get_module_source_path('spyder.plugins.help.utils')
+ tutorial = osp.join(tutorial_path, 'tutorial.rst')
+ text = open(tutorial).read()
+ self.show_rich_text(text, collapse=True)
+
+ def handle_link_clicks(self, url):
+ url = to_text_string(url.toString())
+ if url == "spy://tutorial":
+ self.show_tutorial()
+ elif url.startswith('http'):
+ programs.start_file(url)
+ else:
+ self.rich_text.webview.load(QUrl(url))
+
+ # ------ Public API -------------------------------------------------------
+ @Slot()
+ @Slot(bool)
+ @Slot(bool, bool)
+ def force_refresh(self, valid=True, editing=True):
+ if valid:
+ if self.source_is_console():
+ self.set_object_text(None, force_refresh=True)
+ elif self._last_editor_doc is not None:
+ self.set_editor_doc(self._last_editor_doc, force_refresh=True)
+
+ def set_object_text(self, text, force_refresh=False, ignore_unknown=False):
+ """Set object analyzed by Help"""
+ if (self.locked and not force_refresh):
+ return
+ self.switch_to_console_source()
+
+ add_to_combo = True
+ if text is None:
+ text = to_text_string(self.combo.currentText())
+ add_to_combo = False
+
+ found = self.show_help(text, ignore_unknown=ignore_unknown)
+ if ignore_unknown and not found:
+ return
+
+ if add_to_combo:
+ self.combo.add_text(text)
+ if found:
+ self.save_history()
+
+ if self.dockwidget is not None:
+ self.dockwidget.blockSignals(True)
+ self.__eventually_raise_help(text, force=force_refresh)
+ if self.dockwidget is not None:
+ self.dockwidget.blockSignals(False)
+
+ def set_editor_doc(self, doc, force_refresh=False):
+ """
+ Use the help plugin to show docstring dictionary computed
+ with introspection plugin from the Editor plugin
+ """
+ if (self.locked and not force_refresh):
+ return
+ self.switch_to_editor_source()
+ self._last_editor_doc = doc
+ self.object_edit.setText(doc['obj_text'])
+
+ if self.rich_help:
+ self.render_sphinx_doc(doc)
+ else:
+ self.set_plain_text(doc, is_code=False)
+
+ if self.dockwidget is not None:
+ self.dockwidget.blockSignals(True)
+ self.__eventually_raise_help(doc['docstring'], force=force_refresh)
+ if self.dockwidget is not None:
+ self.dockwidget.blockSignals(False)
+
+ def __eventually_raise_help(self, text, force=False):
+ index = self.source_combo.currentIndex()
+ if hasattr(self.main, 'tabifiedDockWidgets'):
+ # 'QMainWindow.tabifiedDockWidgets' was introduced in PyQt 4.5
+ if (self.dockwidget and (force or self.dockwidget.isVisible()) and
+ not self.ismaximized and
+ (force or text != self._last_texts[index])):
+ dockwidgets = self.main.tabifiedDockWidgets(self.dockwidget)
+ if (self.console.dockwidget not in dockwidgets and
+ self.main.ipyconsole is not None and
+ self.main.ipyconsole.dockwidget not in dockwidgets):
+ self.switch_to_plugin()
+ self._last_texts[index] = text
+
+ def load_history(self, obj=None):
+ """Load history from a text file in user home directory"""
+ if osp.isfile(self.LOG_PATH):
+ history = [line.replace('\n', '')
+ for line in open(self.LOG_PATH, 'r').readlines()]
+ else:
+ history = []
+ return history
+
+ def save_history(self):
+ """Save history to a text file in user home directory"""
+ # Don't fail when saving search history to disk
+ # See issues 8878 and 6864
+ try:
+ search_history = [to_text_string(self.combo.itemText(index))
+ for index in range(self.combo.count())]
+ search_history = '\n'.join(search_history)
+ open(self.LOG_PATH, 'w').write(search_history)
+ except (UnicodeEncodeError, UnicodeDecodeError, EnvironmentError):
+ pass
+
+ @Slot(bool)
+ def toggle_plain_text(self, checked):
+ """Toggle plain text docstring"""
+ if checked:
+ self.docstring = checked
+ self.switch_to_plain_text()
+ self.force_refresh()
+ self.set_option('rich_mode', not checked)
+
+ @Slot(bool)
+ def toggle_show_source(self, checked):
+ """Toggle show source code"""
+ if checked:
+ self.switch_to_plain_text()
+ self.docstring = not checked
+ self.force_refresh()
+ self.set_option('rich_mode', not checked)
+
+ @Slot(bool)
+ def toggle_rich_text(self, checked):
+ """Toggle between sphinxified docstrings or plain ones"""
+ if checked:
+ self.docstring = not checked
+ self.switch_to_rich_text()
+ self.set_option('rich_mode', checked)
+
+ @Slot(bool)
+ def toggle_auto_import(self, checked):
+ """Toggle automatic import feature"""
+ self.combo.validate_current_text()
+ self.set_option('automatic_import', checked)
+ self.force_refresh()
+
+ @Slot()
+ def toggle_locked(self):
+ """
+ Toggle locked state
+ locked = disable link with Console
+ """
+ self.locked = not self.locked
+ self._update_lock_icon()
+
+ def _update_lock_icon(self):
+ """Update locked state icon"""
+ icon = ima.icon('lock') if self.locked else ima.icon('lock_open')
+ self.locked_button.setIcon(icon)
+ tip = _("Unlock") if self.locked else _("Lock")
+ self.locked_button.setToolTip(tip)
+
+ def set_shell(self, shell):
+ """Bind to shell"""
+ self.shell = shell
+
+ def get_shell(self):
+ """
+ Return shell which is currently bound to Help,
+ or another running shell if it has been terminated
+ """
+ if (not hasattr(self.shell, 'get_doc') or
+ (hasattr(self.shell, 'is_running') and
+ not self.shell.is_running())):
+ self.shell = None
+ if self.main.ipyconsole is not None:
+ shell = self.main.ipyconsole.get_current_shellwidget()
+ if shell is not None and shell.kernel_client is not None:
+ self.shell = shell
+ if self.shell is None:
+ self.shell = self.internal_shell
+ return self.shell
+
+ def render_sphinx_doc(self, doc, context=None, css_path=CSS_PATH):
+ """Transform doc string dictionary to HTML and show it"""
+ # Math rendering option could have changed
+ if self.main.editor is not None:
+ fname = self.main.editor.get_current_filename()
+ dname = osp.dirname(fname)
+ else:
+ dname = ''
+ self._sphinx_thread.render(doc, context, self.get_option('math'),
+ dname, css_path=self.css_path)
+
+ def _on_sphinx_thread_html_ready(self, html_text):
+ """Set our sphinx documentation based on thread result"""
+ self._sphinx_thread.wait()
+ self.set_rich_text_html(html_text, QUrl.fromLocalFile(self.css_path))
+
+ def _on_sphinx_thread_error_msg(self, error_msg):
+ """ Display error message on Sphinx rich text failure"""
+ self._sphinx_thread.wait()
+ self.plain_text_action.setChecked(True)
+ sphinx_ver = programs.get_module_version('sphinx')
+ QMessageBox.critical(self,
+ _('Help'),
+ _("The following error occured when calling "
+ "Sphinx %s.
Incompatible Sphinx "
+ "version or doc string decoding failed."
+ "
Error message:
%s"
+ ) % (sphinx_ver, error_msg))
+
+ def show_help(self, obj_text, ignore_unknown=False):
+ """Show help"""
+ shell = self.get_shell()
+ if shell is None:
+ return
+ obj_text = to_text_string(obj_text)
+
+ if not shell.is_defined(obj_text):
+ if self.get_option('automatic_import') and \
+ self.internal_shell.is_defined(obj_text, force_import=True):
+ shell = self.internal_shell
+ else:
+ shell = None
+ doc = None
+ source_text = None
+
+ if shell is not None:
+ doc = shell.get_doc(obj_text)
+ source_text = shell.get_source(obj_text)
+
+ is_code = False
+
+ if self.rich_help:
+ self.render_sphinx_doc(doc, css_path=self.css_path)
+ return doc is not None
+ elif self.docstring:
+ hlp_text = doc
+ if hlp_text is None:
+ hlp_text = source_text
+ if hlp_text is None:
+ hlp_text = self.no_doc_string
+ if ignore_unknown:
+ return False
+ else:
+ hlp_text = source_text
+ if hlp_text is None:
+ hlp_text = doc
+ if hlp_text is None:
+ hlp_text = _("No source code available.")
+ if ignore_unknown:
+ return False
+ else:
+ is_code = True
+ self.set_plain_text(hlp_text, is_code=is_code)
+ return True
diff --git a/spyder/widgets/projects/tests/__init__.py b/spyder/plugins/help/tests/__init__.py
similarity index 100%
rename from spyder/widgets/projects/tests/__init__.py
rename to spyder/plugins/help/tests/__init__.py
diff --git a/spyder/plugins/help/tests/test_plugin.py b/spyder/plugins/help/tests/test_plugin.py
new file mode 100644
index 00000000000..6d01cadad83
--- /dev/null
+++ b/spyder/plugins/help/tests/test_plugin.py
@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright © Spyder Project Contributors
+#
+# Licensed under the terms of the MIT License
+# (see spyder/__init__.py for details)
+# -----------------------------------------------------------------------------
+
+"""
+Tests for the Spyder `help` plugn, `help.py`.
+"""
+
+# Standard library imports
+try:
+ from unittest.mock import Mock, MagicMock
+except ImportError:
+ from mock import Mock, MagicMock # Python 2
+
+# Third party imports
+from qtpy import PYQT_VERSION
+from qtpy.QtWidgets import QMainWindow
+from qtpy.QtWebEngineWidgets import WEBENGINE
+import pytest
+from flaky import flaky
+
+# Local imports
+from spyder.plugins.help.plugin import Help
+from spyder.utils.introspection.utils import default_info_response
+
+
+# =============================================================================
+# Fixtures
+# =============================================================================
+@pytest.fixture
+def help_plugin(qtbot):
+ """Help plugin fixture"""
+
+ class MainMock(QMainWindow):
+ def __getattr__(self, attr):
+ if attr == 'ipyconsole' or attr == 'editor':
+ return None
+ else:
+ return Mock()
+
+ window = MainMock()
+ help_plugin = Help(parent=window)
+ window.setCentralWidget(help_plugin)
+
+ webview = help_plugin.rich_text.webview._webview
+ if WEBENGINE:
+ help_plugin._webpage = webview.page()
+ else:
+ help_plugin._webpage = webview.page().mainFrame()
+
+ qtbot.addWidget(window)
+ window.show()
+ return help_plugin
+
+
+# =============================================================================
+# Utility functions
+# =============================================================================
+def check_text(widget, text):
+ """Check if some text is present in a widget."""
+ if WEBENGINE:
+ def callback(data):
+ global html
+ html = data
+ widget.toHtml(callback)
+ try:
+ return text in html
+ except NameError:
+ return False
+ else:
+ return text in widget.toHtml()
+
+
+# =============================================================================
+# Tests
+# =============================================================================
+@flaky(max_runs=3)
+@pytest.mark.skipif(PYQT_VERSION > '5.10', reason='Segfaults in PyQt 5.10+')
+def test_no_docs_message(help_plugin, qtbot):
+ """
+ Test that no docs message is shown when instrospection plugins
+ can't get any info.
+ """
+ help_plugin.render_sphinx_doc(default_info_response())
+ qtbot.waitUntil(lambda: check_text(help_plugin._webpage,
+ "No documentation available"),
+ timeout=4000)
+
+
+@flaky(max_runs=3)
+@pytest.mark.skipif(PYQT_VERSION > '5.10', reason='Segfaults in PyQt 5.10+')
+def test_no_further_docs_message(help_plugin, qtbot):
+ """
+ Test that no further docs message is shown when instrospection
+ plugins can get partial info.
+ """
+ info = default_info_response()
+ info['name'] = 'foo'
+ info['argspec'] = '(x, y)'
+
+ help_plugin.render_sphinx_doc(info)
+ qtbot.waitUntil(lambda: check_text(help_plugin._webpage,
+ "No further documentation available"),
+ timeout=3000)
+
+
+@pytest.mark.skipif(PYQT_VERSION > '5.10', reason='Segfaults in PyQt 5.10+')
+def test_help_opens_when_show_tutorial_unit(help_plugin, qtbot):
+ """Test fix for #6317 : 'Show tutorial' opens the help plugin if closed."""
+ MockDockwidget = MagicMock()
+ MockDockwidget.return_value.isVisible.return_value = False
+ mockDockwidget_instance = MockDockwidget()
+ mock_show_rich_text = Mock()
+
+ help_plugin.dockwidget = mockDockwidget_instance
+ help_plugin.show_rich_text = mock_show_rich_text
+
+ help_plugin.show_tutorial()
+ qtbot.wait(100)
+
+ assert mock_show_rich_text.call_count == 1
+
+ MockDockwidget.return_value.isVisible.return_value = True
+ mockDockwidget_instance = MockDockwidget()
+ help_plugin.dockwidget = mockDockwidget_instance
+
+ help_plugin.show_tutorial()
+ qtbot.wait(100)
+ assert mock_show_rich_text.call_count == 2
+
+
+if __name__ == "__main__":
+ pytest.main()
diff --git a/spyder/plugins/help/tests/test_widgets.py b/spyder/plugins/help/tests/test_widgets.py
new file mode 100644
index 00000000000..ff2a1bd9eaa
--- /dev/null
+++ b/spyder/plugins/help/tests/test_widgets.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright © Spyder Project Contributors
+# Licensed under the terms of the MIT License
+#
+"""
+Tests for the Help widgets.
+"""
+
+# Test library imports
+import pytest
+
+# Local imports
+from spyder.plugins.help.widgets import RichText, PlainText
+
+
+@pytest.fixture
+def richtext(qtbot):
+ """Set up richtext widget."""
+ widget = RichText(None)
+ qtbot.addWidget(widget)
+ return widget
+
+
+@pytest.fixture
+def plaintext(qtbot):
+ """Set up plaintext widget."""
+ widget = PlainText(None)
+ qtbot.addWidget(widget)
+ return widget
+
+
+def test_richtext(richtext):
+ """Run RichText."""
+ assert richtext
+
+
+def test_plaintext(plaintext):
+ """Run PlainText."""
+ assert plaintext
+
+
+if __name__ == "__main__":
+ pytest.main()
diff --git a/spyder/plugins/help/utils/LICENSE.txt b/spyder/plugins/help/utils/LICENSE.txt
new file mode 100644
index 00000000000..f565ba87307
--- /dev/null
+++ b/spyder/plugins/help/utils/LICENSE.txt
@@ -0,0 +1,19 @@
+Help Utilities License Information
+##################################
+
+Many source files in this directory originate from sources other than Spyder,
+and each is covered by its own license and copyright notice.
+These are listed in the headers for all files, and in the LICENSE.txt file
+in the package's subdirectory if multiple are present. Additionally,
+they are all listed in full in NOTICE.txt at the root of this repo/package,
+which should be included with any distribution that includes these files.
+The NOTICE.txt file can also be viewed online at Spyder's Github repository:
+https://github.com/spyder-ide/spyder/blob/master/NOTICE.txt
+
+Any file not otherwise listed is covered by Spyder's MIT (Expat) License,
+described in the LICENSE.txt file in this repository and Spyder's __init__.py,
+which should also be included with any distribution.
+The current version can also be viewed online at:
+https://github.com/spyder-ide/spyder/blob/master/LICENSE.txt
+
+All trademarks are the property of their respective owners.
diff --git a/spyder/plugins/help/utils/__init__.py b/spyder/plugins/help/utils/__init__.py
new file mode 100644
index 00000000000..b40f03ab67e
--- /dev/null
+++ b/spyder/plugins/help/utils/__init__.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (c) 2009- Spyder Project Contributors and others (see LICENSE.txt)
+#
+# Licensed under the terms of the MIT and other licenses where noted
+# (see LICENSE.txt in this directory and NOTICE.txt in the root for details)
+# -----------------------------------------------------------------------------
+
+"""
+spyder.plugins.help.utils
+=================
+
+Configuration files for the Help plugin rich text mode.
+
+See their headers, LICENSE.txt in this directory or NOTICE.txt for licenses.
+"""
+
+import sys
+from spyder.config.base import get_module_source_path
+sys.path.insert(0, get_module_source_path(__name__))
diff --git a/spyder/plugins/help/utils/conf.py b/spyder/plugins/help/utils/conf.py
new file mode 100644
index 00000000000..e6fa44b9701
--- /dev/null
+++ b/spyder/plugins/help/utils/conf.py
@@ -0,0 +1,129 @@
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Copyright (C) 2009 Tim Dumol
+# Copyright (C) 2010- Spyder Project Contributors
+#
+# Distributed under the terms of the Modified BSD License
+# (BSD 3-clause; see NOTICE.txt in the Spyder root directory for details).
+# -----------------------------------------------------------------------------
+
+"""
+Sphinx configuration file for the Help plugin rich text mode.
+
+Originally based on a portion of sagenb/misc/sphinxify.py from the
+`Sage Notebook project `_,
+part of the `SageMath `_ system.
+"""
+
+# Third party imports
+from sphinx import __version__ as sphinx_version
+
+# Local imports
+from spyder.config.main import CONF
+
+
+#==============================================================================
+# General configuration
+#==============================================================================
+
+# If your extensions are in another directory, add it here. If the directory
+# is relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+#sys.path.append(os.path.abspath('.'))
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+
+# We need jsmath to get pretty plain-text latex in docstrings
+math = CONF.get('help', 'math', '')
+
+if sphinx_version < "1.1" or not math:
+ extensions = ['sphinx.ext.jsmath']
+else:
+ extensions = ['sphinx.ext.mathjax']
+
+# For scipy and matplotlib docstrings, which need this extension to
+# be rendered correctly (see Issue 1138)
+extensions.append('sphinx.ext.autosummary')
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['templates']
+
+# MathJax load path (doesn't have effect for sphinx 1.0-)
+mathjax_path = 'MathJax/MathJax.js'
+
+# JsMath load path (doesn't have effect for sphinx 1.1+)
+jsmath_path = 'easy/load.js'
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'docstring'
+
+# General information about the project.
+project = u"Spyder Help plugin"
+copyright = u'The Spyder Project Contributors'
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_trees = ['.build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#
+# TODO: This role has to be set on a per project basis, i.e. numpy, sympy,
+# mpmath, etc, use different default_role's which give different rendered
+# docstrings. Setting this to None until it's solved.
+default_role = 'None'
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+add_function_parentheses = True
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+#==============================================================================
+# Options for HTML output
+#==============================================================================
+
+# The style sheet to use for HTML and HTML Help pages. A file of that name
+# must exist either in Sphinx' static/ path, or in one of the custom paths
+# given in html_static_path.
+html_style = 'default.css'
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# " v documentation".
+html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+html_short_title = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['static']
+
+# A dictionary of values to pass into the template engine’s context for all
+# pages
+html_context = {}
+
+# If true, Smart Quotes will be used to convert quotes and dashes to
+# typographically correct entities.
+# Spyder: Disabled to fix conflict with qtwebview and mathjax. See issue #5514
+if sphinx_version < "1.7":
+ html_use_smartypants = False
+else:
+ smartquotes = False
+
+# If false, no module index is generated.
+html_use_modindex = False
+
+# If false, no index is generated.
+html_use_index = False
+
+# If true, the index is split into individual pages for each letter.
+html_split_index = False
+
+# If true, the reST sources are included in the HTML build as _sources/.
+html_copy_source = False
+
diff --git a/spyder/utils/help/js/collapse_sections.js b/spyder/plugins/help/utils/js/collapse_sections.js
similarity index 83%
rename from spyder/utils/help/js/collapse_sections.js
rename to spyder/plugins/help/utils/js/collapse_sections.js
index 7b94562545d..f028384906c 100644
--- a/spyder/utils/help/js/collapse_sections.js
+++ b/spyder/plugins/help/utils/js/collapse_sections.js
@@ -1,12 +1,19 @@
//----------------------------------------------------------------------------
// Toggleable sections
//
-// Added expand/collapse functionality to RST sections.
-// Code from the Cloud Sphinx theme
-//
// Copyright 2011-2012 by Assurance Technologies
+// Copyright 2014- Spyder Project Contributors
+//
+// Distributed under the terms of the 3-Clause BSD License
+// (see NOTICE.txt in the Spyder repo's root directory for more details)
+//
+//----------------------------------------------------------------------------
+//
+// Added expand/collapse functionality to RST sections.
//
-// Distributed under the terms of the BSD License
+// Adapted from portions of cloud_sptheme/themes/cloud/static/cloud.js_t
+// from the Cloud Sphinx theme:
+// https://bitbucket.org/ecollins/cloud_sptheme/
//----------------------------------------------------------------------------
//============================================================================
diff --git a/spyder/utils/help/js/copy_button.js b/spyder/plugins/help/utils/js/copy_button.js
similarity index 83%
rename from spyder/utils/help/js/copy_button.js
rename to spyder/plugins/help/utils/js/copy_button.js
index 6d90f255038..69049c0a1d8 100644
--- a/spyder/utils/help/js/copy_button.js
+++ b/spyder/plugins/help/utils/js/copy_button.js
@@ -1,11 +1,20 @@
//----------------------------------------------------------------------------
// Copy Button
//
+// Copyright (c) 2012 Python Software Foundation
+// Copyright (c) 2012- Spyder Project Contributors
+//
+// Distributed under the terms of the Python Software Foundation License Ver 2
+// (see NOTICE.txt in the Spyder repo's root directory for more details)
+//
+//----------------------------------------------------------------------------
+//
// Add a [>>>] button on the top-right corner of code samples to hide
-// the >>> and ... prompts and the output and thus make the code
-// copyable.
+// the >>> and ... prompts and the output and thus make the code copyable.
//
-// Taken from http://docs.python.org/_static/copybutton.js
+// Adapted from python_docs_theme/static/copybutton.js of the
+// Python Docs Theme: https://github.com/python/python-docs-theme
+// Also availible at: https://docs.python.org/_static/copybutton.js
//----------------------------------------------------------------------------
//============================================================================
diff --git a/spyder/utils/help/js/fix_image_paths.js b/spyder/plugins/help/utils/js/fix_image_paths.js
similarity index 100%
rename from spyder/utils/help/js/fix_image_paths.js
rename to spyder/plugins/help/utils/js/fix_image_paths.js
diff --git a/spyder/utils/help/js/jquery.js b/spyder/plugins/help/utils/js/jquery.js
similarity index 99%
rename from spyder/utils/help/js/jquery.js
rename to spyder/plugins/help/utils/js/jquery.js
index 3774ff98613..ceb681ff9f8 100644
--- a/spyder/utils/help/js/jquery.js
+++ b/spyder/plugins/help/utils/js/jquery.js
@@ -3645,7 +3645,7 @@ if ( !jQuery.support.submitBubbles ) {
});
// return undefined since we don't need an event listener
},
-
+
postDispatch: function( event ) {
// If form was submitted by the user, bubble the event up the tree
if ( event._submit_bubble ) {
diff --git a/spyder/utils/help/js/math_config.js b/spyder/plugins/help/utils/js/math_config.js
similarity index 98%
rename from spyder/utils/help/js/math_config.js
rename to spyder/plugins/help/utils/js/math_config.js
index 3e5dcce8c70..d8a53d321a9 100644
--- a/spyder/utils/help/js/math_config.js
+++ b/spyder/plugins/help/utils/js/math_config.js
@@ -8,7 +8,7 @@
//============================================================================
// On document ready
-//============================================================================
+//============================================================================
{% if right_sphinx_version and math_on %}
@@ -30,7 +30,7 @@ $(document).ready(function () {
"SVG": {
blacker: 1
},
-
+
{% if platform == 'win32' %}
// Change math preview size so that it doesn't look too big while
// redendered
@@ -42,7 +42,7 @@ $(document).ready(function () {
}
{% endif %}
});
-
+
// MathJax Hooks
// -------------
// Put here any code that needs to be evaluated after MathJax has been
@@ -51,7 +51,7 @@ $(document).ready(function () {
// Eliminate unnecessary margin-bottom for inline math
$('span.math svg').css('margin-bottom', '0px');
});
-
+
{% if platform == 'win32' %}
// Windows fix
// -----------
diff --git a/spyder/plugins/help/utils/js/mathjax/LICENSE.txt b/spyder/plugins/help/utils/js/mathjax/LICENSE.txt
new file mode 100644
index 00000000000..20e4bd85661
--- /dev/null
+++ b/spyder/plugins/help/utils/js/mathjax/LICENSE.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/spyder/plugins/help/utils/js/mathjax/MathJax.js b/spyder/plugins/help/utils/js/mathjax/MathJax.js
new file mode 100644
index 00000000000..c54a1ed2d36
--- /dev/null
+++ b/spyder/plugins/help/utils/js/mathjax/MathJax.js
@@ -0,0 +1,19 @@
+/*
+ * /MathJax.js
+ *
+ * Copyright (c) 2009-2018 The MathJax Consortium
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+if(document.getElementById&&document.childNodes&&document.createElement){if(!(window.MathJax&&MathJax.Hub)){if(window.MathJax){window.MathJax={AuthorConfig:window.MathJax}}else{window.MathJax={}}MathJax.isPacked=true;MathJax.version="2.7.5";MathJax.fileversion="2.7.5";MathJax.cdnVersion="2.7.5";MathJax.cdnFileVersions={};(function(d){var b=window[d];if(!b){b=window[d]={}}var e=[];var c=function(f){var g=f.constructor;if(!g){g=function(){}}for(var h in f){if(h!=="constructor"&&f.hasOwnProperty(h)){g[h]=f[h]}}return g};var a=function(){return function(){return arguments.callee.Init.call(this,arguments)}};b.Object=c({constructor:a(),Subclass:function(f,h){var g=a();g.SUPER=this;g.Init=this.Init;g.Subclass=this.Subclass;g.Augment=this.Augment;g.protoFunction=this.protoFunction;g.can=this.can;g.has=this.has;g.isa=this.isa;g.prototype=new this(e);g.prototype.constructor=g;g.Augment(f,h);return g},Init:function(f){var g=this;if(f.length===1&&f[0]===e){return g}if(!(g instanceof f.callee)){g=new f.callee(e)}return g.Init.apply(g,f)||g},Augment:function(f,g){var h;if(f!=null){for(h in f){if(f.hasOwnProperty(h)){this.protoFunction(h,f[h])}}if(f.toString!==this.prototype.toString&&f.toString!=={}.toString){this.protoFunction("toString",f.toString)}}if(g!=null){for(h in g){if(g.hasOwnProperty(h)){this[h]=g[h]}}}return this},protoFunction:function(g,f){this.prototype[g]=f;if(typeof f==="function"){f.SUPER=this.SUPER.prototype}},prototype:{Init:function(){},SUPER:function(f){return f.callee.SUPER},can:function(f){return typeof(this[f])==="function"},has:function(f){return typeof(this[f])!=="undefined"},isa:function(f){return(f instanceof Object)&&(this instanceof f)}},can:function(f){return this.prototype.can.call(this,f)},has:function(f){return this.prototype.has.call(this,f)},isa:function(g){var f=this;while(f){if(f===g){return true}else{f=f.SUPER}}return false},SimpleSUPER:c({constructor:function(f){return this.SimpleSUPER.define(f)},define:function(f){var h={};if(f!=null){for(var g in f){if(f.hasOwnProperty(g)){h[g]=this.wrap(g,f[g])}}if(f.toString!==this.prototype.toString&&f.toString!=={}.toString){h.toString=this.wrap("toString",f.toString)}}return h},wrap:function(i,h){if(typeof(h)!=="function"||!h.toString().match(/\.\s*SUPER\s*\(/)){return h}var g=function(){this.SUPER=g.SUPER[i];try{var f=h.apply(this,arguments)}catch(j){delete this.SUPER;throw j}delete this.SUPER;return f};g.toString=function(){return h.toString.apply(h,arguments)};return g}})});b.Object.isArray=Array.isArray||function(f){return Object.prototype.toString.call(f)==="[object Array]"};b.Object.Array=Array})("MathJax");(function(BASENAME){var BASE=window[BASENAME];if(!BASE){BASE=window[BASENAME]={}}var isArray=BASE.Object.isArray;var CALLBACK=function(data){var cb=function(){return arguments.callee.execute.apply(arguments.callee,arguments)};for(var id in CALLBACK.prototype){if(CALLBACK.prototype.hasOwnProperty(id)){if(typeof(data[id])!=="undefined"){cb[id]=data[id]}else{cb[id]=CALLBACK.prototype[id]}}}cb.toString=CALLBACK.prototype.toString;return cb};CALLBACK.prototype={isCallback:true,hook:function(){},data:[],object:window,execute:function(){if(!this.called||this.autoReset){this.called=!this.autoReset;return this.hook.apply(this.object,this.data.concat([].slice.call(arguments,0)))}},reset:function(){delete this.called},toString:function(){return this.hook.toString.apply(this.hook,arguments)}};var ISCALLBACK=function(f){return(typeof(f)==="function"&&f.isCallback)};var EVAL=function(code){return eval.call(window,code)};var TESTEVAL=function(){EVAL("var __TeSt_VaR__ = 1");if(window.__TeSt_VaR__){try{delete window.__TeSt_VaR__}catch(error){window.__TeSt_VaR__=null}}else{if(window.execScript){EVAL=function(code){BASE.__code=code;code="try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";window.execScript(code);var result=BASE.__result;delete BASE.__result;delete BASE.__code;if(result instanceof Error){throw result}return result}}else{EVAL=function(code){BASE.__code=code;code="try {"+BASENAME+".__result = eval("+BASENAME+".__code)} catch(err) {"+BASENAME+".__result = err}";var head=(document.getElementsByTagName("head"))[0];if(!head){head=document.body}var script=document.createElement("script");script.appendChild(document.createTextNode(code));head.appendChild(script);head.removeChild(script);var result=BASE.__result;delete BASE.__result;delete BASE.__code;if(result instanceof Error){throw result}return result}}}TESTEVAL=null};var USING=function(args,i){if(arguments.length>1){if(arguments.length===2&&!(typeof arguments[0]==="function")&&arguments[0] instanceof Object&&typeof arguments[1]==="number"){args=[].slice.call(args,i)}else{args=[].slice.call(arguments,0)}}if(isArray(args)&&args.length===1&&typeof(args[0])==="function"){args=args[0]}if(typeof args==="function"){if(args.execute===CALLBACK.prototype.execute){return args}return CALLBACK({hook:args})}else{if(isArray(args)){if(typeof(args[0])==="string"&&args[1] instanceof Object&&typeof args[1][args[0]]==="function"){return CALLBACK({hook:args[1][args[0]],object:args[1],data:args.slice(2)})}else{if(typeof args[0]==="function"){return CALLBACK({hook:args[0],data:args.slice(1)})}else{if(typeof args[1]==="function"){return CALLBACK({hook:args[1],object:args[0],data:args.slice(2)})}}}}else{if(typeof(args)==="string"){if(TESTEVAL){TESTEVAL()}return CALLBACK({hook:EVAL,data:[args]})}else{if(args instanceof Object){return CALLBACK(args)}else{if(typeof(args)==="undefined"){return CALLBACK({})}}}}}throw Error("Can't make callback from given data")};var DELAY=function(time,callback){callback=USING(callback);callback.timeout=setTimeout(callback,time);return callback};var WAITFOR=function(callback,signal){callback=USING(callback);if(!callback.called){WAITSIGNAL(callback,signal);signal.pending++}};var WAITEXECUTE=function(){var signals=this.signal;delete this.signal;this.execute=this.oldExecute;delete this.oldExecute;var result=this.execute.apply(this,arguments);if(ISCALLBACK(result)&&!result.called){WAITSIGNAL(result,signals)}else{for(var i=0,m=signals.length;i0&&priority=0;i--){this.hooks.splice(i,1)}this.remove=[]}});var EXECUTEHOOKS=function(hooks,data,reset){if(!hooks){return null}if(!isArray(hooks)){hooks=[hooks]}if(!isArray(data)){data=(data==null?[]:[data])}var handler=HOOKS(reset);for(var i=0,m=hooks.length;ig){g=document.styleSheets.length}if(!i){i=document.head||((document.getElementsByTagName("head"))[0]);if(!i){i=document.body}}return i};var f=[];var c=function(){for(var k=0,j=f.length;k=this.timeout){i(this.STATUS.ERROR);return 1}return 0},file:function(j,i){if(i<0){a.Ajax.loadTimeout(j)}else{a.Ajax.loadComplete(j)}},execute:function(){this.hook.call(this.object,this,this.data[0],this.data[1])},checkSafari2:function(i,j,k){if(i.time(k)){return}if(document.styleSheets.length>j&&document.styleSheets[j].cssRules&&document.styleSheets[j].cssRules.length){k(i.STATUS.OK)}else{setTimeout(i,i.delay)}},checkLength:function(i,l,n){if(i.time(n)){return}var m=0;var j=(l.sheet||l.styleSheet);try{if((j.cssRules||j.rules||[]).length>0){m=1}}catch(k){if(k.message.match(/protected variable|restricted URI/)){m=1}else{if(k.message.match(/Security error/)){m=1}}}if(m){setTimeout(a.Callback([n,i.STATUS.OK]),0)}else{setTimeout(i,i.delay)}}},loadComplete:function(i){i=this.fileURL(i);var j=this.loading[i];if(j&&!j.preloaded){a.Message.Clear(j.message);clearTimeout(j.timeout);if(j.script){if(f.length===0){setTimeout(c,0)}f.push(j.script)}this.loaded[i]=j.status;delete this.loading[i];this.addHook(i,j.callback)}else{if(j){delete this.loading[i]}this.loaded[i]=this.STATUS.OK;j={status:this.STATUS.OK}}if(!this.loadHooks[i]){return null}return this.loadHooks[i].Execute(j.status)},loadTimeout:function(i){if(this.loading[i].timeout){clearTimeout(this.loading[i].timeout)}this.loading[i].status=this.STATUS.ERROR;this.loadError(i);this.loadComplete(i)},loadError:function(i){a.Message.Set(["LoadFailed","File failed to load: %1",i],null,2000);a.Hub.signal.Post(["file load error",i])},Styles:function(k,l){var i=this.StyleString(k);if(i===""){l=a.Callback(l);l()}else{var j=document.createElement("style");j.type="text/css";this.head=h(this.head);this.head.appendChild(j);if(j.styleSheet&&typeof(j.styleSheet.cssText)!=="undefined"){j.styleSheet.cssText=i}else{j.appendChild(document.createTextNode(i))}l=this.timer.create.call(this,l,j)}return l},StyleString:function(n){if(typeof(n)==="string"){return n}var k="",o,m;for(o in n){if(n.hasOwnProperty(o)){if(typeof n[o]==="string"){k+=o+" {"+n[o]+"}\n"}else{if(a.Object.isArray(n[o])){for(var l=0;l="0"&&q<="9"){f[j]=p[f[j]-1];if(typeof f[j]==="number"){f[j]=this.number(f[j])}}else{if(q==="{"){q=f[j].substr(1);if(q>="0"&&q<="9"){f[j]=p[f[j].substr(1,f[j].length-2)-1];if(typeof f[j]==="number"){f[j]=this.number(f[j])}}else{var k=f[j].match(/^\{([a-z]+):%(\d+)\|(.*)\}$/);if(k){if(k[1]==="plural"){var d=p[k[2]-1];if(typeof d==="undefined"){f[j]="???"}else{d=this.plural(d)-1;var h=k[3].replace(/(^|[^%])(%%)*%\|/g,"$1$2%\uEFEF").split(/\|/);if(d>=0&&d=3){c.push([f[0],f[1],this.processSnippet(g,f[2])])}else{c.push(e[d])}}}}else{c.push(e[d])}}return c},markdownPattern:/(%.)|(\*{1,3})((?:%.|.)+?)\2|(`+)((?:%.|.)+?)\4|\[((?:%.|.)+?)\]\(([^\s\)]+)\)/,processMarkdown:function(b,h,d){var j=[],e;var c=b.split(this.markdownPattern);var g=c[0];for(var f=1,a=c.length;f1?d[1]:""));f=null}if(e&&(!b.preJax||d)){c.nodeValue=c.nodeValue.replace(b.postJax,(e.length>1?e[1]:""))}if(f&&!f.nodeValue.match(/\S/)){f=f.previousSibling}}if(b.preRemoveClass&&f&&f.className===b.preRemoveClass){a.MathJax.preview=f}a.MathJax.checked=1},processInput:function(a){var b,i=MathJax.ElementJax.STATE;var h,e,d=a.scripts.length;try{while(a.ithis.processUpdateTime&&a.i1){d.jax[a.outputJax].push(b)}b.MathJax.state=c.OUTPUT},prepareOutput:function(c,f){while(c.jthis.processUpdateTime&&h.i=0;q--){if((b[q].src||"").match(f)){s.script=b[q].innerHTML;if(RegExp.$2){var t=RegExp.$2.substr(1).split(/\&/);for(var p=0,l=t.length;p=parseInt(y[z])}}return true},Select:function(j){var i=j[d.Browser];if(i){return i(d.Browser)}return null}};var e=k.replace(/^Mozilla\/(\d+\.)+\d+ /,"").replace(/[a-z][-a-z0-9._: ]+\/\d+[^ ]*-[^ ]*\.([a-z][a-z])?\d+ /i,"").replace(/Gentoo |Ubuntu\/(\d+\.)*\d+ (\([^)]*\) )?/,"");d.Browser=d.Insert(d.Insert(new String("Unknown"),{version:"0.0"}),a);for(var v in a){if(a.hasOwnProperty(v)){if(a[v]&&v.substr(0,2)==="is"){v=v.slice(2);if(v==="Mac"||v==="PC"){continue}d.Browser=d.Insert(new String(v),a);var r=new RegExp(".*(Version/| Trident/.*; rv:)((?:\\d+\\.)+\\d+)|.*("+v+")"+(v=="MSIE"?" ":"/")+"((?:\\d+\\.)*\\d+)|(?:^|\\(| )([a-z][-a-z0-9._: ]+|(?:Apple)?WebKit)/((?:\\d+\\.)+\\d+)");var u=r.exec(e)||["","","","unknown","0.0"];d.Browser.name=(u[1]!=""?v:(u[3]||u[5]));d.Browser.version=u[2]||u[4]||u[6];break}}}try{d.Browser.Select({Safari:function(j){var i=parseInt((String(j.version).split("."))[0]);if(i>85){j.webkit=j.version}if(i>=538){j.version="8.0"}else{if(i>=537){j.version="7.0"}else{if(i>=536){j.version="6.0"}else{if(i>=534){j.version="5.1"}else{if(i>=533){j.version="5.0"}else{if(i>=526){j.version="4.0"}else{if(i>=525){j.version="3.1"}else{if(i>500){j.version="3.0"}else{if(i>400){j.version="2.0"}else{if(i>85){j.version="1.0"}}}}}}}}}}j.webkit=(navigator.appVersion.match(/WebKit\/(\d+)\./))[1];j.isMobile=(navigator.appVersion.match(/Mobile/i)!=null);j.noContextMenu=j.isMobile},Firefox:function(j){if((j.version==="0.0"||k.match(/Firefox/)==null)&&navigator.product==="Gecko"){var m=k.match(/[\/ ]rv:(\d+\.\d.*?)[\) ]/);if(m){j.version=m[1]}else{var i=(navigator.buildID||navigator.productSub||"0").substr(0,8);if(i>="20111220"){j.version="9.0"}else{if(i>="20111120"){j.version="8.0"}else{if(i>="20110927"){j.version="7.0"}else{if(i>="20110816"){j.version="6.0"}else{if(i>="20110621"){j.version="5.0"}else{if(i>="20110320"){j.version="4.0"}else{if(i>="20100121"){j.version="3.6"}else{if(i>="20090630"){j.version="3.5"}else{if(i>="20080617"){j.version="3.0"}else{if(i>="20061024"){j.version="2.0"}}}}}}}}}}}}j.isMobile=(navigator.appVersion.match(/Android/i)!=null||k.match(/ Fennec\//)!=null||k.match(/Mobile/)!=null)},Chrome:function(i){i.noContextMenu=i.isMobile=!!navigator.userAgent.match(/ Mobile[ \/]/)},Opera:function(i){i.version=opera.version()},Edge:function(i){i.isMobile=!!navigator.userAgent.match(/ Phone/)},MSIE:function(j){j.isMobile=!!navigator.userAgent.match(/ Phone/);j.isIE9=!!(document.documentMode&&(window.performance||window.msPerformance));MathJax.HTML.setScriptBug=!j.isIE9||document.documentMode<9;MathJax.Hub.msieHTMLCollectionBug=(document.documentMode<9);if(document.documentMode<10&&!s.params.NoMathPlayer){try{new ActiveXObject("MathPlayer.Factory.1");j.hasMathPlayer=true}catch(m){}try{if(j.hasMathPlayer){var i=document.createElement("object");i.id="mathplayer";i.classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987";g.appendChild(i);document.namespaces.add("m","http://www.w3.org/1998/Math/MathML");j.mpNamespace=true;if(document.readyState&&(document.readyState==="loading"||document.readyState==="interactive")){document.write('');j.mpImported=true}}else{document.namespaces.add("mjx_IE_fix","http://www.w3.org/1999/xlink")}}catch(m){}}}})}catch(c){console.error(c.message)}d.Browser.Select(MathJax.Message.browsers);if(h.AuthorConfig&&typeof h.AuthorConfig.AuthorInit==="function"){h.AuthorConfig.AuthorInit()}d.queue=h.Callback.Queue();d.queue.Push(["Post",s.signal,"Begin"],["Config",s],["Cookie",s],["Styles",s],["Message",s],function(){var i=h.Callback.Queue(s.Jax(),s.Extensions());return i.Push({})},["Menu",s],s.onLoad(),function(){MathJax.isReady=true},["Typeset",s],["Hash",s],["MenuZoom",s],["Post",s.signal,"End"])})("MathJax")}};
diff --git a/spyder/plugins/help/utils/js/mathjax/config/AM_CHTML-full.js b/spyder/plugins/help/utils/js/mathjax/config/AM_CHTML-full.js
new file mode 100644
index 00000000000..9490be76688
--- /dev/null
+++ b/spyder/plugins/help/utils/js/mathjax/config/AM_CHTML-full.js
@@ -0,0 +1,53 @@
+/*
+ * /MathJax/config/AM_CHTML-full.js
+ *
+ * Copyright (c) 2010-2018 The MathJax Consortium
+ *
+ * Part of the MathJax library.
+ * See http://www.mathjax.org for details.
+ *
+ * Licensed under the Apache License, Version 2.0;
+ * you may not use this file except in compliance with the License.
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+MathJax.Ajax.Preloading(
+ "[MathJax]/jax/input/AsciiMath/config.js",
+ "[MathJax]/jax/output/CommonHTML/config.js",
+ "[MathJax]/jax/output/PreviewHTML/config.js",
+ "[MathJax]/extensions/asciimath2jax.js",
+ "[MathJax]/extensions/MathEvents.js",
+ "[MathJax]/extensions/MathZoom.js",
+ "[MathJax]/extensions/MathMenu.js",
+ "[MathJax]/jax/element/mml/jax.js",
+ "[MathJax]/extensions/toMathML.js",
+ "[MathJax]/jax/input/AsciiMath/jax.js",
+ "[MathJax]/jax/output/CommonHTML/jax.js",
+ "[MathJax]/jax/output/CommonHTML/autoload/mtable.js",
+ "[MathJax]/jax/output/PreviewHTML/jax.js",
+ "[MathJax]/extensions/fast-preview.js",
+ "[MathJax]/extensions/AssistiveMML.js",
+ "[MathJax]/extensions/a11y/accessibility-menu.js"
+);
+
+MathJax.Hub.Config({
+ extensions: ['[a11y]/accessibility-menu.js']
+});
+
+MathJax.InputJax.AsciiMath=MathJax.InputJax({id:"AsciiMath",version:"2.7.5",directory:MathJax.InputJax.directory+"/AsciiMath",extensionDir:MathJax.InputJax.extensionDir+"/AsciiMath",config:{fixphi:true,useMathMLspacing:true,displaystyle:true,decimalsign:"."}});MathJax.InputJax.AsciiMath.Register("math/asciimath");MathJax.InputJax.AsciiMath.loadComplete("config.js");
+MathJax.OutputJax.CommonHTML=MathJax.OutputJax({id:"CommonHTML",version:"2.7.5",directory:MathJax.OutputJax.directory+"/CommonHTML",extensionDir:MathJax.OutputJax.extensionDir+"/CommonHTML",autoloadDir:MathJax.OutputJax.directory+"/CommonHTML/autoload",fontDir:MathJax.OutputJax.directory+"/CommonHTML/fonts",webfontDir:MathJax.OutputJax.fontDir+"/HTML-CSS",config:{matchFontHeight:true,scale:100,minScaleAdjust:50,mtextFontInherit:false,undefinedFamily:"STIXGeneral,'Cambria Math','Arial Unicode MS',serif",EqnChunk:(MathJax.Hub.Browser.isMobile?20:100),EqnChunkFactor:1.5,EqnChunkDelay:100,linebreaks:{automatic:false,width:"container"}}});if(!MathJax.Hub.config.delayJaxRegistration){MathJax.OutputJax.CommonHTML.Register("jax/mml")}MathJax.OutputJax.CommonHTML.loadComplete("config.js");
+MathJax.OutputJax.PreviewHTML=MathJax.OutputJax({id:"PreviewHTML",version:"2.7.5",directory:MathJax.OutputJax.directory+"/PreviewHTML",extensionDir:MathJax.OutputJax.extensionDir+"/PreviewHTML",noFastPreview:true,config:{scale:100,minScaleAdjust:50,mtextFontInherit:false,linebreaks:{automatic:false,width:"container"}}});if(!MathJax.Hub.config.delayJaxRegistration){MathJax.OutputJax.PreviewHTML.Register("jax/mml")}MathJax.OutputJax.PreviewHTML.loadComplete("config.js");
+MathJax.Extension.asciimath2jax={version:"2.7.5",config:{delimiters:[["`","`"]],skipTags:["script","noscript","style","textarea","pre","code","annotation","annotation-xml"],ignoreClass:"asciimath2jax_ignore",processClass:"asciimath2jax_process",preview:"AsciiMath"},ignoreTags:{br:(MathJax.Hub.Browser.isMSIE&&document.documentMode<9?"\n":" "),wbr:"","#comment":""},PreProcess:function(a){if(!this.configured){this.config=MathJax.Hub.CombineConfig("asciimath2jax",this.config);if(this.config.Augment){MathJax.Hub.Insert(this,this.config.Augment)}this.configured=true}if(typeof(a)==="string"){a=document.getElementById(a)}if(!a){a=document.body}if(this.createPatterns()){this.scanElement(a,a.nextSibling)}},createPatterns:function(){var d=[],c,a,b=this.config;this.match={};if(b.delimiters.length===0){return false}for(c=0,a=b.delimiters.length;c0){this.HoverFadeTimer(q,q.hover.inc);return}s.parentNode.removeChild(s);if(r){r.parentNode.removeChild(r)}if(q.hover.remove){clearTimeout(q.hover.remove)}delete q.hover},HoverFadeTimer:function(q,s,r){q.hover.inc=s;if(!q.hover.timer){q.hover.timer=setTimeout(g(["HoverFade",this,q]),(r||o.fadeDelay))}},HoverMenu:function(q){if(!q){q=window.event}return b[this.jax].ContextMenu(q,this.math,true)},ClearHover:function(q){if(q.hover.remove){clearTimeout(q.hover.remove)}if(q.hover.timer){clearTimeout(q.hover.timer)}f.ClearHoverTimer();delete q.hover},Px:function(q){if(Math.abs(q)<0.006){return"0px"}return q.toFixed(2).replace(/\.?0+$/,"")+"px"},getImages:function(){if(k.discoverable){var q=new Image();q.src=o.button.src}}};var a=c.Touch={last:0,delay:500,start:function(r){var q=new Date().getTime();var s=(q-a.lastt){z.style.height=t+"px";z.style.width=(x.zW+this.scrollSize)+"px"}if(z.offsetWidth>l){z.style.width=l+"px";z.style.height=(x.zH+this.scrollSize)+"px"}}if(this.operaPositionBug){z.style.width=Math.min(l,x.zW)+"px"}if(z.offsetWidth>m&&z.offsetWidth-m=9);h.msiePositionBug=!m;h.msieSizeBug=l.versionAtLeast("7.0")&&(!document.documentMode||n===7||n===8);h.msieZIndexBug=(n<=7);h.msieInlineBlockAlignBug=(n<=7);h.msieTrapEventBug=!window.addEventListener;if(document.compatMode==="BackCompat"){h.scrollSize=52}if(m){delete i.styles["#MathJax_Zoom"].filter}},Opera:function(l){h.operaPositionBug=true;h.operaRefreshBug=true}});h.topImg=(h.msieInlineBlockAlignBug?d.Element("img",{style:{width:0,height:0,position:"relative"},src:"about:blank"}):d.Element("span",{style:{width:0,height:0,display:"inline-block"}}));if(h.operaPositionBug||h.msieTopBug){h.topImg.style.border="1px solid"}MathJax.Callback.Queue(["StartupHook",MathJax.Hub.Register,"Begin Styles",{}],["Styles",f,i.styles],["Post",a.Startup.signal,"MathZoom Ready"],["loadComplete",f,"[MathJax]/extensions/MathZoom.js"])})(MathJax.Hub,MathJax.HTML,MathJax.Ajax,MathJax.OutputJax["HTML-CSS"],MathJax.OutputJax.NativeMML);
+(function(f,o,q,e,r){var p="2.7.5";var d=MathJax.Callback.Signal("menu");MathJax.Extension.MathMenu={version:p,signal:d};var t=function(u){return MathJax.Localization._.apply(MathJax.Localization,[["MathMenu",u]].concat([].slice.call(arguments,1)))};var i=MathJax.Object.isArray;var a=f.Browser.isPC,l=f.Browser.isMSIE,m=((document.documentMode||0)>8);var j=(a?null:"5px");var s=f.CombineConfig("MathMenu",{delay:150,showRenderer:true,showMathPlayer:true,showFontMenu:false,showContext:false,showDiscoverable:false,showLocale:true,showLocaleURL:false,semanticsAnnotations:{TeX:["TeX","LaTeX","application/x-tex"],StarMath:["StarMath 5.0"],Maple:["Maple"],ContentMathML:["MathML-Content","application/mathml-content+xml"],OpenMath:["OpenMath"]},windowSettings:{status:"no",toolbar:"no",locationbar:"no",menubar:"no",directories:"no",personalbar:"no",resizable:"yes",scrollbars:"yes",width:400,height:300,left:Math.round((screen.width-400)/2),top:Math.round((screen.height-300)/3)},styles:{"#MathJax_About":{position:"fixed",left:"50%",width:"auto","text-align":"center",border:"3px outset",padding:"1em 2em","background-color":"#DDDDDD",color:"black",cursor:"default","font-family":"message-box","font-size":"120%","font-style":"normal","text-indent":0,"text-transform":"none","line-height":"normal","letter-spacing":"normal","word-spacing":"normal","word-wrap":"normal","white-space":"nowrap","float":"none","z-index":201,"border-radius":"15px","-webkit-border-radius":"15px","-moz-border-radius":"15px","-khtml-border-radius":"15px","box-shadow":"0px 10px 20px #808080","-webkit-box-shadow":"0px 10px 20px #808080","-moz-box-shadow":"0px 10px 20px #808080","-khtml-box-shadow":"0px 10px 20px #808080",filter:"progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')"},"#MathJax_About.MathJax_MousePost":{outline:"none"},".MathJax_Menu":{position:"absolute","background-color":"white",color:"black",width:"auto",padding:(a?"2px":"5px 0px"),border:"1px solid #CCCCCC",margin:0,cursor:"default",font:"menu","text-align":"left","text-indent":0,"text-transform":"none","line-height":"normal","letter-spacing":"normal","word-spacing":"normal","word-wrap":"normal","white-space":"nowrap","float":"none","z-index":201,"border-radius":j,"-webkit-border-radius":j,"-moz-border-radius":j,"-khtml-border-radius":j,"box-shadow":"0px 10px 20px #808080","-webkit-box-shadow":"0px 10px 20px #808080","-moz-box-shadow":"0px 10px 20px #808080","-khtml-box-shadow":"0px 10px 20px #808080",filter:"progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')"},".MathJax_MenuItem":{padding:(a?"2px 2em":"1px 2em"),background:"transparent"},".MathJax_MenuArrow":{position:"absolute",right:".5em","padding-top":".25em",color:"#666666","font-family":(l?"'Arial unicode MS'":null),"font-size":".75em"},".MathJax_MenuActive .MathJax_MenuArrow":{color:"white"},".MathJax_MenuArrow.RTL":{left:".5em",right:"auto"},".MathJax_MenuCheck":{position:"absolute",left:".7em","font-family":(l?"'Arial unicode MS'":null)},".MathJax_MenuCheck.RTL":{right:".7em",left:"auto"},".MathJax_MenuRadioCheck":{position:"absolute",left:(a?"1em":".7em")},".MathJax_MenuRadioCheck.RTL":{right:(a?"1em":".7em"),left:"auto"},".MathJax_MenuLabel":{padding:(a?"2px 2em 4px 1.33em":"1px 2em 3px 1.33em"),"font-style":"italic"},".MathJax_MenuRule":{"border-top":(a?"1px solid #CCCCCC":"1px solid #DDDDDD"),margin:(a?"4px 1px 0px":"4px 3px")},".MathJax_MenuDisabled":{color:"GrayText"},".MathJax_MenuActive":{"background-color":(a?"Highlight":"#606872"),color:(a?"HighlightText":"white")},".MathJax_MenuDisabled:focus, .MathJax_MenuLabel:focus":{"background-color":"#E8E8E8"},".MathJax_ContextMenu:focus":{outline:"none"},".MathJax_ContextMenu .MathJax_MenuItem:focus":{outline:"none"},"#MathJax_AboutClose":{top:".2em",right:".2em"},".MathJax_Menu .MathJax_MenuClose":{top:"-10px",left:"-10px"},".MathJax_MenuClose":{position:"absolute",cursor:"pointer",display:"inline-block",border:"2px solid #AAA","border-radius":"18px","-webkit-border-radius":"18px","-moz-border-radius":"18px","-khtml-border-radius":"18px","font-family":"'Courier New',Courier","font-size":"24px",color:"#F0F0F0"},".MathJax_MenuClose span":{display:"block","background-color":"#AAA",border:"1.5px solid","border-radius":"18px","-webkit-border-radius":"18px","-moz-border-radius":"18px","-khtml-border-radius":"18px","line-height":0,padding:"8px 0 6px"},".MathJax_MenuClose:hover":{color:"white!important",border:"2px solid #CCC!important"},".MathJax_MenuClose:hover span":{"background-color":"#CCC!important"},".MathJax_MenuClose:hover:focus":{outline:"none"}}});var n,k,b;f.Register.StartupHook("MathEvents Ready",function(){n=MathJax.Extension.MathEvents.Event.False;k=MathJax.Extension.MathEvents.Hover;b=MathJax.Extension.MathEvents.Event.KEY});var h=MathJax.Object.Subclass({Keydown:function(u,v){switch(u.keyCode){case b.ESCAPE:this.Remove(u,v);break;case b.RIGHT:this.Right(u,v);break;case b.LEFT:this.Left(u,v);break;case b.UP:this.Up(u,v);break;case b.DOWN:this.Down(u,v);break;case b.RETURN:case b.SPACE:this.Space(u,v);break;default:return;break}return n(u)},Escape:function(u,v){},Right:function(u,v){},Left:function(u,v){},Up:function(u,v){},Down:function(u,v){},Space:function(u,v){}},{});var g=MathJax.Menu=h.Subclass({version:p,items:[],posted:false,title:null,margin:5,Init:function(u){this.items=[].slice.call(arguments,0)},With:function(u){if(u){f.Insert(this,u)}return this},Post:function(M,E,B){if(!M){M=window.event||{}}var I=document.getElementById("MathJax_MenuFrame");if(!I){I=g.Background(this);delete c.lastItem;delete c.lastMenu;delete g.skipUp;d.Post(["post",g.jax]);g.isRTL=(MathJax.Localization.fontDirection()==="rtl")}var v=o.Element("div",{onmouseup:g.Mouseup,ondblclick:n,ondragstart:n,onselectstart:n,oncontextmenu:n,menuItem:this,className:"MathJax_Menu",onkeydown:g.Keydown,role:"menu"});if(M.type==="contextmenu"||M.type==="mouseover"){v.className+=" MathJax_ContextMenu"}if(!B){MathJax.Localization.setCSS(v)}for(var N=0,K=this.items.length;NA-this.margin){H=A-v.offsetWidth-this.margin}if(g.isMobile){H=Math.max(5,H-Math.floor(v.offsetWidth/2));F-=20}g.skipUp=M.isContextMenu}else{var z="left",J=E.offsetWidth;H=(g.isMobile?30:J-2);F=0;while(E&&E!==I){H+=E.offsetLeft;F+=E.offsetTop;E=E.parentNode}if(!g.isMobile){if((g.isRTL&&H-J-v.offsetWidth>this.margin)||(!g.isRTL&&H+v.offsetWidth>A-this.margin)){z="right";H=Math.max(this.margin,H-J-v.offsetWidth+6)}}if(!a){v.style["borderRadiusTop"+z]=0;v.style["WebkitBorderRadiusTop"+z]=0;v.style["MozBorderRadiusTop"+z]=0;v.style["KhtmlBorderRadiusTop"+z]=0}}v.style.left=H+"px";v.style.top=F+"px";if(document.selection&&document.selection.empty){document.selection.empty()}var G=window.pageXOffset||document.documentElement.scrollLeft;var D=window.pageYOffset||document.documentElement.scrollTop;g.Focus(v);if(M.type==="keydown"){g.skipMouseoverFromKey=true;setTimeout(function(){delete g.skipMouseoverFromKey},s.delay)}window.scrollTo(G,D);return n(M)},Remove:function(u,v){d.Post(["unpost",g.jax]);var w=document.getElementById("MathJax_MenuFrame");if(w){w.parentNode.removeChild(w);if(this.msieFixedPositionBug){detachEvent("onresize",g.Resize)}}if(g.jax.hover){delete g.jax.hover.nofade;k.UnHover(g.jax)}g.Unfocus(v);if(u.type==="mousedown"){g.CurrentNode().blur()}return n(u)},Find:function(u){return this.FindN(1,u,[].slice.call(arguments,1))},FindId:function(u){return this.FindN(0,u,[].slice.call(arguments,1))},FindN:function(y,v,x){for(var w=0,u=this.items.length;w0){u.oldTabIndex=u.tabIndex}u.tabIndex=-1}},SetTabIndex:function(){var v=g.AllNodes();for(var w=0,u;u=v[w];w++){if(u.oldTabIndex!==undefined){u.tabIndex=u.oldTabIndex;delete u.oldTabIndex}else{u.tabIndex=f.getTabOrder(u)}}},Mod:function(u,v){return((u%v)+v)%v},IndexOf:(Array.prototype.indexOf?function(u,v,w){return u.indexOf(v,w)}:function(u,x,y){for(var w=(y||0),v=u.length;w=0&&c.GetMenuNode(w).menuItem!==v[u].menuItem){v[u].menuItem.posted=false;v[u].parentNode.removeChild(v[u]);u--}},Touchstart:function(u,v){return this.TouchEvent(u,v,"Mousedown")},Touchend:function(u,v){return this.TouchEvent(u,v,"Mouseup")},TouchEvent:function(v,w,u){if(this!==c.lastItem){if(c.lastMenu){g.Event(v,c.lastMenu,"Mouseout")}g.Event(v,w,"Mouseover",true);c.lastItem=this;c.lastMenu=w}if(this.nativeTouch){return null}g.Event(v,w,u);return false},Remove:function(u,v){v=v.parentNode.menuItem;return v.Remove(u,v)},With:function(u){if(u){f.Insert(this,u)}return this},isRTL:function(){return g.isRTL},rtlClass:function(){return(this.isRTL()?" RTL":"")}},{GetMenuNode:function(u){return u.parentNode}});g.ENTRY=g.ITEM.Subclass({role:"menuitem",Attributes:function(u){u=f.Insert({onmouseover:g.Mouseover,onmouseout:g.Mouseout,onmousedown:g.Mousedown,onkeydown:g.Keydown,"aria-disabled":!!this.disabled},u);u=this.SUPER(arguments).Attributes.call(this,u);if(this.disabled){u.className+=" MathJax_MenuDisabled"}return u},MoveVertical:function(u,E,w){var x=c.GetMenuNode(E);var D=[];for(var z=0,C=x.menuItem.items,y;y=C[z];z++){if(!y.hidden){D.push(y)}}var B=g.IndexOf(D,this);if(B===-1){return}var A=D.length;var v=x.childNodes;do{B=g.Mod(w(B),A)}while(D[B].hidden||!v[B].role||v[B].role==="separator");this.Deactivate(E);D[B].Activate(u,v[B])},Up:function(v,u){this.MoveVertical(v,u,function(w){return w-1})},Down:function(v,u){this.MoveVertical(v,u,function(w){return w+1})},Right:function(v,u){this.MoveHorizontal(v,u,g.Right,!this.isRTL())},Left:function(v,u){this.MoveHorizontal(v,u,g.Left,this.isRTL())},MoveHorizontal:function(A,z,u,B){var x=c.GetMenuNode(z);if(x.menuItem===g.menu&&A.shiftKey){u(A,z)}if(B){return}if(x.menuItem!==g.menu){this.Deactivate(z)}var v=x.previousSibling.childNodes;var y=v.length;while(y--){var w=v[y];if(w.menuItem.submenu&&w.menuItem.submenu===x.menuItem){g.Focus(w);break}}this.RemoveSubmenus(z)},Space:function(u,v){this.Mouseup(u,v)},Activate:function(u,v){this.Deactivate(v);if(!this.disabled){v.className+=" MathJax_MenuActive"}this.DeactivateSubmenus(v);g.Focus(v)},Deactivate:function(u){u.className=u.className.replace(/ MathJax_MenuActive/,"")}});g.ITEM.COMMAND=g.ENTRY.Subclass({action:function(){},Init:function(u,w,v){if(!i(u)){u=[u,u]}this.name=u;this.action=w;this.With(v)},Label:function(u,v){return[this.Name()]},Mouseup:function(u,v){if(!this.disabled){this.Remove(u,v);d.Post(["command",this]);this.action.call(this,u)}return n(u)}});g.ITEM.SUBMENU=g.ENTRY.Subclass({submenu:null,marker:"\u25BA",markerRTL:"\u25C4",Attributes:function(u){u=f.Insert({"aria-haspopup":"true"},u);u=this.SUPER(arguments).Attributes.call(this,u);return u},Init:function(u,w){if(!i(u)){u=[u,u]}this.name=u;var v=1;if(!(w instanceof g.ITEM)){this.With(w),v++}this.submenu=g.apply(g,[].slice.call(arguments,v))},Label:function(u,v){this.submenu.posted=false;return[this.Name()+" ",["span",{className:"MathJax_MenuArrow"+this.rtlClass()},[this.isRTL()?this.markerRTL:this.marker]]]},Timer:function(u,v){this.ClearTimer();u={type:u.type,clientX:u.clientX,clientY:u.clientY};this.timer=setTimeout(e(["Mouseup",this,u,v]),s.delay)},ClearTimer:function(){if(this.timer){clearTimeout(this.timer)}},Touchend:function(v,x){var w=this.submenu.posted;var u=this.SUPER(arguments).Touchend.apply(this,arguments);if(w){this.Deactivate(x);delete c.lastItem;delete c.lastMenu}return u},Mouseout:function(u,v){if(!this.submenu.posted){this.Deactivate(v)}this.ClearTimer()},Mouseover:function(u,v){this.Activate(u,v)},Mouseup:function(u,v){if(!this.disabled){if(!this.submenu.posted){this.ClearTimer();this.submenu.Post(u,v,this.ltr);g.Focus(v)}else{this.DeactivateSubmenus(v)}}return n(u)},Activate:function(u,v){if(!this.disabled){this.Deactivate(v);v.className+=" MathJax_MenuActive"}if(!this.submenu.posted){this.DeactivateSubmenus(v);if(!g.isMobile){this.Timer(u,v)}}g.Focus(v)},MoveVertical:function(w,v,u){this.ClearTimer();this.SUPER(arguments).MoveVertical.apply(this,arguments)},MoveHorizontal:function(w,y,v,x){if(!x){this.SUPER(arguments).MoveHorizontal.apply(this,arguments);return}if(this.disabled){return}if(!this.submenu.posted){this.Activate(w,y);return}var u=c.GetMenuNode(y).nextSibling.childNodes;if(u.length>0){this.submenu.items[0].Activate(w,u[0])}}});g.ITEM.RADIO=g.ENTRY.Subclass({variable:null,marker:(a?"\u25CF":"\u2713"),role:"menuitemradio",Attributes:function(v){var u=s.settings[this.variable]===this.value?"true":"false";v=f.Insert({"aria-checked":u},v);v=this.SUPER(arguments).Attributes.call(this,v);return v},Init:function(v,u,w){if(!i(v)){v=[v,v]}this.name=v;this.variable=u;this.With(w);if(this.value==null){this.value=this.name[0]}},Label:function(v,w){var u={className:"MathJax_MenuRadioCheck"+this.rtlClass()};if(s.settings[this.variable]!==this.value){u={style:{display:"none"}}}return[["span",u,[this.marker]]," "+this.Name()]},Mouseup:function(x,y){if(!this.disabled){var z=y.parentNode.childNodes;for(var v=0,u=z.length;v/g,">");var y=t("EqSource","MathJax Equation Source");if(g.isMobile){u.document.open();u.document.write(""+y+" ");u.document.write(""+z+"
");u.document.write("
");u.document.write("");u.document.close()}else{u.document.open();u.document.write(""+y+" ");u.document.write(""+z+"
");u.document.write("");u.document.close();var v=u.document.body.firstChild;setTimeout(function(){var B=(u.outerHeight-u.innerHeight)||30,A=(u.outerWidth-u.innerWidth)||30,w,E;A=Math.max(140,Math.min(Math.floor(0.5*screen.width),v.offsetWidth+A+25));B=Math.max(40,Math.min(Math.floor(0.5*screen.height),v.offsetHeight+B+25));if(g.prototype.msieHeightBug){B+=35}u.resizeTo(A,B);var D;try{D=x.screenX}catch(C){}if(x&&D!=null){w=Math.max(0,Math.min(x.screenX-Math.floor(A/2),screen.width-A-20));E=Math.max(0,Math.min(x.screenY-Math.floor(B/2),screen.height-B-20));u.moveTo(w,E)}},50)}};g.Scale=function(){var z=["CommonHTML","HTML-CSS","SVG","NativeMML","PreviewHTML"],u=z.length,y=100,w,v;for(w=0;w7;g.Augment({margin:20,msieBackgroundBug:((document.documentMode||0)<9),msieFixedPositionBug:(v||!w),msieAboutBug:v,msieHeightBug:((document.documentMode||0)<9)});if(m){delete s.styles["#MathJax_About"].filter;delete s.styles[".MathJax_Menu"].filter}},Firefox:function(u){g.skipMouseover=u.isMobile&&u.versionAtLeast("6.0");g.skipMousedown=u.isMobile}});g.isMobile=f.Browser.isMobile;g.noContextMenu=f.Browser.noContextMenu;g.CreateLocaleMenu=function(){if(!g.menu){return}var z=g.menu.Find("Language").submenu,w=z.items;var v=[],B=MathJax.Localization.strings;for(var A in B){if(B.hasOwnProperty(A)){v.push(A)}}v=v.sort();z.items=[];for(var x=0,u=v.length;x0||this.Get("scriptlevel")>0)&&g>=0){return""}return this.TEXSPACELENGTH[Math.abs(g)]},TEXSPACELENGTH:["",a.LENGTH.THINMATHSPACE,a.LENGTH.MEDIUMMATHSPACE,a.LENGTH.THICKMATHSPACE],TEXSPACE:[[0,-1,2,3,0,0,0,1],[-1,-1,0,3,0,0,0,1],[2,2,0,0,2,0,0,2],[3,3,0,0,3,0,0,3],[0,0,0,0,0,0,0,0],[0,-1,2,3,0,0,0,1],[1,1,0,1,1,1,1,1],[1,-1,2,3,1,0,1,1]],autoDefault:function(e){return""},isSpacelike:function(){return false},isEmbellished:function(){return false},Core:function(){return this},CoreMO:function(){return this},childIndex:function(g){if(g==null){return}for(var f=0,e=this.data.length;f=55296&&e.charCodeAt(0)<56320)?a.VARIANT.ITALIC:a.VARIANT.NORMAL)}return""},setTeXclass:function(f){this.getPrevClass(f);var e=this.data.join("");if(e.length>1&&e.match(/^[a-z][a-z0-9]*$/i)&&this.texClass===a.TEXCLASS.ORD){this.texClass=a.TEXCLASS.OP;this.autoOP=true}return this}});a.mn=a.mbase.Subclass({type:"mn",isToken:true,texClass:a.TEXCLASS.ORD,defaults:{mathvariant:a.INHERIT,mathsize:a.INHERIT,mathbackground:a.INHERIT,mathcolor:a.INHERIT,dir:a.INHERIT}});a.mo=a.mbase.Subclass({type:"mo",isToken:true,defaults:{mathvariant:a.INHERIT,mathsize:a.INHERIT,mathbackground:a.INHERIT,mathcolor:a.INHERIT,dir:a.INHERIT,form:a.AUTO,fence:a.AUTO,separator:a.AUTO,lspace:a.AUTO,rspace:a.AUTO,stretchy:a.AUTO,symmetric:a.AUTO,maxsize:a.AUTO,minsize:a.AUTO,largeop:a.AUTO,movablelimits:a.AUTO,accent:a.AUTO,linebreak:a.LINEBREAK.AUTO,lineleading:a.INHERIT,linebreakstyle:a.AUTO,linebreakmultchar:a.INHERIT,indentalign:a.INHERIT,indentshift:a.INHERIT,indenttarget:a.INHERIT,indentalignfirst:a.INHERIT,indentshiftfirst:a.INHERIT,indentalignlast:a.INHERIT,indentshiftlast:a.INHERIT,texClass:a.AUTO},defaultDef:{form:a.FORM.INFIX,fence:false,separator:false,lspace:a.LENGTH.THICKMATHSPACE,rspace:a.LENGTH.THICKMATHSPACE,stretchy:false,symmetric:false,maxsize:a.SIZE.INFINITY,minsize:"0em",largeop:false,movablelimits:false,accent:false,linebreak:a.LINEBREAK.AUTO,lineleading:"1ex",linebreakstyle:"before",indentalign:a.INDENTALIGN.AUTO,indentshift:"0",indenttarget:"",indentalignfirst:a.INDENTALIGN.INDENTALIGN,indentshiftfirst:a.INDENTSHIFT.INDENTSHIFT,indentalignlast:a.INDENTALIGN.INDENTALIGN,indentshiftlast:a.INDENTSHIFT.INDENTSHIFT,texClass:a.TEXCLASS.REL},SPACE_ATTR:{lspace:1,rspace:2},useMMLspacing:3,hasMMLspacing:function(){if(this.useMMLspacing){return true}return this.form&&(this.OPTABLE[this.form]||{})[this.data.join("")]},autoDefault:function(g,n){var l=this.def;if(!l){if(g==="form"){return this.getForm()}var k=this.data.join("");var f=[this.Get("form"),a.FORM.INFIX,a.FORM.POSTFIX,a.FORM.PREFIX];for(var h=0,e=f.length;h=55296&&k<56320){k=(((k-55296)<<10)+(j.charCodeAt(1)-56320))+65536}for(var g=0,e=this.RANGES.length;g=0;e--){if(this.data[0]&&!this.data[e].isSpacelike()){return this.data[e]}}return null},Core:function(){if(!(this.isEmbellished())||typeof(this.core)==="undefined"){return this}return this.data[this.core]},CoreMO:function(){if(!(this.isEmbellished())||typeof(this.core)==="undefined"){return this}return this.data[this.core].CoreMO()},toString:function(){if(this.inferred){return"["+this.data.join(",")+"]"}return this.SUPER(arguments).toString.call(this)},setTeXclass:function(g){var f,e=this.data.length;if((this.open||this.close)&&(!g||!g.fnOP)){this.getPrevClass(g);g=null;for(f=0;f0){e++}return e},adjustChild_texprimestyle:function(e){if(e==this.den){return true}return this.Get("texprimestyle")},setTeXclass:a.mbase.setSeparateTeXclasses});a.msqrt=a.mbase.Subclass({type:"msqrt",inferRow:true,linebreakContainer:true,texClass:a.TEXCLASS.ORD,setTeXclass:a.mbase.setSeparateTeXclasses,adjustChild_texprimestyle:function(e){return true}});a.mroot=a.mbase.Subclass({type:"mroot",linebreakContainer:true,texClass:a.TEXCLASS.ORD,adjustChild_displaystyle:function(e){if(e===1){return false}return this.Get("displaystyle")},adjustChild_scriptlevel:function(f){var e=this.Get("scriptlevel");if(f===1){e+=2}return e},adjustChild_texprimestyle:function(e){if(e===0){return true}return this.Get("texprimestyle")},setTeXclass:a.mbase.setSeparateTeXclasses});a.mstyle=a.mbase.Subclass({type:"mstyle",isSpacelike:a.mbase.childrenSpacelike,isEmbellished:a.mbase.childEmbellished,Core:a.mbase.childCore,CoreMO:a.mbase.childCoreMO,inferRow:true,defaults:{scriptlevel:a.INHERIT,displaystyle:a.INHERIT,scriptsizemultiplier:Math.sqrt(1/2),scriptminsize:"8pt",mathbackground:a.INHERIT,mathcolor:a.INHERIT,dir:a.INHERIT,infixlinebreakstyle:a.LINEBREAKSTYLE.BEFORE,decimalseparator:"."},adjustChild_scriptlevel:function(g){var f=this.scriptlevel;if(f==null){f=this.Get("scriptlevel")}else{if(String(f).match(/^ *[-+]/)){var e=this.Get("scriptlevel",null,true);f=e+parseInt(f)}}return f},inheritFromMe:true,noInherit:{mpadded:{width:true,height:true,depth:true,lspace:true,voffset:true},mtable:{width:true,height:true,depth:true,align:true}},getRemoved:{fontfamily:"fontFamily",fontweight:"fontWeight",fontstyle:"fontStyle",fontsize:"fontSize"},setTeXclass:a.mbase.setChildTeXclass});a.merror=a.mbase.Subclass({type:"merror",inferRow:true,linebreakContainer:true,texClass:a.TEXCLASS.ORD});a.mpadded=a.mbase.Subclass({type:"mpadded",inferRow:true,isSpacelike:a.mbase.childrenSpacelike,isEmbellished:a.mbase.childEmbellished,Core:a.mbase.childCore,CoreMO:a.mbase.childCoreMO,defaults:{mathbackground:a.INHERIT,mathcolor:a.INHERIT,width:"",height:"",depth:"",lspace:0,voffset:0},setTeXclass:a.mbase.setChildTeXclass});a.mphantom=a.mbase.Subclass({type:"mphantom",texClass:a.TEXCLASS.ORD,inferRow:true,isSpacelike:a.mbase.childrenSpacelike,isEmbellished:a.mbase.childEmbellished,Core:a.mbase.childCore,CoreMO:a.mbase.childCoreMO,setTeXclass:a.mbase.setChildTeXclass});a.mfenced=a.mbase.Subclass({type:"mfenced",defaults:{mathbackground:a.INHERIT,mathcolor:a.INHERIT,open:"(",close:")",separators:","},addFakeNodes:function(){var f=this.getValues("open","close","separators");f.open=f.open.replace(/[ \t\n\r]/g,"");f.close=f.close.replace(/[ \t\n\r]/g,"");f.separators=f.separators.replace(/[ \t\n\r]/g,"");if(f.open!==""){this.SetData("open",a.mo(f.open).With({fence:true,form:a.FORM.PREFIX,texClass:a.TEXCLASS.OPEN}))}if(f.separators!==""){while(f.separators.length0){return false}return this.Get("displaystyle")},adjustChild_scriptlevel:function(f){var e=this.Get("scriptlevel");if(f>0){e++}return e},adjustChild_texprimestyle:function(e){if(e===this.sub){return true}return this.Get("texprimestyle")},setTeXclass:a.mbase.setBaseTeXclasses});a.msub=a.msubsup.Subclass({type:"msub"});a.msup=a.msubsup.Subclass({type:"msup",sub:2,sup:1});a.mmultiscripts=a.msubsup.Subclass({type:"mmultiscripts",adjustChild_texprimestyle:function(e){if(e%2===1){return true}return this.Get("texprimestyle")}});a.mprescripts=a.mbase.Subclass({type:"mprescripts"});a.none=a.mbase.Subclass({type:"none"});a.munderover=a.mbase.Subclass({type:"munderover",base:0,under:1,over:2,sub:1,sup:2,ACCENTS:["","accentunder","accent"],linebreakContainer:true,isEmbellished:a.mbase.childEmbellished,Core:a.mbase.childCore,CoreMO:a.mbase.childCoreMO,defaults:{mathbackground:a.INHERIT,mathcolor:a.INHERIT,accent:a.AUTO,accentunder:a.AUTO,align:a.ALIGN.CENTER,texClass:a.AUTO,subscriptshift:"",superscriptshift:""},autoDefault:function(e){if(e==="texClass"){return(this.isEmbellished()?this.CoreMO().Get(e):a.TEXCLASS.ORD)}if(e==="accent"&&this.data[this.over]){return this.data[this.over].CoreMO().Get("accent")}if(e==="accentunder"&&this.data[this.under]){return this.data[this.under].CoreMO().Get("accent")}return false},adjustChild_displaystyle:function(e){if(e>0){return false}return this.Get("displaystyle")},adjustChild_scriptlevel:function(g){var f=this.Get("scriptlevel");var e=(this.data[this.base]&&!this.Get("displaystyle")&&this.data[this.base].CoreMO().Get("movablelimits"));if(g==this.under&&(e||!this.Get("accentunder"))){f++}if(g==this.over&&(e||!this.Get("accent"))){f++}return f},adjustChild_texprimestyle:function(e){if(e===this.base&&this.data[this.over]){return true}return this.Get("texprimestyle")},setTeXclass:a.mbase.setBaseTeXclasses});a.munder=a.munderover.Subclass({type:"munder"});a.mover=a.munderover.Subclass({type:"mover",over:1,under:2,sup:1,sub:2,ACCENTS:["","accent","accentunder"]});a.mtable=a.mbase.Subclass({type:"mtable",defaults:{mathbackground:a.INHERIT,mathcolor:a.INHERIT,align:a.ALIGN.AXIS,rowalign:a.ALIGN.BASELINE,columnalign:a.ALIGN.CENTER,groupalign:"{left}",alignmentscope:true,columnwidth:a.WIDTH.AUTO,width:a.WIDTH.AUTO,rowspacing:"1ex",columnspacing:".8em",rowlines:a.LINES.NONE,columnlines:a.LINES.NONE,frame:a.LINES.NONE,framespacing:"0.4em 0.5ex",equalrows:false,equalcolumns:false,displaystyle:false,side:a.SIDE.RIGHT,minlabelspacing:"0.8em",texClass:a.TEXCLASS.ORD,useHeight:1},adjustChild_displaystyle:function(){return(this.displaystyle!=null?this.displaystyle:this.defaults.displaystyle)},inheritFromMe:true,noInherit:{mover:{align:true},munder:{align:true},munderover:{align:true},mtable:{align:true,rowalign:true,columnalign:true,groupalign:true,alignmentscope:true,columnwidth:true,width:true,rowspacing:true,columnspacing:true,rowlines:true,columnlines:true,frame:true,framespacing:true,equalrows:true,equalcolumns:true,displaystyle:true,side:true,minlabelspacing:true,texClass:true,useHeight:1}},linebreakContainer:true,Append:function(){for(var f=0,e=arguments.length;f>10)+55296)+String.fromCharCode((e&1023)+56320)}});a.xml=a.mbase.Subclass({type:"xml",Init:function(){this.div=document.createElement("div");return this.SUPER(arguments).Init.apply(this,arguments)},Append:function(){for(var f=0,e=arguments.length;f":d.REL,"?":[1,1,b.CLOSE],"\\":d.ORD,"^":d.ORD11,_:d.ORD11,"|":[2,2,b.ORD,{fence:true,stretchy:true,symmetric:true}],"#":d.ORD,"$":d.ORD,"\u002E":[0,3,b.PUNCT,{separator:true}],"\u02B9":d.ORD,"\u0300":d.ACCENT,"\u0301":d.ACCENT,"\u0303":d.WIDEACCENT,"\u0304":d.ACCENT,"\u0306":d.ACCENT,"\u0307":d.ACCENT,"\u0308":d.ACCENT,"\u030C":d.ACCENT,"\u0332":d.WIDEACCENT,"\u0338":d.REL4,"\u2015":[0,0,b.ORD,{stretchy:true}],"\u2017":[0,0,b.ORD,{stretchy:true}],"\u2020":d.BIN3,"\u2021":d.BIN3,"\u20D7":d.ACCENT,"\u2111":d.ORD,"\u2113":d.ORD,"\u2118":d.ORD,"\u211C":d.ORD,"\u2205":d.ORD,"\u221E":d.ORD,"\u2305":d.BIN3,"\u2306":d.BIN3,"\u2322":d.REL4,"\u2323":d.REL4,"\u2329":d.OPEN,"\u232A":d.CLOSE,"\u23AA":d.ORD,"\u23AF":[0,0,b.ORD,{stretchy:true}],"\u23B0":d.OPEN,"\u23B1":d.CLOSE,"\u2500":d.ORD,"\u25EF":d.BIN3,"\u2660":d.ORD,"\u2661":d.ORD,"\u2662":d.ORD,"\u2663":d.ORD,"\u3008":d.OPEN,"\u3009":d.CLOSE,"\uFE37":d.WIDEACCENT,"\uFE38":d.WIDEACCENT}}},{OPTYPES:d});var c=a.mo.prototype.OPTABLE;c.infix["^"]=d.WIDEREL;c.infix._=d.WIDEREL;c.prefix["\u2223"]=d.OPEN;c.prefix["\u2225"]=d.OPEN;c.postfix["\u2223"]=d.CLOSE;c.postfix["\u2225"]=d.CLOSE})(MathJax.ElementJax.mml);MathJax.ElementJax.mml.loadComplete("jax.js");
+MathJax.Hub.Register.LoadHook("[MathJax]/jax/element/mml/jax.js",function(){var c="2.7.5";var a=MathJax.ElementJax.mml,b=MathJax.Hub.config.menuSettings;a.mbase.Augment({toMathML:function(l){var h=(this.inferred&&this.parent.inferRow);if(l==null){l=""}var f=this.type,e=this.toMathMLattributes();if(f==="mspace"){return l+"<"+f+e+" />"}var k=[],j=(this.isToken?"":l+(h?"":" "));for(var g=0,d=this.data.length;g ")}}}if(this.isToken||this.isChars){return l+"<"+f+e+">"+k.join("")+""+f+">"}if(h){return k.join("\n")}if(k.length===0||(k.length===1&&k[0]==="")){return l+"<"+f+e+" />"}return l+"<"+f+e+">\n"+k.join("\n")+"\n"+l+""+f+">"},toMathMLattributes:function(){var j=(this.type==="mstyle"?a.math.prototype.defaults:this.defaults);var h=(this.attrNames||a.copyAttributeNames),g=a.skipAttributes,l=a.copyAttributes;var e=[];if(this.type==="math"&&(!this.attr||!("xmlns" in this.attr))){e.push('xmlns="http://www.w3.org/1998/Math/MathML"')}if(!this.attrNames){for(var k in j){if(!g[k]&&!l[k]&&j.hasOwnProperty(k)){if(this[k]!=null&&this[k]!==j[k]){if(this.Get(k,null,1)!==this[k]){e.push(k+'="'+this.toMathMLattribute(this[k])+'"')}}}}}for(var f=0,d=h.length;f126||(k<32&&k!==10&&k!==13&&k!==9)){f[g]=""+k.toString(16).toUpperCase()+";"}else{var j={"&":"&","<":"<",">":">",'"':"""}[f[g]];if(j){f[g]=j}}}else{if(g+11);var p=this.type,k=this.toMathMLattributes();var j=[],o=d+(g?" "+(n?" ":""):"")+" ";for(var h=0,f=this.data.length;h ")}}if(j.length===0||(j.length===1&&j[0]==="")){if(!g){return"<"+p+k+" />"}j.push(o+" ")}if(g){if(n){j.unshift(d+" ");j.push(d+" ")}j.unshift(d+" ");var l=e.originalText.replace(/[&<>]/g,function(i){return{">":">","<":"<","&":"&"}[i]});j.push(d+' '+l+" ");j.push(d+" ")}return d+"<"+p+k+">\n"+j.join("\n")+"\n"+d+""+p+">"}});a.msubsup.Augment({toMathML:function(j){var f=this.type;if(this.data[this.sup]==null){f="msub"}if(this.data[this.sub]==null){f="msup"}var e=this.toMathMLattributes();delete this.data[0].inferred;var h=[];for(var g=0,d=this.data.length;g\n"+h.join("\n")+"\n"+j+""+f+">"}});a.munderover.Augment({toMathML:function(k){var f=this.type;var j=this.data[this.base];if(j&&j.isa(a.TeXAtom)&&j.movablelimits&&!j.Get("displaystyle")){type="msubsup";if(this.data[this.under]==null){f="msup"}if(this.data[this.over]==null){f="msub"}}else{if(this.data[this.under]==null){f="mover"}if(this.data[this.over]==null){f="munder"}}var e=this.toMathMLattributes();delete this.data[0].inferred;var h=[];for(var g=0,d=this.data.length;g\n"+h.join("\n")+"\n"+k+""+f+">"}});a.TeXAtom.Augment({toMathML:function(e){var d=this.toMathMLattributes();if(!d&&this.data[0].data.length===1){return e.substr(2)+this.data[0].toMathML(e)}return e+"\n"+this.data[0].toMathML(e+" ")+"\n"+e+" "}});a.chars.Augment({toMathML:function(d){return(d||"")+this.toMathMLquote(this.toString())}});a.entity.Augment({toMathML:function(d){return(d||"")+"&"+this.toMathMLquote(this.data[0])+";"}});a.xml.Augment({toMathML:function(d){return(d||"")+this.toString()}});MathJax.Hub.Register.StartupHook("TeX mathchoice Ready",function(){a.TeXmathchoice.Augment({toMathML:function(d){return this.Core().toMathML(d)}})});MathJax.Hub.Startup.signal.Post("toMathML Ready")});MathJax.Ajax.loadComplete("[MathJax]/extensions/toMathML.js");
+(function(aa){var g;var X=MathJax.Object.Subclass({firstChild:null,lastChild:null,Init:function(){this.childNodes=[]},appendChild:function(ab){if(ab.parent){ab.parent.removeChild(ab)}if(this.lastChild){this.lastChild.nextSibling=ab}if(!this.firstChild){this.firstChild=ab}this.childNodes.push(ab);ab.parent=this;this.lastChild=ab;return ab},removeChild:function(ad){for(var ac=0,ab=this.childNodes.length;ac=ab-1){this.lastChild=ae}this.childNodes[ad]=ae;ae.nextSibling=ac.nextSibling;ac.nextSibling=ac.parent=null;return ac},hasChildNodes:function(ab){return(this.childNodes.length>0)},toString:function(){return"{"+this.childNodes.join("")+"}"}});var x=function(){g=MathJax.ElementJax.mml;var ab=g.mbase.prototype.Init;g.mbase.Augment({firstChild:null,lastChild:null,nodeValue:null,nextSibling:null,Init:function(){var ac=ab.apply(this,arguments)||this;ac.childNodes=ac.data;ac.nodeName=ac.type;return ac},appendChild:function(af){if(af.parent){af.parent.removeChild(af)}var ad=arguments;if(af.isa(X)){ad=af.childNodes;af.data=af.childNodes=[];af.firstChild=af.lastChild=null}for(var ae=0,ac=ad.length;ae=ac-1){this.lastChild=af}this.SetData(ae,af);af.nextSibling=ad.nextSibling;ad.nextSibling=ad.parent=null;return ad},hasChildNodes:function(ac){return(this.childNodes.length>0)},setAttribute:function(ac,ad){this[ac]=ad}})};var Q={};var e={getElementById:true,createElementNS:function(ac,ab){var ad=g[ab]();if(ab==="mo"&&aa.config.useMathMLspacing){ad.useMMLspacing=128}return ad},createTextNode:function(ab){return g.chars(ab).With({nodeValue:ab})},createDocumentFragment:function(){return X()}};var J={appName:"MathJax"};var C="blue";var o=true;var v=true;var d=".";var f=true;var l=(J.appName.slice(0,9)=="Microsoft");function E(ab){if(l){return e.createElement(ab)}else{return e.createElementNS("http://www.w3.org/1999/xhtml",ab)}}var W="http://www.w3.org/1998/Math/MathML";function P(ab){if(l){return e.createElement("m:"+ab)}else{return e.createElementNS(W,ab)}}function O(ab,ad){var ac;if(l){ac=e.createElement("m:"+ab)}else{ac=e.createElementNS(W,ab)}if(ad){ac.appendChild(ad)}return ac}function u(ab,ac){z.push({input:ab,tag:"mo",output:ac,tex:null,ttype:V});B()}function r(ab){z.push(ab);B()}var D=["\uD835\uDC9C","\u212C","\uD835\uDC9E","\uD835\uDC9F","\u2130","\u2131","\uD835\uDCA2","\u210B","\u2110","\uD835\uDCA5","\uD835\uDCA6","\u2112","\u2133","\uD835\uDCA9","\uD835\uDCAA","\uD835\uDCAB","\uD835\uDCAC","\u211B","\uD835\uDCAE","\uD835\uDCAF","\uD835\uDCB0","\uD835\uDCB1","\uD835\uDCB2","\uD835\uDCB3","\uD835\uDCB4","\uD835\uDCB5","\uD835\uDCB6","\uD835\uDCB7","\uD835\uDCB8","\uD835\uDCB9","\u212F","\uD835\uDCBB","\u210A","\uD835\uDCBD","\uD835\uDCBE","\uD835\uDCBF","\uD835\uDCC0","\uD835\uDCC1","\uD835\uDCC2","\uD835\uDCC3","\u2134","\uD835\uDCC5","\uD835\uDCC6","\uD835\uDCC7","\uD835\uDCC8","\uD835\uDCC9","\uD835\uDCCA","\uD835\uDCCB","\uD835\uDCCC","\uD835\uDCCD","\uD835\uDCCE","\uD835\uDCCF"];var H=["\uD835\uDD04","\uD835\uDD05","\u212D","\uD835\uDD07","\uD835\uDD08","\uD835\uDD09","\uD835\uDD0A","\u210C","\u2111","\uD835\uDD0D","\uD835\uDD0E","\uD835\uDD0F","\uD835\uDD10","\uD835\uDD11","\uD835\uDD12","\uD835\uDD13","\uD835\uDD14","\u211C","\uD835\uDD16","\uD835\uDD17","\uD835\uDD18","\uD835\uDD19","\uD835\uDD1A","\uD835\uDD1B","\uD835\uDD1C","\u2128","\uD835\uDD1E","\uD835\uDD1F","\uD835\uDD20","\uD835\uDD21","\uD835\uDD22","\uD835\uDD23","\uD835\uDD24","\uD835\uDD25","\uD835\uDD26","\uD835\uDD27","\uD835\uDD28","\uD835\uDD29","\uD835\uDD2A","\uD835\uDD2B","\uD835\uDD2C","\uD835\uDD2D","\uD835\uDD2E","\uD835\uDD2F","\uD835\uDD30","\uD835\uDD31","\uD835\uDD32","\uD835\uDD33","\uD835\uDD34","\uD835\uDD35","\uD835\uDD36","\uD835\uDD37"];var w=["\uD835\uDD38","\uD835\uDD39","\u2102","\uD835\uDD3B","\uD835\uDD3C","\uD835\uDD3D","\uD835\uDD3E","\u210D","\uD835\uDD40","\uD835\uDD41","\uD835\uDD42","\uD835\uDD43","\uD835\uDD44","\u2115","\uD835\uDD46","\u2119","\u211A","\u211D","\uD835\uDD4A","\uD835\uDD4B","\uD835\uDD4C","\uD835\uDD4D","\uD835\uDD4E","\uD835\uDD4F","\uD835\uDD50","\u2124","\uD835\uDD52","\uD835\uDD53","\uD835\uDD54","\uD835\uDD55","\uD835\uDD56","\uD835\uDD57","\uD835\uDD58","\uD835\uDD59","\uD835\uDD5A","\uD835\uDD5B","\uD835\uDD5C","\uD835\uDD5D","\uD835\uDD5E","\uD835\uDD5F","\uD835\uDD60","\uD835\uDD61","\uD835\uDD62","\uD835\uDD63","\uD835\uDD64","\uD835\uDD65","\uD835\uDD66","\uD835\uDD67","\uD835\uDD68","\uD835\uDD69","\uD835\uDD6A","\uD835\uDD6B"];var c=0,A=1,U=2,i=3,b=4,h=5,a=6,L=7,V=8,m=9,Y=10,K=15;var k={input:'"',tag:"mtext",output:"mbox",tex:null,ttype:Y};var z=[{input:"alpha",tag:"mi",output:"\u03B1",tex:null,ttype:c},{input:"beta",tag:"mi",output:"\u03B2",tex:null,ttype:c},{input:"chi",tag:"mi",output:"\u03C7",tex:null,ttype:c},{input:"delta",tag:"mi",output:"\u03B4",tex:null,ttype:c},{input:"Delta",tag:"mo",output:"\u0394",tex:null,ttype:c},{input:"epsi",tag:"mi",output:"\u03B5",tex:"epsilon",ttype:c},{input:"varepsilon",tag:"mi",output:"\u025B",tex:null,ttype:c},{input:"eta",tag:"mi",output:"\u03B7",tex:null,ttype:c},{input:"gamma",tag:"mi",output:"\u03B3",tex:null,ttype:c},{input:"Gamma",tag:"mo",output:"\u0393",tex:null,ttype:c},{input:"iota",tag:"mi",output:"\u03B9",tex:null,ttype:c},{input:"kappa",tag:"mi",output:"\u03BA",tex:null,ttype:c},{input:"lambda",tag:"mi",output:"\u03BB",tex:null,ttype:c},{input:"Lambda",tag:"mo",output:"\u039B",tex:null,ttype:c},{input:"lamda",tag:"mi",output:"\u03BB",tex:null,ttype:c},{input:"Lamda",tag:"mo",output:"\u039B",tex:null,ttype:c},{input:"mu",tag:"mi",output:"\u03BC",tex:null,ttype:c},{input:"nu",tag:"mi",output:"\u03BD",tex:null,ttype:c},{input:"omega",tag:"mi",output:"\u03C9",tex:null,ttype:c},{input:"Omega",tag:"mo",output:"\u03A9",tex:null,ttype:c},{input:"phi",tag:"mi",output:f?"\u03D5":"\u03C6",tex:null,ttype:c},{input:"varphi",tag:"mi",output:f?"\u03C6":"\u03D5",tex:null,ttype:c},{input:"Phi",tag:"mo",output:"\u03A6",tex:null,ttype:c},{input:"pi",tag:"mi",output:"\u03C0",tex:null,ttype:c},{input:"Pi",tag:"mo",output:"\u03A0",tex:null,ttype:c},{input:"psi",tag:"mi",output:"\u03C8",tex:null,ttype:c},{input:"Psi",tag:"mi",output:"\u03A8",tex:null,ttype:c},{input:"rho",tag:"mi",output:"\u03C1",tex:null,ttype:c},{input:"sigma",tag:"mi",output:"\u03C3",tex:null,ttype:c},{input:"Sigma",tag:"mo",output:"\u03A3",tex:null,ttype:c},{input:"tau",tag:"mi",output:"\u03C4",tex:null,ttype:c},{input:"theta",tag:"mi",output:"\u03B8",tex:null,ttype:c},{input:"vartheta",tag:"mi",output:"\u03D1",tex:null,ttype:c},{input:"Theta",tag:"mo",output:"\u0398",tex:null,ttype:c},{input:"upsilon",tag:"mi",output:"\u03C5",tex:null,ttype:c},{input:"xi",tag:"mi",output:"\u03BE",tex:null,ttype:c},{input:"Xi",tag:"mo",output:"\u039E",tex:null,ttype:c},{input:"zeta",tag:"mi",output:"\u03B6",tex:null,ttype:c},{input:"*",tag:"mo",output:"\u22C5",tex:"cdot",ttype:c},{input:"**",tag:"mo",output:"\u2217",tex:"ast",ttype:c},{input:"***",tag:"mo",output:"\u22C6",tex:"star",ttype:c},{input:"//",tag:"mo",output:"/",tex:null,ttype:c},{input:"\\\\",tag:"mo",output:"\\",tex:"backslash",ttype:c},{input:"setminus",tag:"mo",output:"\\",tex:null,ttype:c},{input:"xx",tag:"mo",output:"\u00D7",tex:"times",ttype:c},{input:"|><",tag:"mo",output:"\u22C9",tex:"ltimes",ttype:c},{input:"><|",tag:"mo",output:"\u22CA",tex:"rtimes",ttype:c},{input:"|><|",tag:"mo",output:"\u22C8",tex:"bowtie",ttype:c},{input:"-:",tag:"mo",output:"\u00F7",tex:"div",ttype:c},{input:"divide",tag:"mo",output:"-:",tex:null,ttype:V},{input:"@",tag:"mo",output:"\u2218",tex:"circ",ttype:c},{input:"o+",tag:"mo",output:"\u2295",tex:"oplus",ttype:c},{input:"ox",tag:"mo",output:"\u2297",tex:"otimes",ttype:c},{input:"o.",tag:"mo",output:"\u2299",tex:"odot",ttype:c},{input:"sum",tag:"mo",output:"\u2211",tex:null,ttype:L},{input:"prod",tag:"mo",output:"\u220F",tex:null,ttype:L},{input:"^^",tag:"mo",output:"\u2227",tex:"wedge",ttype:c},{input:"^^^",tag:"mo",output:"\u22C0",tex:"bigwedge",ttype:L},{input:"vv",tag:"mo",output:"\u2228",tex:"vee",ttype:c},{input:"vvv",tag:"mo",output:"\u22C1",tex:"bigvee",ttype:L},{input:"nn",tag:"mo",output:"\u2229",tex:"cap",ttype:c},{input:"nnn",tag:"mo",output:"\u22C2",tex:"bigcap",ttype:L},{input:"uu",tag:"mo",output:"\u222A",tex:"cup",ttype:c},{input:"uuu",tag:"mo",output:"\u22C3",tex:"bigcup",ttype:L},{input:"!=",tag:"mo",output:"\u2260",tex:"ne",ttype:c},{input:":=",tag:"mo",output:":=",tex:null,ttype:c},{input:"lt",tag:"mo",output:"<",tex:null,ttype:c},{input:"<=",tag:"mo",output:"\u2264",tex:"le",ttype:c},{input:"lt=",tag:"mo",output:"\u2264",tex:"leq",ttype:c},{input:"gt",tag:"mo",output:">",tex:null,ttype:c},{input:">=",tag:"mo",output:"\u2265",tex:"ge",ttype:c},{input:"gt=",tag:"mo",output:"\u2265",tex:"geq",ttype:c},{input:"-<",tag:"mo",output:"\u227A",tex:"prec",ttype:c},{input:"-lt",tag:"mo",output:"\u227A",tex:null,ttype:c},{input:">-",tag:"mo",output:"\u227B",tex:"succ",ttype:c},{input:"-<=",tag:"mo",output:"\u2AAF",tex:"preceq",ttype:c},{input:">-=",tag:"mo",output:"\u2AB0",tex:"succeq",ttype:c},{input:"in",tag:"mo",output:"\u2208",tex:null,ttype:c},{input:"!in",tag:"mo",output:"\u2209",tex:"notin",ttype:c},{input:"sub",tag:"mo",output:"\u2282",tex:"subset",ttype:c},{input:"sup",tag:"mo",output:"\u2283",tex:"supset",ttype:c},{input:"sube",tag:"mo",output:"\u2286",tex:"subseteq",ttype:c},{input:"supe",tag:"mo",output:"\u2287",tex:"supseteq",ttype:c},{input:"-=",tag:"mo",output:"\u2261",tex:"equiv",ttype:c},{input:"~=",tag:"mo",output:"\u2245",tex:"cong",ttype:c},{input:"~~",tag:"mo",output:"\u2248",tex:"approx",ttype:c},{input:"prop",tag:"mo",output:"\u221D",tex:"propto",ttype:c},{input:"and",tag:"mtext",output:"and",tex:null,ttype:a},{input:"or",tag:"mtext",output:"or",tex:null,ttype:a},{input:"not",tag:"mo",output:"\u00AC",tex:"neg",ttype:c},{input:"=>",tag:"mo",output:"\u21D2",tex:"implies",ttype:c},{input:"if",tag:"mo",output:"if",tex:null,ttype:a},{input:"<=>",tag:"mo",output:"\u21D4",tex:"iff",ttype:c},{input:"AA",tag:"mo",output:"\u2200",tex:"forall",ttype:c},{input:"EE",tag:"mo",output:"\u2203",tex:"exists",ttype:c},{input:"_|_",tag:"mo",output:"\u22A5",tex:"bot",ttype:c},{input:"TT",tag:"mo",output:"\u22A4",tex:"top",ttype:c},{input:"|--",tag:"mo",output:"\u22A2",tex:"vdash",ttype:c},{input:"|==",tag:"mo",output:"\u22A8",tex:"models",ttype:c},{input:"(",tag:"mo",output:"(",tex:"left(",ttype:b},{input:")",tag:"mo",output:")",tex:"right)",ttype:h},{input:"[",tag:"mo",output:"[",tex:"left[",ttype:b},{input:"]",tag:"mo",output:"]",tex:"right]",ttype:h},{input:"{",tag:"mo",output:"{",tex:null,ttype:b},{input:"}",tag:"mo",output:"}",tex:null,ttype:h},{input:"|",tag:"mo",output:"|",tex:null,ttype:m},{input:":|:",tag:"mo",output:"|",tex:null,ttype:c},{input:"|:",tag:"mo",output:"|",tex:null,ttype:b},{input:":|",tag:"mo",output:"|",tex:null,ttype:h},{input:"(:",tag:"mo",output:"\u2329",tex:"langle",ttype:b},{input:":)",tag:"mo",output:"\u232A",tex:"rangle",ttype:h},{input:"<<",tag:"mo",output:"\u2329",tex:null,ttype:b},{input:">>",tag:"mo",output:"\u232A",tex:null,ttype:h},{input:"{:",tag:"mo",output:"{:",tex:null,ttype:b,invisible:true},{input:":}",tag:"mo",output:":}",tex:null,ttype:h,invisible:true},{input:"int",tag:"mo",output:"\u222B",tex:null,ttype:c},{input:"dx",tag:"mi",output:"{:d x:}",tex:null,ttype:V},{input:"dy",tag:"mi",output:"{:d y:}",tex:null,ttype:V},{input:"dz",tag:"mi",output:"{:d z:}",tex:null,ttype:V},{input:"dt",tag:"mi",output:"{:d t:}",tex:null,ttype:V},{input:"oint",tag:"mo",output:"\u222E",tex:null,ttype:c},{input:"del",tag:"mo",output:"\u2202",tex:"partial",ttype:c},{input:"grad",tag:"mo",output:"\u2207",tex:"nabla",ttype:c},{input:"+-",tag:"mo",output:"\u00B1",tex:"pm",ttype:c},{input:"O/",tag:"mo",output:"\u2205",tex:"emptyset",ttype:c},{input:"oo",tag:"mo",output:"\u221E",tex:"infty",ttype:c},{input:"aleph",tag:"mo",output:"\u2135",tex:null,ttype:c},{input:"...",tag:"mo",output:"...",tex:"ldots",ttype:c},{input:":.",tag:"mo",output:"\u2234",tex:"therefore",ttype:c},{input:":'",tag:"mo",output:"\u2235",tex:"because",ttype:c},{input:"/_",tag:"mo",output:"\u2220",tex:"angle",ttype:c},{input:"/_\\",tag:"mo",output:"\u25B3",tex:"triangle",ttype:c},{input:"'",tag:"mo",output:"\u2032",tex:"prime",ttype:c},{input:"tilde",tag:"mover",output:"~",tex:null,ttype:A,acc:true},{input:"\\ ",tag:"mo",output:"\u00A0",tex:null,ttype:c},{input:"frown",tag:"mo",output:"\u2322",tex:null,ttype:c},{input:"quad",tag:"mo",output:"\u00A0\u00A0",tex:null,ttype:c},{input:"qquad",tag:"mo",output:"\u00A0\u00A0\u00A0\u00A0",tex:null,ttype:c},{input:"cdots",tag:"mo",output:"\u22EF",tex:null,ttype:c},{input:"vdots",tag:"mo",output:"\u22EE",tex:null,ttype:c},{input:"ddots",tag:"mo",output:"\u22F1",tex:null,ttype:c},{input:"diamond",tag:"mo",output:"\u22C4",tex:null,ttype:c},{input:"square",tag:"mo",output:"\u25A1",tex:null,ttype:c},{input:"|__",tag:"mo",output:"\u230A",tex:"lfloor",ttype:c},{input:"__|",tag:"mo",output:"\u230B",tex:"rfloor",ttype:c},{input:"|~",tag:"mo",output:"\u2308",tex:"lceiling",ttype:c},{input:"~|",tag:"mo",output:"\u2309",tex:"rceiling",ttype:c},{input:"CC",tag:"mo",output:"\u2102",tex:null,ttype:c},{input:"NN",tag:"mo",output:"\u2115",tex:null,ttype:c},{input:"QQ",tag:"mo",output:"\u211A",tex:null,ttype:c},{input:"RR",tag:"mo",output:"\u211D",tex:null,ttype:c},{input:"ZZ",tag:"mo",output:"\u2124",tex:null,ttype:c},{input:"f",tag:"mi",output:"f",tex:null,ttype:A,func:true},{input:"g",tag:"mi",output:"g",tex:null,ttype:A,func:true},{input:"lim",tag:"mo",output:"lim",tex:null,ttype:L},{input:"Lim",tag:"mo",output:"Lim",tex:null,ttype:L},{input:"sin",tag:"mo",output:"sin",tex:null,ttype:A,func:true},{input:"cos",tag:"mo",output:"cos",tex:null,ttype:A,func:true},{input:"tan",tag:"mo",output:"tan",tex:null,ttype:A,func:true},{input:"sinh",tag:"mo",output:"sinh",tex:null,ttype:A,func:true},{input:"cosh",tag:"mo",output:"cosh",tex:null,ttype:A,func:true},{input:"tanh",tag:"mo",output:"tanh",tex:null,ttype:A,func:true},{input:"cot",tag:"mo",output:"cot",tex:null,ttype:A,func:true},{input:"sec",tag:"mo",output:"sec",tex:null,ttype:A,func:true},{input:"csc",tag:"mo",output:"csc",tex:null,ttype:A,func:true},{input:"arcsin",tag:"mo",output:"arcsin",tex:null,ttype:A,func:true},{input:"arccos",tag:"mo",output:"arccos",tex:null,ttype:A,func:true},{input:"arctan",tag:"mo",output:"arctan",tex:null,ttype:A,func:true},{input:"coth",tag:"mo",output:"coth",tex:null,ttype:A,func:true},{input:"sech",tag:"mo",output:"sech",tex:null,ttype:A,func:true},{input:"csch",tag:"mo",output:"csch",tex:null,ttype:A,func:true},{input:"exp",tag:"mo",output:"exp",tex:null,ttype:A,func:true},{input:"abs",tag:"mo",output:"abs",tex:null,ttype:A,rewriteleftright:["|","|"]},{input:"norm",tag:"mo",output:"norm",tex:null,ttype:A,rewriteleftright:["\u2225","\u2225"]},{input:"floor",tag:"mo",output:"floor",tex:null,ttype:A,rewriteleftright:["\u230A","\u230B"]},{input:"ceil",tag:"mo",output:"ceil",tex:null,ttype:A,rewriteleftright:["\u2308","\u2309"]},{input:"log",tag:"mo",output:"log",tex:null,ttype:A,func:true},{input:"ln",tag:"mo",output:"ln",tex:null,ttype:A,func:true},{input:"det",tag:"mo",output:"det",tex:null,ttype:A,func:true},{input:"dim",tag:"mo",output:"dim",tex:null,ttype:c},{input:"mod",tag:"mo",output:"mod",tex:null,ttype:c},{input:"gcd",tag:"mo",output:"gcd",tex:null,ttype:A,func:true},{input:"lcm",tag:"mo",output:"lcm",tex:null,ttype:A,func:true},{input:"lub",tag:"mo",output:"lub",tex:null,ttype:c},{input:"glb",tag:"mo",output:"glb",tex:null,ttype:c},{input:"min",tag:"mo",output:"min",tex:null,ttype:L},{input:"max",tag:"mo",output:"max",tex:null,ttype:L},{input:"Sin",tag:"mo",output:"Sin",tex:null,ttype:A,func:true},{input:"Cos",tag:"mo",output:"Cos",tex:null,ttype:A,func:true},{input:"Tan",tag:"mo",output:"Tan",tex:null,ttype:A,func:true},{input:"Arcsin",tag:"mo",output:"Arcsin",tex:null,ttype:A,func:true},{input:"Arccos",tag:"mo",output:"Arccos",tex:null,ttype:A,func:true},{input:"Arctan",tag:"mo",output:"Arctan",tex:null,ttype:A,func:true},{input:"Sinh",tag:"mo",output:"Sinh",tex:null,ttype:A,func:true},{input:"Cosh",tag:"mo",output:"Cosh",tex:null,ttype:A,func:true},{input:"Tanh",tag:"mo",output:"Tanh",tex:null,ttype:A,func:true},{input:"Cot",tag:"mo",output:"Cot",tex:null,ttype:A,func:true},{input:"Sec",tag:"mo",output:"Sec",tex:null,ttype:A,func:true},{input:"Csc",tag:"mo",output:"Csc",tex:null,ttype:A,func:true},{input:"Log",tag:"mo",output:"Log",tex:null,ttype:A,func:true},{input:"Ln",tag:"mo",output:"Ln",tex:null,ttype:A,func:true},{input:"Abs",tag:"mo",output:"abs",tex:null,ttype:A,notexcopy:true,rewriteleftright:["|","|"]},{input:"uarr",tag:"mo",output:"\u2191",tex:"uparrow",ttype:c},{input:"darr",tag:"mo",output:"\u2193",tex:"downarrow",ttype:c},{input:"rarr",tag:"mo",output:"\u2192",tex:"rightarrow",ttype:c},{input:"->",tag:"mo",output:"\u2192",tex:"to",ttype:c},{input:">->",tag:"mo",output:"\u21A3",tex:"rightarrowtail",ttype:c},{input:"->>",tag:"mo",output:"\u21A0",tex:"twoheadrightarrow",ttype:c},{input:">->>",tag:"mo",output:"\u2916",tex:"twoheadrightarrowtail",ttype:c},{input:"|->",tag:"mo",output:"\u21A6",tex:"mapsto",ttype:c},{input:"larr",tag:"mo",output:"\u2190",tex:"leftarrow",ttype:c},{input:"harr",tag:"mo",output:"\u2194",tex:"leftrightarrow",ttype:c},{input:"rArr",tag:"mo",output:"\u21D2",tex:"Rightarrow",ttype:c},{input:"lArr",tag:"mo",output:"\u21D0",tex:"Leftarrow",ttype:c},{input:"hArr",tag:"mo",output:"\u21D4",tex:"Leftrightarrow",ttype:c},{input:"sqrt",tag:"msqrt",output:"sqrt",tex:null,ttype:A},{input:"root",tag:"mroot",output:"root",tex:null,ttype:U},{input:"frac",tag:"mfrac",output:"/",tex:null,ttype:U},{input:"/",tag:"mfrac",output:"/",tex:null,ttype:i},{input:"stackrel",tag:"mover",output:"stackrel",tex:null,ttype:U},{input:"overset",tag:"mover",output:"stackrel",tex:null,ttype:U},{input:"underset",tag:"munder",output:"stackrel",tex:null,ttype:U},{input:"_",tag:"msub",output:"_",tex:null,ttype:i},{input:"^",tag:"msup",output:"^",tex:null,ttype:i},{input:"hat",tag:"mover",output:"\u005E",tex:null,ttype:A,acc:true},{input:"bar",tag:"mover",output:"\u00AF",tex:"overline",ttype:A,acc:true},{input:"vec",tag:"mover",output:"\u2192",tex:null,ttype:A,acc:true},{input:"dot",tag:"mover",output:".",tex:null,ttype:A,acc:true},{input:"ddot",tag:"mover",output:"..",tex:null,ttype:A,acc:true},{input:"overarc",tag:"mover",output:"\u23DC",tex:"overparen",ttype:A,acc:true},{input:"ul",tag:"munder",output:"\u0332",tex:"underline",ttype:A,acc:true},{input:"ubrace",tag:"munder",output:"\u23DF",tex:"underbrace",ttype:K,acc:true},{input:"obrace",tag:"mover",output:"\u23DE",tex:"overbrace",ttype:K,acc:true},{input:"text",tag:"mtext",output:"text",tex:null,ttype:Y},{input:"mbox",tag:"mtext",output:"mbox",tex:null,ttype:Y},{input:"color",tag:"mstyle",ttype:U},{input:"id",tag:"mrow",ttype:U},{input:"class",tag:"mrow",ttype:U},{input:"cancel",tag:"menclose",output:"cancel",tex:null,ttype:A},k,{input:"bb",tag:"mstyle",atname:"mathvariant",atval:"bold",output:"bb",tex:null,ttype:A},{input:"mathbf",tag:"mstyle",atname:"mathvariant",atval:"bold",output:"mathbf",tex:null,ttype:A},{input:"sf",tag:"mstyle",atname:"mathvariant",atval:"sans-serif",output:"sf",tex:null,ttype:A},{input:"mathsf",tag:"mstyle",atname:"mathvariant",atval:"sans-serif",output:"mathsf",tex:null,ttype:A},{input:"bbb",tag:"mstyle",atname:"mathvariant",atval:"double-struck",output:"bbb",tex:null,ttype:A,codes:w},{input:"mathbb",tag:"mstyle",atname:"mathvariant",atval:"double-struck",output:"mathbb",tex:null,ttype:A,codes:w},{input:"cc",tag:"mstyle",atname:"mathvariant",atval:"script",output:"cc",tex:null,ttype:A,codes:D},{input:"mathcal",tag:"mstyle",atname:"mathvariant",atval:"script",output:"mathcal",tex:null,ttype:A,codes:D},{input:"tt",tag:"mstyle",atname:"mathvariant",atval:"monospace",output:"tt",tex:null,ttype:A},{input:"mathtt",tag:"mstyle",atname:"mathvariant",atval:"monospace",output:"mathtt",tex:null,ttype:A},{input:"fr",tag:"mstyle",atname:"mathvariant",atval:"fraktur",output:"fr",tex:null,ttype:A,codes:H},{input:"mathfrak",tag:"mstyle",atname:"mathvariant",atval:"fraktur",output:"mathfrak",tex:null,ttype:A,codes:H}];function T(ac,ab){if(ac.input>ab.input){return 1}else{return -1}}var S=[];function n(){var ac;var ab=z.length;for(ac=0;ac>1;if(ac[ab]=S[ab]}s=y;if(af!=""){y=z[ae].ttype;return z[ae]}y=c;ab=1;ak=ah.slice(0,1);var ai=true;while("0"<=ak&&ak<="9"&&ab<=ah.length){ak=ah.slice(ab,ab+1);ab++}if(ak==d){ak=ah.slice(ab,ab+1);if("0"<=ak&&ak<="9"){ai=false;ab++;while("0"<=ak&&ak<="9"&&ab<=ah.length){ak=ah.slice(ab,ab+1);ab++}}}if((ai&&ab>1)||ab>2){ak=ah.slice(0,ab-1);aj="mn"}else{ab=2;ak=ah.slice(0,1);aj=(("A">ak||ak>"Z")&&("a">ak||ak>"z")?"mo":"mi")}if(ak=="-"&&s==i){y=i;return{input:ak,tag:aj,output:ak,ttype:A,func:true}}return{input:ak,tag:aj,output:ak,ttype:c}}function R(ac){var ab;if(!ac.hasChildNodes()){return}if(ac.firstChild.hasChildNodes()&&(ac.nodeName=="mrow"||ac.nodeName=="M:MROW")){ab=ac.firstChild.firstChild.nodeValue;if(ab=="("||ab=="["||ab=="{"){ac.removeChild(ac.firstChild)}}if(ac.lastChild.hasChildNodes()&&(ac.nodeName=="mrow"||ac.nodeName=="M:MROW")){ab=ac.lastChild.firstChild.nodeValue;if(ab==")"||ab=="]"||ab=="}"){ac.removeChild(ac.lastChild)}}}var F,s,y;function G(ai){var ad,ac,al,af,ak,ag=e.createDocumentFragment();ai=p(ai,0);ad=j(ai);if(ad==null||ad.ttype==h&&F>0){return[null,ai]}if(ad.ttype==V){ai=ad.output+p(ai,ad.input.length);ad=j(ai)}switch(ad.ttype){case L:case c:ai=p(ai,ad.input.length);return[O(ad.tag,e.createTextNode(ad.output)),ai];case b:F++;ai=p(ai,ad.input.length);al=q(ai,true);F--;if(typeof ad.invisible=="boolean"&&ad.invisible){ac=O("mrow",al[0])}else{ac=O("mo",e.createTextNode(ad.output));ac=O("mrow",ac);ac.appendChild(al[0])}return[ac,al[1]];case Y:if(ad!=k){ai=p(ai,ad.input.length)}if(ai.charAt(0)=="{"){af=ai.indexOf("}")}else{if(ai.charAt(0)=="("){af=ai.indexOf(")")}else{if(ai.charAt(0)=="["){af=ai.indexOf("]")}else{if(ad==k){af=ai.slice(1).indexOf('"')+1}else{af=0}}}}if(af==-1){af=ai.length}ak=ai.slice(1,af);if(ak.charAt(0)==" "){ac=O("mspace");ac.setAttribute("width","1ex");ag.appendChild(ac)}ag.appendChild(O(ad.tag,e.createTextNode(ak)));if(ak.charAt(ak.length-1)==" "){ac=O("mspace");ac.setAttribute("width","1ex");ag.appendChild(ac)}ai=p(ai,af+1);return[O("mrow",ag),ai];case K:case A:ai=p(ai,ad.input.length);al=G(ai);if(al[0]==null){return[O(ad.tag,e.createTextNode(ad.output)),ai]}if(typeof ad.func=="boolean"&&ad.func){ak=ai.charAt(0);if(ak=="^"||ak=="_"||ak=="/"||ak=="|"||ak==","||(ad.input.length==1&&ad.input.match(/\w/)&&ak!="(")){return[O(ad.tag,e.createTextNode(ad.output)),ai]}else{ac=O("mrow",O(ad.tag,e.createTextNode(ad.output)));ac.appendChild(al[0]);return[ac,al[1]]}}R(al[0]);if(ad.input=="sqrt"){return[O(ad.tag,al[0]),al[1]]}else{if(typeof ad.rewriteleftright!="undefined"){ac=O("mrow",O("mo",e.createTextNode(ad.rewriteleftright[0])));ac.appendChild(al[0]);ac.appendChild(O("mo",e.createTextNode(ad.rewriteleftright[1])));return[ac,al[1]]}else{if(ad.input=="cancel"){ac=O(ad.tag,al[0]);ac.setAttribute("notation","updiagonalstrike");return[ac,al[1]]}else{if(typeof ad.acc=="boolean"&&ad.acc){ac=O(ad.tag,al[0]);var ah=O("mo",e.createTextNode(ad.output));if(ad.input=="vec"&&((al[0].nodeName=="mrow"&&al[0].childNodes.length==1&&al[0].firstChild.firstChild.nodeValue!==null&&al[0].firstChild.firstChild.nodeValue.length==1)||(al[0].firstChild.nodeValue!==null&&al[0].firstChild.nodeValue.length==1))){ah.setAttribute("stretchy",false)}ac.appendChild(ah);return[ac,al[1]]}else{if(!l&&typeof ad.codes!="undefined"){for(af=0;af64&&ak.charCodeAt(ae)<91){aj=aj+ad.codes[ak.charCodeAt(ae)-65]}else{if(ak.charCodeAt(ae)>96&&ak.charCodeAt(ae)<123){aj=aj+ad.codes[ak.charCodeAt(ae)-71]}else{aj=aj+ak.charAt(ae)}}}if(al[0].nodeName=="mi"){al[0]=O("mo").appendChild(e.createTextNode(aj))}else{al[0].replaceChild(O("mo").appendChild(e.createTextNode(aj)),al[0].childNodes[af])}}}}ac=O(ad.tag,al[0]);ac.setAttribute(ad.atname,ad.atval);return[ac,al[1]]}}}}case U:ai=p(ai,ad.input.length);al=G(ai);if(al[0]==null){return[O("mo",e.createTextNode(ad.input)),ai]}R(al[0]);var ab=G(al[1]);if(ab[0]==null){return[O("mo",e.createTextNode(ad.input)),ai]}R(ab[0]);if(["color","class","id"].indexOf(ad.input)>=0){if(ai.charAt(0)=="{"){af=ai.indexOf("}")}else{if(ai.charAt(0)=="("){af=ai.indexOf(")")}else{if(ai.charAt(0)=="["){af=ai.indexOf("]")}}}ak=ai.slice(1,af);ac=O(ad.tag,ab[0]);if(ad.input==="color"){ac.setAttribute("mathcolor",ak)}else{if(ad.input==="class"){ac.setAttribute("class",ak)}else{if(ad.input==="id"){ac.setAttribute("id",ak)}}}return[ac,ab[1]]}if(ad.input=="root"||ad.output=="stackrel"){ag.appendChild(ab[0])}ag.appendChild(al[0]);if(ad.input=="frac"){ag.appendChild(ab[0])}return[O(ad.tag,ag),ab[1]];case i:ai=p(ai,ad.input.length);return[O("mo",e.createTextNode(ad.output)),ai];case a:ai=p(ai,ad.input.length);ac=O("mspace");ac.setAttribute("width","1ex");ag.appendChild(ac);ag.appendChild(O(ad.tag,e.createTextNode(ad.output)));ac=O("mspace");ac.setAttribute("width","1ex");ag.appendChild(ac);return[O("mrow",ag),ai];case m:F++;ai=p(ai,ad.input.length);al=q(ai,false);F--;ak="";if(al[0].lastChild!=null){ak=al[0].lastChild.firstChild.nodeValue}if(ak=="|"&&ai.charAt(0)!==","){ac=O("mo",e.createTextNode(ad.output));ac=O("mrow",ac);ac.appendChild(al[0]);return[ac,al[1]]}else{ac=O("mo",e.createTextNode("\u2223"));ac=O("mrow",ac);return[ac,ai]}default:ai=p(ai,ad.input.length);return[O(ad.tag,e.createTextNode(ad.output)),ai]}}function t(ah){var af,ai,ag,ae,ab,ad;ah=p(ah,0);ai=j(ah);ab=G(ah);ae=ab[0];ah=ab[1];af=j(ah);if(af.ttype==i&&af.input!="/"){ah=p(ah,af.input.length);ab=G(ah);if(ab[0]==null){ab[0]=O("mo",e.createTextNode("\u25A1"))}else{R(ab[0])}ah=ab[1];ad=(ai.ttype==L||ai.ttype==K);if(af.input=="_"){ag=j(ah);if(ag.input=="^"){ah=p(ah,ag.input.length);var ac=G(ah);R(ac[0]);ah=ac[1];ae=O((ad?"munderover":"msubsup"),ae);ae.appendChild(ab[0]);ae.appendChild(ac[0]);ae=O("mrow",ae)}else{ae=O((ad?"munder":"msub"),ae);ae.appendChild(ab[0])}}else{if(af.input=="^"&&ad){ae=O("mover",ae);ae.appendChild(ab[0])}else{ae=O(af.tag,ae);ae.appendChild(ab[0])}}if(typeof ai.func!="undefined"&&ai.func){ag=j(ah);if(ag.ttype!=i&&ag.ttype!=h){ab=t(ah);ae=O("mrow",ae);ae.appendChild(ab[0]);ah=ab[1]}}}return[ae,ah]}function q(ak,aj){var ao,al,ag,ar,ah=e.createDocumentFragment();do{ak=p(ak,0);ag=t(ak);al=ag[0];ak=ag[1];ao=j(ak);if(ao.ttype==i&&ao.input=="/"){ak=p(ak,ao.input.length);ag=t(ak);if(ag[0]==null){ag[0]=O("mo",e.createTextNode("\u25A1"))}else{R(ag[0])}ak=ag[1];R(al);al=O(ao.tag,al);al.appendChild(ag[0]);ah.appendChild(al);ao=j(ak)}else{if(al!=undefined){ah.appendChild(al)}}}while((ao.ttype!=h&&(ao.ttype!=m||aj)||F==0)&&ao!=null&&ao.output!="");if(ao.ttype==h||ao.ttype==m){var at=ah.childNodes.length;if(at>0&&ah.childNodes[at-1].nodeName=="mrow"&&ah.childNodes[at-1].lastChild&&ah.childNodes[at-1].lastChild.firstChild){var av=ah.childNodes[at-1].lastChild.firstChild.nodeValue;if(av==")"||av=="]"){var ac=ah.childNodes[at-1].firstChild.firstChild.nodeValue;if(ac=="("&&av==")"&&ao.output!="}"||ac=="["&&av=="]"){var ad=[];var ap=true;var am=ah.childNodes.length;for(ar=0;ap&&ar1){ap=ad[ar].length==ad[ar-2].length}}ap=ap&&(ad.length>1||ad[0].length>0);var af=[];if(ap){var ae,ab,ai,an,au=e.createDocumentFragment();for(ar=0;ar2){ah.removeChild(ah.firstChild);ah.removeChild(ah.firstChild)}au.appendChild(O("mtr",ae))}al=O("mtable",au);al.setAttribute("columnlines",af.join(" "));if(typeof ao.invisible=="boolean"&&ao.invisible){al.setAttribute("columnalign","left")}ah.replaceChild(al,ah.firstChild)}}}}ak=p(ak,ao.input.length);if(typeof ao.invisible!="boolean"||!ao.invisible){al=O("mo",e.createTextNode(ao.output));ah.appendChild(al)}}return[ah,ak]}function M(ad,ac){var ae,ab;F=0;ad=ad.replace(/ /g,"");ad=ad.replace(/>/g,">");ad=ad.replace(/</g,"<");ae=q(ad.replace(/^\s+/g,""),false)[0];ab=O("mstyle",ae);if(C!=""){ab.setAttribute("mathcolor",C)}if(mathfontsize!=""){ab.setAttribute("fontsize",mathfontsize);ab.setAttribute("mathsize",mathfontsize)}if(mathfontfamily!=""){ab.setAttribute("fontfamily",mathfontfamily);ab.setAttribute("mathvariant",mathfontfamily)}if(o){ab.setAttribute("displaystyle","true")}ab=O("math",ab);if(v){ab.setAttribute("title",ad.replace(/\s+/g," "))}return ab}v=false;mathfontfamily="";C="";mathfontsize="";(function(){for(var ac=0,ab=z.length;ac *":{position:"absolute"},".MJXc-bevelled > *":{display:"inline-block"},".mjx-stack":{display:"inline-block"},".mjx-op":{display:"block"},".mjx-under":{display:"table-cell"},".mjx-over":{display:"block"},".mjx-over > *":{"padding-left":"0px!important","padding-right":"0px!important"},".mjx-under > *":{"padding-left":"0px!important","padding-right":"0px!important"},".mjx-stack > .mjx-sup":{display:"block"},".mjx-stack > .mjx-sub":{display:"block"},".mjx-prestack > .mjx-presup":{display:"block"},".mjx-prestack > .mjx-presub":{display:"block"},".mjx-delim-h > .mjx-char":{display:"inline-block"},".mjx-surd":{"vertical-align":"top"},".mjx-mphantom *":{visibility:"hidden"},".mjx-merror":{"background-color":"#FFFF88",color:"#CC0000",border:"1px solid #CC0000",padding:"2px 3px","font-style":"normal","font-size":"90%"},".mjx-annotation-xml":{"line-height":"normal"},".mjx-menclose > svg":{fill:"none",stroke:"currentColor"},".mjx-mtr":{display:"table-row"},".mjx-mlabeledtr":{display:"table-row"},".mjx-mtd":{display:"table-cell","text-align":"center"},".mjx-label":{display:"table-row"},".mjx-box":{display:"inline-block"},".mjx-block":{display:"block"},".mjx-span":{display:"inline"},".mjx-char":{display:"block","white-space":"pre"},".mjx-itable":{display:"inline-table",width:"auto"},".mjx-row":{display:"table-row"},".mjx-cell":{display:"table-cell"},".mjx-table":{display:"table",width:"100%"},".mjx-line":{display:"block",height:0},".mjx-strut":{width:0,"padding-top":k+"em"},".mjx-vsize":{width:0},".MJXc-space1":{"margin-left":".167em"},".MJXc-space2":{"margin-left":".222em"},".MJXc-space3":{"margin-left":".278em"},".mjx-chartest":{display:"block",visibility:"hidden",position:"absolute",top:0,"line-height":"normal","font-size":"500%"},".mjx-chartest .mjx-char":{display:"inline"},".mjx-chartest .mjx-box":{"padding-top":"1000px"},".MJXc-processing":{visibility:"hidden",position:"fixed",width:0,height:0,overflow:"hidden"},".MJXc-processed":{display:"none"},".mjx-test":{"font-style":"normal","font-weight":"normal","font-size":"100%","font-size-adjust":"none","text-indent":0,"text-transform":"none","letter-spacing":"normal","word-spacing":"normal",overflow:"hidden",height:"1px"},".mjx-test.mjx-test-display":{display:"table!important"},".mjx-test.mjx-test-inline":{display:"inline!important","margin-right":"-1px"},".mjx-test.mjx-test-default":{display:"block!important",clear:"both"},".mjx-ex-box":{display:"inline-block!important",position:"absolute",overflow:"hidden","min-height":0,"max-height":"none",padding:0,border:0,margin:0,width:"1px",height:"60ex"},".mjx-test-inline .mjx-left-box":{display:"inline-block",width:0,"float":"left"},".mjx-test-inline .mjx-right-box":{display:"inline-block",width:0,"float":"right"},".mjx-test-display .mjx-right-box":{display:"table-cell!important",width:"10000em!important","min-width":0,"max-width":"none",padding:0,border:0,margin:0},"#MathJax_CHTML_Tooltip":{"background-color":"InfoBackground",color:"InfoText",border:"1px solid black","box-shadow":"2px 2px 5px #AAAAAA","-webkit-box-shadow":"2px 2px 5px #AAAAAA","-moz-box-shadow":"2px 2px 5px #AAAAAA","-khtml-box-shadow":"2px 2px 5px #AAAAAA",padding:"3px 4px","z-index":401,position:"absolute",left:0,top:0,width:"auto",height:"auto",display:"none"}};var i=1000000;var n=5;var c={},r=MathJax.Hub.config;a.Augment({settings:f.config.menuSettings,config:{styles:p},Config:function(){if(!this.require){this.require=[]}this.SUPER(arguments).Config.call(this);var s=this.settings;if(s.scale){this.config.scale=s.scale}this.require.push(this.fontDir+"/TeX/fontdata.js");this.require.push(MathJax.OutputJax.extensionDir+"/MathEvents.js");c=this.config.linebreaks},Startup:function(){e=MathJax.Extension.MathEvents.Event;q=MathJax.Extension.MathEvents.Touch;h=MathJax.Extension.MathEvents.Hover;this.ContextMenu=e.ContextMenu;this.Mousedown=e.AltContextMenu;this.Mouseover=h.Mouseover;this.Mouseout=h.Mouseout;this.Mousemove=h.Mousemove;var s=a.addElement(document.body,"mjx-block",{style:{display:"block",width:"5in"}});this.pxPerInch=s.offsetWidth/5;s.parentNode.removeChild(s);this.TestSpan=a.Element("mjx-test",{style:{left:"1em"}},[["mjx-left-box"],["mjx-ex-box"],["mjx-right-box"]]);return o.Styles(this.config.styles,["InitializeCHTML",this])},InitializeCHTML:function(){this.getDefaultExEm();if(this.defaultEm){return}var s=MathJax.Callback();o.timer.start(o,function(t){if(t.time(s)){f.signal.Post(["CommonHTML Jax - no default em size"]);return}a.getDefaultExEm();if(a.defaultEm){s()}else{setTimeout(t,t.delay)}},this.defaultEmDelay,this.defaultEmTimeout);return s},defaultEmDelay:100,defaultEmTimeout:1000,getDefaultExEm:function(){var s=document.body.appendChild(this.TestSpan.cloneNode(true));s.className+=" mjx-test-inline mjx-test-default";this.defaultEm=this.getFontSize(s);this.defaultEx=s.childNodes[1].offsetHeight/60;this.defaultWidth=Math.max(0,s.lastChild.offsetLeft-s.firstChild.offsetLeft-2);document.body.removeChild(s)},getFontSize:(window.getComputedStyle?function(t){var s=window.getComputedStyle(t);return parseFloat(s.fontSize)}:function(s){return s.style.pixelLeft}),getMaxWidth:(window.getComputedStyle?function(t){var s=window.getComputedStyle(t);if(s.maxWidth!=="none"){return parseFloat(s.maxWidth)}return 0}:function(t){var s=t.currentStyle.maxWidth;if(s!=="none"){if(s.match(/\d*px/)){return parseFloat(s)}var u=t.style.left;t.style.left=s;s=t.style.pixelLeft;t.style.left=u;return s}return 0}),loadFont:function(s){f.RestartAfter(o.Require(this.fontDir+"/"+s))},fontLoaded:function(s){if(!s.match(/-|fontdata/)){s+="-Regular"}if(!s.match(/\.js$/)){s+=".js"}MathJax.Callback.Queue(["Post",f.Startup.signal,"CommonHTML - font data loaded for "+s],["loadComplete",o,this.fontDir+"/"+s])},Element:function(s,u,t){if(s.substr(0,4)==="mjx-"){if(!u){u={}}if(u.isMathJax==null){u.isMathJax=true}if(u.className){u.className=s+" "+u.className}else{u.className=s}s="span"}return this.HTMLElement(s,u,t)},addElement:function(u,s,v,t){return u.appendChild(this.Element(s,v,t))},HTMLElement:m.Element,ucMatch:m.ucMatch,setScript:m.setScript,getNode:function(x,w){var u=RegExp("\\b"+w+"\\b");var t=[];while(x){for(var v=0,s=x.childNodes.length;v=x.CHTMLlast+x.CHTMLchunk){this.postTranslate(x);x.CHTMLchunk=Math.floor(x.CHTMLchunk*this.config.EqnChunkFactor);x.CHTMLdelay=true}},initCHTML:function(t,s){},savePreview:function(s){var t=s.MathJax.preview;if(t&&t.parentNode){s.MathJax.tmpPreview=document.createElement("span");t.parentNode.replaceChild(s.MathJax.tmpPreview,t)}},restorePreview:function(s){var t=s.MathJax.tmpPreview;if(t){t.parentNode.replaceChild(s.MathJax.preview,t);delete s.MathJax.tmpPreview}},getMetrics:function(s){var t=s.CHTML;this.jax=s;this.em=t.em;this.outerEm=t.outerEm;this.scale=t.scale;this.cwidth=t.cwidth;this.linebreakWidth=t.lineWidth},postTranslate:function(x){var t=x.jax[this.id];for(var v=x.CHTMLlast,s=x.CHTMLeqn;vC.h){t.marginTop=a.Em(C.t-C.h)}if(C.b>C.d){t.marginBottom=a.Em(C.b-C.d)}if(C.l<0){t.paddingLeft=a.Em(-C.l)}if(C.r>C.w){t.marginRight=a.Em(C.r-C.w)}t.position="absolute";var z=v.offsetWidth,x=v.offsetHeight,D=A.firstChild.offsetHeight,w=A.firstChild.offsetWidth;v.style.position="";return{Y:-e.getBBox(B).h,mW:w,mH:D,zW:z,zH:x}},Remove:function(s){var t=document.getElementById(s.inputID+"-Frame");if(t&&s.CHTML.display){t=t.parentNode}if(t){t.parentNode.removeChild(t)}delete s.CHTML},ID:0,idPostfix:"",GetID:function(){this.ID++;return this.ID},MATHSPACE:{veryverythinmathspace:1/18,verythinmathspace:2/18,thinmathspace:3/18,mediummathspace:4/18,thickmathspace:5/18,verythickmathspace:6/18,veryverythickmathspace:7/18,negativeveryverythinmathspace:-1/18,negativeverythinmathspace:-2/18,negativethinmathspace:-3/18,negativemediummathspace:-4/18,negativethickmathspace:-5/18,negativeverythickmathspace:-6/18,negativeveryverythickmathspace:-7/18,thin:0.04,medium:0.06,thick:0.1,infinity:i},SPACECLASS:{thinmathspace:"MJXc-space1",mediummathspace:"MJXc-space2",thickmathspace:"MJXc-space3"},pxPerInch:96,em:16,maxStretchyParts:1000,FONTDEF:{},TEXDEF:{x_height:0.442,quad:1,num1:0.676508,num2:0.393732,num3:0.44373,denom1:0.685951,denom2:0.344841,sup1:0.412892,sup2:0.362892,sup3:0.288888,sub1:0.15,sub2:0.247217,sup_drop:0.386108,sub_drop:0.05,delim1:2.39,delim2:1,axis_height:0.25,rule_thickness:0.06,big_op_spacing1:0.111111,big_op_spacing2:0.166666,big_op_spacing3:0.2,big_op_spacing4:0.45,big_op_spacing5:0.1,surd_height:0.075,scriptspace:0.05,nulldelimiterspace:0.12,delimiterfactor:901,delimitershortfall:0.3,min_rule_thickness:1.25},isChar:function(s){if(s.length===1){return true}if(s.length!==2){return false}var t=s.charCodeAt(0);return(t>=55296&&t<56319)},unicodeChar:function(s){if(s<65535){return String.fromCharCode(s)}s-=65536;return String.fromCharCode((s>>10)+55296)+String.fromCharCode((s&1023)+56320)},getUnicode:function(s){var t=s.text.charCodeAt(s.i);s.i++;if(t>=55296&&t<56319){t=(((t-55296)<<10)+(s.text.charCodeAt(s.i)-56320))+65536;s.i++}return t},getCharList:function(w,v){var u,z,s=w.cache,B=v;if(s[v]){return s[v]}if(v>65535&&this.FONTDATA.RemapPlane1){var y=this.FONTDATA.RemapPlane1(v,w);v=y.n;w=y.variant}var t=this.FONTDATA.RANGES,A=this.FONTDATA.VARIANT;if(v>=t[0].low&&v<=t[t.length-1].high){for(u=0,z=t.length;u=t[u].low&&v<=t[u].high){if(t[u].remap&&t[u].remap[v]){v=x+t[u].remap[v]}else{v=v-t[u].low+x;if(t[u].add){v+=t[u].add}}if(w["variant"+t[u].offset]){w=A[w["variant"+t[u].offset]]}break}}}s[B]=this.remapChar(w,v,0);return s[B]},remapChar:function(t,y,w){var v=[],x=this.FONTDATA.VARIANT;if(t.remap&&t.remap[y]){y=t.remap[y];if(t.remap.variant){t=x[t.remap.variant]}}else{if(this.FONTDATA.REMAP[y]&&!t.noRemap){y=this.FONTDATA.REMAP[y]}}if(g(y)){if(y[2]){w=n}t=x[y[1]];y=y[0]}if(typeof(y)==="string"){var s={text:y,i:0,length:y.length};while(s.i(B.a||0)){B.a=u.a}u.className=w.className;var t=w[D.n];if(A){var v=w;if(g(A)){v=a.FONTDATA.FONTS[A[1]];A=A[0];if(typeof(v)==="string"){a.loadFont(v)}}if(v[D.n]){a.fixChar(v[D.n],D.n)}t=a.fixChar(v[A],A);u.className=v.className}u.text+=t.c;if(B.hB.w+t[3]){B.l=B.w+t[3]}if(B.rw.a){w.a=u.a}}s=this.flushText(s,u,t.style);if(v[2]<3){s.style.width=a.Em(v[2])}},flushText:function(t,u,s){t=a.addElement(t,"mjx-charbox",{className:u.className,style:s},[u.text]);if(u.a){t.style.paddingBottom=a.Em(u.a)}u.text="";u.className=null;u.a=0;u.flushed=true;return t}},handleText:function(u,x,t,w){if(u.childNodes.length===0){a.addElement(u,"mjx-char");w=a.BBOX.empty(w)}if(typeof(t)==="string"){t=this.FONTDATA.VARIANT[t]}if(!t){t=this.FONTDATA.VARIANT[d.VARIANT.NORMAL]}var s={text:x,i:0,length:x.length},v=[];if(t.style&&s.length){v.push(this.styledText(t,x))}else{while(s.i-w.b){u.firstChild.style.paddingBottom=this.EmRounded(w.d+w.b)}return w},createDelimiter:function(x,s,u,A,v){if(!s){var B=this.BBOX.zero();B.w=B.r=this.TEX.nulldelimiterspace;a.addElement(x,"mjx-box",{style:{width:B.w}});return B}if(!(u instanceof Array)){u=[u,u]}var z=u[1];u=u[0];var t={alias:s};while(t.alias){s=t.alias;t=this.FONTDATA.DELIMITERS[s];if(!t){t={HW:[0,this.FONTDATA.VARIANT[d.VARIANT.NORMAL]]}}}if(t.load){f.RestartAfter(o.Require(this.fontDir+"/TeX/fontdata-"+t.load+".js"))}for(var y=0,w=t.HW.length;y=u-0.01||(y==w-1&&!t.stretch)){if(t.HW[y][3]){s=t.HW[y][3]}B=this.createChar(x,[s,t.HW[y][1]],(t.HW[y][2]||1),v);B.offset=0.6*B.w;if(A){B.scale=A.scale;A.rscale=A.rscale}return B}}if(!t.stretch){return B}return this["extendDelimiter"+t.dir](x,z,t.stretch,A,v)},extendDelimiterV:function(E,x,P,w,C){E=a.addElement(E,"mjx-delim-v");var N=a.Element("span");var B,A,O,v,I,t,F,y,G=1,M;I=this.createChar(N,(P.top||P.ext),1,C);B=N.removeChild(N.firstChild);t=this.createChar(N,(P.bot||P.ext),1,C);A=N.removeChild(N.firstChild);F=y=a.BBOX.zero();var J=I.h+I.d+t.h+t.d-l;E.appendChild(B);if(P.mid){F=this.createChar(N,P.mid,1,C);O=N.removeChild(N.firstChild);J+=F.h+F.d;G=2}if(P.min&&xJ){y=this.createChar(N,P.ext,1,C);v=N.removeChild(N.firstChild);var L=y.h+y.d,u=L-l;var D=Math.min(Math.ceil((x-J)/(G*u)),this.maxStretchyParts);if(P.fullExtenders){x=D*G*u+J}else{u=(x-J)/(G*D)}M=y.d+y.a-L/2;v.style.margin=v.style.padding="";v.style.lineHeight=a.Em(u);v.style.marginBottom=a.Em(M-l/2/G);v.style.marginTop=a.Em(-M-l/2/G);var K=v.textContent,z="\n"+K;while(--D>0){K+=z}v.textContent=K;E.appendChild(v);if(P.mid){E.appendChild(O);E.appendChild(v.cloneNode(true))}}else{M=(x-J-l)/G;B.style.marginBottom=a.Em(M+parseFloat(B.style.marginBottom||"0"));if(P.mid){E.appendChild(O)}A.style.marginTop=a.Em(M+parseFloat(A.style.marginTop||"0"))}E.appendChild(A);var s=a.BBOX({w:Math.max(I.w,y.w,t.w,F.w),l:Math.min(I.l,y.l,t.l,F.l),r:Math.max(I.r,y.r,t.r,F.r),h:x-t.d,d:t.d,t:x-t.d,b:t.d});s.offset=0.5*s.w;if(w){s.scale=w.scale;s.rscale=w.rscale}return s},extendDelimiterH:function(F,s,P,v,D){F=a.addElement(F,"mjx-delim-h");var N=a.Element("span");var t,M,O,u,K,C,x,G,z,H=1;C=this.createChar(N,(P.left||P.rep),1,D);t=N.removeChild(N.firstChild);x=this.createChar(N,(P.right||P.rep),1,D);M=N.removeChild(N.firstChild);z=this.createChar(N,P.rep,1,D);u=N.removeChild(N.firstChild);t.style.marginLeft=a.Em(-C.l);M.style.marginRight=a.Em(x.r-x.w);F.appendChild(t);var Q=a.BBOX.zero();Q.h=Math.max(C.h,x.h,z.h);Q.d=Math.max(C.D||C.d,x.D||x.d,z.D||z.d);var y=(C.r-C.l)+(x.r-x.l)-l;if(P.mid){G=this.createChar(N,P.mid,1,D);O=N.removeChild(N.firstChild);O.style.marginleft=a.Em(-G.l);O.style.marginRight=a.Em(G.r-G.w);y+=G.r-G.l+l;H=2;if(G.h>Q.h){Q.h=G.h}if(G.d>Q.d){Q.d=G.d}}if(P.min&&sy){var B=z.r-z.l,J=B-l;var E=Math.min(Math.ceil((s-y)/(H*J)),this.maxStretchyParts);if(P.fullExtenders){s=E*H*J+y}else{J=(s-y)/(H*E)}var L=(B-J+l/H)/2;u.style.marginLeft=a.Em(-z.l-L);u.style.marginRight=a.Em(z.r-z.w+L);u.style.letterSpacing=a.Em(-(z.w-J));t.style.marginRight=a.Em(C.r-C.w);M.style.marginleft=a.Em(-x.l);var I=u.textContent,A=I;while(--E>0){I+=A}u.textContent=I;F.appendChild(u);if(P.mid){F.appendChild(O);K=F.appendChild(u.cloneNode(true))}}else{L=(s-y-l/H)/2;t.style.marginRight=a.Em(C.r-C.w+L);if(P.mid){F.appendChild(O)}M.style.marginLeft=a.Em(-x.l+L)}F.appendChild(M);this.adjustHeights([t,u,O,K,M],[C,z,G,z,x],Q);if(v){Q.scale=v.scale;Q.rscale=v.rscale}return Q},adjustHeights:function(t,w,x){var u=x.h,y=x.d;if(x.d<0){y=-x.d;x.D=x.d;x.d=0}for(var v=0,s=t.length;v0){delete this.D}},rescale:function(s){this.w*=s;this.h*=s;this.d*=s;this.l*=s;this.r*=s;this.t*=s;this.b*=s;if(this.L){this.L*=s}if(this.R){this.R*=s}if(this.D){this.D*=s}},combine:function(t,s,v){t.X=s;t.Y=v;var u=t.rscale;if(s+u*t.r>this.r){this.r=s+u*t.r}if(s+u*t.lthis.w){this.w=s+u*(t.w+(t.L||0)+(t.R||0))}if(v+u*t.h>this.h){this.h=v+u*t.h}if(t.D&&(this.D==null||u*t.D-v>this.D)&&u*t.D>this.d){this.D=u*t.D-v}else{if(t.D==null&&this.D){delete this.D}}if(u*t.d-v>this.d){this.d=u*t.d-v}if(v+u*t.t>this.t){this.t=v+u*t.t}if(u*t.b-v>this.b){this.b=u*t.b-v}},append:function(t){var u=t.rscale;var s=this.w;if(s+u*t.r>this.r){this.r=s+u*t.r}if(s+u*t.lthis.h){this.h=u*t.h}if(t.D&&(this.D==null||u*t.D>this.D)&&u*t.D>this.d){this.D=u*t.D}else{if(t.D==null&&this.D){delete this.D}}if(u*t.d>this.d){this.d=u*t.d}if(u*t.t>this.t){this.t=u*t.t}if(u*t.b>this.b){this.b=u*t.b}},updateFrom:function(s){this.h=s.h;this.d=s.d;this.w=s.w;this.r=s.r;this.l=s.l;this.t=s.t;this.b=s.b;if(s.pwidth){this.pwidth=s.pwidth}if(s.D){this.D=s.D}else{delete this.D}},adjust:function(t,s,v,u){this[s]+=a.length2em(t,1,this.scale);if(u==null){if(this[s]>this[v]){this[v]=this[s]}}else{if(this[v]z.r){z.r=z.w}if(t.h>z.h){z.h=t.h}if(t.d>z.d){z.d=t.d}if(t.t>z.t){z.t=t.t}if(t.b>z.b){z.b=t.b}}}},CHTMLstretchChildH:function(v,s,x){var y=this.data[v];if(y){var z=this.CHTML,u=y.CHTML;if(u.stretch||(u.stretch==null&&y.CHTMLcanStretch("Horizontal",s))){var t=u.w;u=y.CHTMLstretchH(this.CHTMLchildNode(x,v),s);z.w+=u.w-t;if(z.w>z.r){z.r=z.w}if(u.h>z.h){z.h=u.h}if(u.d>z.d){z.d=u.d}if(u.t>z.t){z.t=u.t}if(u.b>z.b){z.b=u.b}}}},CHTMLupdateFrom:function(s){this.CHTML.updateFrom(s);if(this.inferRow){this.data[0].CHTML.updateFrom(s)}},CHTMLcanStretch:function(w,u,v){var t=false;if(this.isEmbellished()){var s=this.Core();if(s&&s!==this){t=s.CHTMLcanStretch(w,u,v)}}this.CHTML.stretch=t;return t},CHTMLstretchV:function(s,t){this.CHTMLupdateFrom(this.Core().CHTMLstretchV(s,t));return this.CHTML},CHTMLstretchH:function(t,s){this.CHTMLupdateFrom(this.CHTMLstretchCoreH(t,s));return this.CHTML},CHTMLstretchCoreH:function(t,s){return this.Core().CHTMLstretchH(this.CHTMLcoreNode(t),s)},CHTMLcreateNode:function(s){if(!this.CHTML){this.CHTML={}}this.CHTML=a.BBOX.zero();if(this.href){s=a.addElement(s,"a",{href:this.href,isMathJax:true})}if(!this.CHTMLnodeID){this.CHTMLnodeID=a.GetID()}var t=(this.id||"MJXc-Node-"+this.CHTMLnodeID)+a.idPostfix;return this.CHTMLhandleAttributes(a.addElement(s,"mjx-"+this.type,{id:t}))},CHTMLnodeElement:function(){if(!this.CHTMLnodeID){return null}return document.getElementById((this.id||"MJXc-Node-"+this.CHTMLnodeID)+a.idPostfix)},CHTMLlength2em:function(t,s){return a.length2em(t,s,this.CHTML.scale)},CHTMLhandleAttributes:function(v){if(this["class"]){if(v.className){v.className+=" "+this["class"]}else{v.className=this["class"]}}if(this.attrNames){var z=this.attrNames,u=d.nocopyAttributes,y=f.config.ignoreMMLattributes;var w=(this.type==="mstyle"?d.math.prototype.defaults:this.defaults);for(var t=0,s=z.length;t2){s.scriptlevel=2}x=Math.pow(this.Get("scriptsizemultiplier"),s.scriptlevel);s.scriptminsize=a.length2em(this.Get("scriptminsize"),0.8,1);if(x600?"bold":"normal")}var t=s.mathvariant;if(this.variantForm){t="-TeX-variant"}if(s.family&&!s.hasVariant){if(!s.weight&&s.mathvariant.match(/bold/)){s.weight="bold"}if(!s.style&&s.mathvariant.match(/italic/)){s.style="italic"}this.CHTMLvariant={fonts:[],noRemap:true,cache:{},style:{"font-family":s.family,"font-weight":s.weight||"normal","font-style":s.style||"normal"}};return}if(s.weight==="bold"){t={normal:d.VARIANT.BOLD,italic:d.VARIANT.BOLDITALIC,fraktur:d.VARIANT.BOLDFRAKTUR,script:d.VARIANT.BOLDSCRIPT,"sans-serif":d.VARIANT.BOLDSANSSERIF,"sans-serif-italic":d.VARIANT.SANSSERIFBOLDITALIC}[t]||t}else{if(s.weight==="normal"){t={bold:d.VARIANT.normal,"bold-italic":d.VARIANT.ITALIC,"bold-fraktur":d.VARIANT.FRAKTUR,"bold-script":d.VARIANT.SCRIPT,"bold-sans-serif":d.VARIANT.SANSSERIF,"sans-serif-bold-italic":d.VARIANT.SANSSERIFITALIC}[t]||t}}if(s.style==="italic"){t={normal:d.VARIANT.ITALIC,bold:d.VARIANT.BOLDITALIC,"sans-serif":d.VARIANT.SANSSERIFITALIC,"bold-sans-serif":d.VARIANT.SANSSERIFBOLDITALIC}[t]||t}else{if(s.style==="normal"){t={italic:d.VARIANT.NORMAL,"bold-italic":d.VARIANT.BOLD,"sans-serif-italic":d.VARIANT.SANSSERIF,"sans-serif-bold-italic":d.VARIANT.BOLDSANSSERIF}[t]||t}}this.CHTMLvariant=a.FONTDATA.VARIANT[t]||a.FONTDATA.VARIANT[d.VARIANT.NORMAL]},CHTMLbboxFor:function(s){if(this.data[s]&&this.data[s].CHTML){return this.data[s].CHTML}return a.BBOX.zero()},CHTMLdrawBBox:function(t,u){if(!u){u=this.CHTML}var s=a.Element("mjx-box",{style:{opacity:0.25,"margin-left":a.Em(-(u.w+(u.R||0)))}},[["mjx-box",{style:{height:a.Em(u.h),width:a.Em(u.w),"background-color":"red"}}],["mjx-box",{style:{height:a.Em(u.d),width:a.Em(u.w),"margin-left":a.Em(-u.w),"vertical-align":a.Em(-u.d),"background-color":"green"}}]]);if(t.nextSibling){t.parentNode.insertBefore(s,t.nextSibling)}else{t.parentNode.appendChild(s)}},CHTMLnotEmpty:function(s){while(s&&s.data.length<2&&(s.type==="mrow"||s.type==="texatom")){s=s.data[0]}return !!s}},{CHTMLautoload:function(){this.constructor.Augment({toCommonHTML:d.mbase.CHTMLautoloadFail});var s=a.autoloadDir+"/"+this.type+".js";f.RestartAfter(o.Require(s))},CHTMLautoloadFail:function(){throw Error("CommonHTML can't autoload '"+this.type+"'")},CHTMLautoloadList:{},CHTMLautoloadFile:function(s){if(d.mbase.CHTMLautoloadList.hasOwnProperty(s)){throw Error("CommonHTML can't autoload file '"+s+"'")}d.mbase.CHTMLautoloadList[s]=true;var t=a.autoloadDir+"/"+s+".js";f.RestartAfter(o.Require(t))},CHTMLstretchV:function(s,t){this.Core().CHTMLstretchV(s,t);this.toCommonHTML(this.CHTMLnodeElement(),{stretch:true});return this.CHTML},CHTMLstretchH:function(t,s){this.CHTMLupdateFrom(this.CHTMLstretchCoreH(t,s));this.toCommonHTML(t,{stretch:true});return this.CHTML}});d.chars.Augment({toCommonHTML:function(t,s){this.CHTML=null;if(s==null){s={}}var u=this.toString();if(s.remap){u=s.remap(u,s.remapchars)}this.CHTMLhandleText(t,u,s.variant||this.parent.CHTMLvariant)}});d.entity.Augment({toCommonHTML:function(t,s){if(s==null){s={}}var u=this.toString();if(s.remapchars){u=s.remap(u,s.remapchars)}this.CHTMLhandleText(t,u,s.variant||this.parent.CHTMLvariant)}});d.math.Augment({toCommonHTML:function(x){x=this.CHTMLdefaultNode(x);if(this.CHTML.w<0){x.parentNode.style.width="0px";x.parentNode.style.marginRight=a.Em(this.CHTML.w)}var v=this.Get("alttext");if(v&&!x.getAttribute("aria-label")){x.setAttribute("aria-label",v)}if(this.CHTML.pwidth){x.parentNode.style.minWidth=this.CHTML.mwidth||a.Em(this.CHTML.w);x.parentNode.className="mjx-full-width "+x.parentNode.className;x.style.width=this.CHTML.pwidth}else{if(!this.isMultiline&&this.Get("display")==="block"){var u=this.getValues("indentalignfirst","indentshiftfirst","indentalign","indentshift");if(u.indentalignfirst!==d.INDENTALIGN.INDENTALIGN){u.indentalign=u.indentalignfirst}if(u.indentalign===d.INDENTALIGN.AUTO){u.indentalign=r.displayAlign}if(u.indentshiftfirst!==d.INDENTSHIFT.INDENTSHIFT){u.indentshift=u.indentshiftfirst}if(u.indentshift==="auto"){u.indentshift="0"}var t=this.CHTMLlength2em(u.indentshift,a.cwidth);if(r.displayIndent!=="0"){var s=this.CHTMLlength2em(r.displayIndent,a.cwidth);t+=(u.indentalign===d.INDENTALIGN.RIGHT?-s:s)}var w=x.parentNode.parentNode.style;x.parentNode.style.textAlign=w.textAlign=u.indentalign;if(t){t*=a.em/a.outerEm;f.Insert(w,({left:{marginLeft:a.Em(t)},right:{marginRight:a.Em(-t)},center:{marginLeft:a.Em(t),marginRight:a.Em(-t)}})[u.indentalign])}}}return x}});d.mi.Augment({toCommonHTML:function(s){s=this.CHTMLdefaultNode(s);var u=this.CHTML,t=this.data.join("");if(u.skew!=null&&!a.isChar(t)){delete u.skew}if(u.r>u.w&&a.isChar(t)&&!this.CHTMLvariant.noIC){u.ic=u.r-u.w;u.w=u.r;s.lastChild.style.paddingRight=a.Em(u.ic)}return s}});d.mn.Augment({CHTMLremapMinus:function(s){return s.replace(/^-/,"\u2212")},toCommonHTML:function(s){s=this.CHTMLdefaultNode(s,{childOptions:{remap:this.CHTMLremapMinus}});var u=this.CHTML,t=this.data.join("");if(u.skew!=null&&!a.isChar(t)){delete u.skew}if(u.r>u.w&&a.isChar(t)&&!this.CHTMLvariant.noIC){u.ic=u.r-u.w;u.w=u.r;s.lastChild.style.paddingRight=a.Em(u.ic)}return s}});d.mo.Augment({toCommonHTML:function(v){v=this.CHTMLcreateNode(v);this.CHTMLhandleStyle(v);this.CHTMLgetVariant();this.CHTMLhandleScale(v);a.BBOX.empty(this.CHTML);var t=this.getValues("displaystyle","largeop");t.variant=this.CHTMLvariant;t.text=this.data.join("");if(t.text==""){if(this.fence){v.style.width=a.Em(a.TEX.nulldelimiterspace)}}else{this.CHTMLadjustAccent(t);this.CHTMLadjustVariant(t);for(var u=0,s=this.data.length;u0){if(!this.hasValue("lspace")){t.lspace=0.15}if(!this.hasValue("rspace")){t.rspace=0.15}}var s=this,u=this.Parent();while(u&&u.isEmbellished()&&u.Core()===s){s=u;u=u.Parent();v=s.CHTMLnodeElement()}if(t.lspace){v.style.paddingLeft=a.Em(t.lspace)}if(t.rspace){v.style.paddingRight=a.Em(t.rspace)}this.CHTML.L=t.lspace;this.CHTML.R=t.rspace}else{this.SUPER(arguments).CHTMLhandleSpace.apply(this,arguments)}},CHTMLadjustAccent:function(u){var t=this.CoreParent();u.parent=t;if(a.isChar(u.text)&&t&&t.isa(d.munderover)){var v=t.data[t.over],s=t.data[t.under];if(v&&this===v.CoreMO()&&t.Get("accent")){u.remapchars=a.FONTDATA.REMAPACCENT}else{if(s&&this===s.CoreMO()&&t.Get("accentunder")){u.remapchars=a.FONTDATA.REMAPACCENTUNDER}}}},CHTMLadjustVariant:function(t){var s=t.parent,u=(s&&s.isa(d.msubsup)&&this!==s.data[s.base]);if(t.largeop){t.mathvariant=(t.displaystyle?"-largeOp":"-smallOp")}if(u){t.remapchars=this.remapChars;if(t.text.match(/['`"\u00B4\u2032-\u2037\u2057]/)){t.mathvariant="-TeX-variant"}}},CHTMLfixCombiningChar:function(s){s=s.firstChild;var t=a.Element("mjx-box",{style:{width:".25em","margin-left":"-.25em"}});s.insertBefore(t,s.firstChild)},CHTMLcenterOp:function(s){var u=this.CHTML;var t=(u.h-u.d)/2-a.TEX.axis_height;if(Math.abs(t)>0.001){s.style.verticalAlign=a.Em(-t)}u.h-=t;u.d+=t;if(u.r>u.w){u.ic=u.r-u.w;u.w=u.r;s.style.paddingRight=a.Em(u.ic)}},CHTMLcanStretch:function(w,u,v){if(!this.Get("stretchy")){return false}var x=this.data.join("");if(!a.isChar(x)){return false}var t={text:x};this.CHTMLadjustAccent(t);if(t.remapchars){x=t.remapchars[x]||x}x=a.FONTDATA.DELIMITERS[x.charCodeAt(0)];var s=(x&&x.dir===w.substr(0,1));if(s){s=(this.CHTML.h!==u||this.CHTML.d!==v||!!this.Get("minsize",true)||!!this.Get("maxsize",true));if(s){this.CHTML.stretch=true}}return s},CHTMLstretchV:function(v,y){var w=this.CHTMLnodeElement(),x=this.CHTML;var t=this.getValues("symmetric","maxsize","minsize");var u,s=a.TEX.axis_height;if(t.symmetric){u=2*Math.max(v-s,y+s)}else{u=v+y}t.maxsize=this.CHTMLlength2em(t.maxsize,x.h+x.d);t.minsize=this.CHTMLlength2em(t.minsize,x.h+x.d);u=Math.max(t.minsize,Math.min(t.maxsize,u));if(u!==x.sH){if(u!=t.minsize){u=[Math.max(u*a.TEX.delimiterfactor/1000,u-a.TEX.delimitershortfall),u]}while(w.firstChild){w.removeChild(w.firstChild)}this.CHTML=x=a.createDelimiter(w,this.data.join("").charCodeAt(0),u,x);x.sH=(u instanceof Array?u[1]:u);if(t.symmetric){u=(x.h+x.d)/2+s}else{u=(x.h+x.d)*v/(v+y)}u-=x.h;if(Math.abs(u)>0.05){w.style.verticalAlign=a.Em(u);x.h+=u;x.d-=u;x.t+=u;x.b-=u}}return this.CHTML},CHTMLstretchH:function(u,s){var v=this.CHTML;var t=this.getValues("maxsize","minsize","mathvariant","fontweight");if((t.fontweight==="bold"||(this.removedStyles||{}).fontWeight==="bold"||parseInt(t.fontweight)>=600)&&!this.Get("mathvariant",true)){t.mathvariant=d.VARIANT.BOLD}t.maxsize=this.CHTMLlength2em(t.maxsize,v.w);t.minsize=this.CHTMLlength2em(t.minsize,v.w);s=Math.max(t.minsize,Math.min(t.maxsize,s));if(s!==v.sW){while(u.firstChild){u.removeChild(u.firstChild)}this.CHTML=v=a.createDelimiter(u,this.data.join("").charCodeAt(0),s,v,t.mathvariant);v.sW=s}return this.CHTML}});d.mtext.Augment({CHTMLgetVariant:function(){if(a.config.mtextFontInherit||this.Parent().type==="merror"){var u=(a.config.scale/100)/a.scale;var t={cache:{},fonts:[],className:"MJXc-font-inherit",rscale:u,style:{"font-size":a.Percent(u)}};var s=this.Get("mathvariant");if(s.match(/bold/)){t.style["font-weight"]="bold"}if(s.match(/italic|-tex-mathit/)){t.style["font-style"]="italic"}if(s==="monospace"){t.className+=" MJXc-monospace-font"}if(s==="double-struck"){t.className+=" MJXc-double-struck-font"}if(s.match(/fraktur/)){t.className+=" MJXc-fraktur-font"}if(s.match(/sans-serif/)){t.className+=" MJXc-sans-serif-font"}if(s.match(/script/)){t.className+=" MJXc-script-font"}this.CHTMLvariant=t}else{this.SUPER(arguments).CHTMLgetVariant.call(this)}}});d.merror.Augment({toCommonHTML:function(s){s=this.CHTMLdefaultNode(s);var t=this.CHTML;t.rescale(0.9);t.h+=3/a.em;if(t.h>t.t){t.t=t.h}t.d+=3/a.em;if(t.d>t.b){t.b=t.d}t.w+=8/a.em;t.r=t.w;t.l=0;return s}});d.mspace.Augment({toCommonHTML:function(v){v=this.CHTMLcreateNode(v);this.CHTMLhandleStyle(v);this.CHTMLhandleScale(v);var t=this.getValues("height","depth","width");var s=this.CHTMLlength2em(t.width),u=this.CHTMLlength2em(t.height),y=this.CHTMLlength2em(t.depth);var x=this.CHTML;x.w=x.r=s;x.h=x.t=u;x.d=x.b=y;x.l=0;if(s<0){v.style.marginRight=a.Em(s);s=0}v.style.width=a.Em(s);v.style.height=a.Em(Math.max(0,u+y));if(y){v.style.verticalAlign=a.Em(-y)}this.CHTMLhandleBBox(v);this.CHTMLhandleColor(v);return v}});d.mpadded.Augment({toCommonHTML:function(t,F){var s;if(F&&F.stretch){t=t.firstChild;s=t.firstChild}else{t=this.CHTMLdefaultNode(t,{childNodes:"mjx-box",forceChild:true});s=t.firstChild;t=a.addElement(t,"mjx-block");t.appendChild(s);a.addElement(t,"mjx-strut")}var z=this.CHTMLbboxFor(0);var D=this.getValues("width","height","depth","lspace","voffset");var B=0,A=0,C=z.w,u=z.h,v=z.d;s.style.width=0;s.style.margin=a.Em(-u)+" 0 "+a.Em(-v);if(D.width!==""){C=this.CHTMLdimen(D.width,"w",C,0)}if(D.height!==""){u=this.CHTMLdimen(D.height,"h",u,0)}if(D.depth!==""){v=this.CHTMLdimen(D.depth,"d",v,0)}if(D.voffset!==""){A=this.CHTMLdimen(D.voffset);if(A){s.style.position="relative";s.style.top=a.Em(-A)}}if(D.lspace!==""){B=this.CHTMLdimen(D.lspace);if(B){s.style.position="relative";s.style.left=a.Em(B)}}t.style.width=0;t.style.marginTop=a.Em(u-k);t.style.padding="0 "+a.Em(C)+" "+a.Em(v)+" 0";var E=a.BBOX({w:C,h:u,d:v,l:0,r:C,t:u,b:v,scale:this.CHTML.scale,rscale:this.CHTML.rscale});E.combine(z,B,A);E.w=C;E.h=u;E.d=v;this.CHTML=E;return t.parentNode},CHTMLstretchV:d.mbase.CHTMLstretchV,CHTMLstretchH:d.mbase.CHTMLstretchH,CHTMLdimen:function(w,y,x,s){if(s==null){s=-i}w=String(w);var t=w.match(/width|height|depth/);var u=(t?this.CHTML[t[0].charAt(0)]:(y?this.CHTML[y]:0));var v=(this.CHTMLlength2em(w,u)||0);if(w.match(/^[-+]/)&&x!=null){v+=x}if(s!=null){v=Math.max(s,v)}return v}});d.munderover.Augment({toCommonHTML:function(w,G){var E=this.getValues("displaystyle","accent","accentunder","align");var u=this.data[this.base];if(!E.displaystyle&&u!=null&&(u.movablelimits||u.CoreMO().Get("movablelimits"))){return d.msubsup.prototype.toCommonHTML.call(this,w,t)}var B,z,s=[],t=false;if(G&&G.stretch){if(this.data[this.base]){u=a.getNode(w,"mjx-op")}if(this.data[this.under]){B=a.getNode(w,"mjx-under")}if(this.data[this.over]){z=a.getNode(w,"mjx-over")}s[0]=u;s[1]=B||z;s[2]=z;t=true}else{var y=["mjx-op","mjx-under","mjx-over"];if(this.over===1){y[1]=y[2]}w=this.CHTMLdefaultNode(w,{childNodes:y,noBBox:true,forceChild:true,minChildren:2});s[0]=u=w.removeChild(w.firstChild);s[1]=B=z=w.removeChild(w.firstChild);if(w.firstChild){s[2]=z=w.removeChild(w.firstChild)}}var x=[],v=this.CHTMLgetBBoxes(x,s,E);var F=x[this.base],C=this.CHTML;C.w=v;C.h=F.h;C.d=F.d;if(F.h<0.35){u.style.marginTop=a.Em(F.h-0.35)}if(E.accent&&F.hu){u=s}}if(u===-i){u=s}for(y=0;yD.w){D.skew+=(D.w-(A.x+u*A.w))/2}}}else{y=a.TEX.big_op_spacing1;x=a.TEX.big_op_spacing3;v=Math.max(y,x-Math.max(0,u*A.d))}A.x+=E/2;A.y=D.h+v+w+u*A.d;if(v){B.style.paddingBottom=a.Em(v/u)}if(w){B.style.paddingTop=a.Em(w/u)}return C},CHTMLaddUnderscript:function(B,z,E,D,t,A,s){var C=this.CHTML;var y,x,w=a.TEX.big_op_spacing5,v;var F=z[this.under],u=F.rscale;if(!s){a.addElement(t,"mjx-itable",{},[["mjx-row",{},[["mjx-cell"]]],["mjx-row"]]);t.firstChild.firstChild.firstChild.appendChild(A);t.firstChild.lastChild.appendChild(B)}if(F.D){F.d=F.D}if(F.d<0){B.firstChild.style.verticalAlign="top";t.firstChild.style.marginBottom=a.Em(F.d)}if(E.accentunder){v=2*a.TEX.rule_thickness;w=0}else{y=a.TEX.big_op_spacing2;x=a.TEX.big_op_spacing4;v=Math.max(y,x-u*F.h)}F.x=-D/2;F.y=-(C.d+v+w+u*F.h);if(v){B.style.paddingTop=a.Em(v/u)}if(w){B.style.paddingBottom=a.Em(w/u)}},CHTMLplaceBoxes:function(s,B,A,E,z){var t=this.CHTML.w,y,v=z.length,x;var D=a.BBOX.zero();D.scale=this.CHTML.scale;D.rscale=this.CHTML.rscale;z[this.base].x=z[this.base].y=0;var F=i;for(y=0;y0){L+=Q;J-=Q}}L=Math.max(L,A.superscriptshift);J=Math.max(J,A.subscriptshift);H.style.paddingRight=a.Em(N/B);z.style.paddingBottom=a.Em(L/w+J/B-W.d-P.h/B*w);z.style.paddingLeft=a.Em(Y/w);z.style.paddingRight=a.Em(N/w);E.style.verticalAlign=a.Em(-J);G.combine(W,I+Y,L);G.combine(P,I,-J)}}G.clean();return S},CHTMLstretchV:d.mbase.CHTMLstretchV,CHTMLstretchH:d.mbase.CHTMLstretchH,CHTMLchildNode:function(u,t){var s=["mjx-base","mjx-sub","mjx-sup"];if(this.over===1){s[1]=s[2]}return a.getNode(u,s[t])}});d.mfrac.Augment({toCommonHTML:function(N){N=this.CHTMLdefaultNode(N,{childNodes:["mjx-numerator","mjx-denominator"],childOptions:{autowidth:true},forceChild:true,noBBox:true,minChildren:2});var x=this.getValues("linethickness","displaystyle","numalign","denomalign","bevelled");var O=x.displaystyle;var D=N.firstChild,w=N.lastChild;var y=a.addElement(N,"mjx-box");y.appendChild(D);y.appendChild(w);N.appendChild(y);if(x.numalign!=="center"){D.style.textAlign=x.numalign}if(x.denomalign!=="center"){w.style.textAlign=x.denomalign}var P=this.CHTMLbboxFor(0),B=this.CHTMLbboxFor(1),C=a.BBOX.empty(this.CHTML),F=P.rscale,z=B.rscale;x.linethickness=Math.max(0,a.thickness2em(x.linethickness||"0",C.scale));var M=a.TEX.min_rule_thickness/a.em,T=a.TEX.axis_height;var J=x.linethickness,L,K,I,G;if(x.bevelled){y.className+=" MJXc-bevelled";var S=(O?0.4:0.15);var E=Math.max(F*(P.h+P.d),z*(B.h+B.d))+2*S;var R=a.Element("mjx-bevel");y.insertBefore(R,w);var s=a.createDelimiter(R,47,E);I=F*(P.d-P.h)/2+T+S;G=z*(B.d-B.h)/2+T-S;if(I){D.style.verticalAlign=a.Em(I/F)}if(G){w.style.verticalAlign=a.Em(G/z)}R.style.marginLeft=R.style.marginRight=a.Em(-S/2);C.combine(P,0,I);C.combine(s,F*P.w-S/2,0);C.combine(B,F*P.w+s.w-S,G);C.clean()}else{y.className+=" MJXc-stacked";if(O){I=a.TEX.num1;G=a.TEX.denom1}else{I=(J===0?a.TEX.num3:a.TEX.num2);G=a.TEX.denom2}if(J===0){L=Math.max((O?7:3)*a.TEX.rule_thickness,2*M);K=(I-P.d*F)-(B.h*z-G);if(KD){s=((A.h+A.d)-(D-G))/2}D=F.h+s+G;var B=this.CHTMLaddRoot(w,A,A.h+A.d-D);v.style.paddingTop=a.Em(s);v.style.borderTop=a.Px(y*F.scale,1)+" solid";E.style.paddingTop=a.Em(2*G-y);F.h+=s+2*G;C.combine(A,B,D-A.h);C.combine(F,B+A.w,0);C.clean();return w},CHTMLaddRoot:function(){return 0},CHTMLhandleBBox:function(s){var t=this.CHTMLbboxFor(0);delete t.pwidth;this.SUPER(arguments).CHTMLhandleBBox.apply(this,arguments)}});d.mroot.Augment({toCommonHTML:d.msqrt.prototype.toCommonHTML,CHTMLhandleBBox:d.msqrt.prototype.CHTMLhandleBBox,CHTMLaddRoot:function(A,u,v){if(!this.data[1]){return}var z=this.CHTML,B=this.data[1].CHTML,x=A.firstChild;var s=B.rscale;var t=this.CHTMLrootHeight(B,u,s)-v;var y=Math.min(B.w,B.r);var C=Math.max(y,u.offset/s);if(t){x.style.verticalAlign=a.Em(t/s)}if(C>y){x.firstChild.style.paddingLeft=a.Em(C-y)}C-=u.offset/s;x.style.width=a.Em(C);z.combine(B,0,t);return C*s},CHTMLrootHeight:function(u,s,t){return 0.45*(s.h+s.d-0.9)+s.offset+Math.max(0,u.d-0.075)}});d.mfenced.Augment({toCommonHTML:function(v){v=this.CHTMLcreateNode(v);this.CHTMLhandleStyle(v);this.CHTMLhandleScale(v);this.CHTMLaddChild(v,"open",{});for(var u=0,s=this.data.length;ua.linebreakWidth)||this.hasNewline()},CHTMLstretchV:function(s,t){this.CHTMLstretchChildV(this.CoreIndex(),s,t);return this.CHTML},CHTMLstretchH:function(t,s){this.CHTMLstretchChildH(this.CoreIndex(),s,t);return this.CHTML}});d.TeXAtom.Augment({toCommonHTML:function(x,w){if(!w||!w.stretch){x=this.CHTMLdefaultNode(x)}if(this.texClass===d.TEXCLASS.VCENTER){var s=a.TEX.axis_height,u=this.CHTML;var t=s-(u.h+u.d)/2+u.d;if(Math.abs(t)>0.001){x.style.verticalAlign=a.Em(t);u.h+=t;u.t+=t;u.d-=t;u.b-=t}}return x},CHTMLstretchV:function(s,t){this.CHTMLupdateFrom(this.Core().CHTMLstretchV(s,t));this.toCommonHTML(this.CHTMLnodeElement(),{stretch:true});return this.CHTML},CHTMLstretchH:function(t,s){this.CHTMLupdateFrom(this.CHTMLstretchCoreH(t,s));this.toCommonHTML(t,{stretch:true});return this.CHTML}});d.semantics.Augment({toCommonHTML:function(s){s=this.CHTMLcreateNode(s);if(this.data[0]){this.data[0].toCommonHTML(s);this.CHTMLupdateFrom(this.data[0].CHTML);this.CHTMLhandleBBox(s)}return s}});d.annotation.Augment({toCommonHTML:function(s){return this.CHTMLcreateNode(s)}});d["annotation-xml"].Augment({toCommonHTML:d.mbase.CHTMLautoload});d.ms.Augment({toCommonHTML:d.mbase.CHTMLautoload});d.mglyph.Augment({toCommonHTML:d.mbase.CHTMLautoload});d.menclose.Augment({toCommonHTML:d.mbase.CHTMLautoload});d.maction.Augment({toCommonHTML:d.mbase.CHTMLautoload});d.mmultiscripts.Augment({toCommonHTML:d.mbase.CHTMLautoload});d.mtable.Augment({toCommonHTML:d.mbase.CHTMLautoload});MathJax.Hub.Register.StartupHook("onLoad",function(){setTimeout(MathJax.Callback(["loadComplete",a,"jax.js"]),0)})});MathJax.Hub.Register.StartupHook("End Cookie",function(){if(f.config.menuSettings.zoom!=="None"){o.Require("[MathJax]/extensions/MathZoom.js")}})})(MathJax.Ajax,MathJax.Hub,MathJax.HTML,MathJax.OutputJax.CommonHTML);
+MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function(){var g="2.7.5";var b=MathJax.ElementJax.mml,a=MathJax.Hub.config,e=MathJax.OutputJax.CommonHTML,d=MathJax.Hub.SplitList;var c=-1,f=1000000;b.mtable.Augment({toCommonHTML:function(l){var m={rows:[],labels:[],labeled:false};l=this.CHTMLdefaultNode(l,{noBBox:true,childOptions:m});var k=e.Element("mjx-table");while(l.firstChild){k.appendChild(l.firstChild)}l.appendChild(k);var h=this.getValues("columnalign","rowalign","columnspacing","rowspacing","columnwidth","equalcolumns","equalrows","columnlines","rowlines","frame","framespacing","align","width","side","minlabelspacing","useHeight");var j=e.TEX.min_rule_thickness/e.em;m.t=e.Px(j*this.CHTML.scale,1);this.CHTMLgetBoxSizes(h,m);this.CHTMLgetAttributes(h,m);this.CHTMLadjustCells(h,m);if(h.frame){k.style.border=m.t+" "+h.frame}this.CHTMLalignV(h,m,l);this.CHTMLcolumnWidths(h,m,l);this.CHTMLstretchCells(h,m);if(m.labeled){this.CHTMLaddLabels(h,m,l,k)}var i=this.CHTML;i.w=i.r=m.R;i.h=i.t=m.T-m.B;i.d=i.b=m.B;if(!h.frame&&!i.pwidth){l.style.padding="0 "+e.Em(1/6);i.L=i.R=1/6}this.CHTMLhandleSpace(l);this.CHTMLhandleBBox(l);this.CHTMLhandleColor(l);return l},CHTMLgetBoxSizes:function(z,k){var r=e.FONTDATA.lineH*z.useHeight,t=e.FONTDATA.lineD*z.useHeight;var y=[],h=[],l=[],w=-1,q,n;for(q=0,n=this.data.length;qw){w=p}}var u=B.data[p-A].CHTML;if(u.h>y[q]){y[q]=u.h}if(u.d>h[q]){h[q]=u.d}if(u.w>l[p]){l[p]=u.w}}}if(z.equalrows){k.HD=true;var x=Math.max.apply(Math,y);var o=Math.max.apply(Math,h);for(q=0,n=y.length;qt||m<=0){m=null}}else{w.align=this.defaults.align}var p=0,l=0,u=e.TEX.axis_height;if(w.fspace){p+=k.FSPACE[1]}if(w.frame){p+=2/e.em;l+=1/e.em}for(var q=0;q=m){l+=r+s+x[q]}}}if(!m){l=({top:p,bottom:0,center:p/2,baseline:p/2,axis:p/2-u})[w.align]}if(l){o.style.verticalAlign=e.Em(-l)}k.T=p;k.B=l},CHTMLcolumnWidths:function(l,r,A){var I=r.CWIDTH,K=r.CSPACE,u=r.J,F;var G=0,n=false,y=l.width.match(/%$/);var H,B,v;if(l.width!=="auto"&&!y){G=Math.max(0,this.CHTMLlength2em(l.width,r.R));n=true}if(l.equalcolumns){if(y){var z=e.Percent(1/(u+1));for(F=0;F<=u;F++){I[F]=z}}else{v=Math.max.apply(Math,r.W);if(l.width!=="auto"){var q=(l.fspace?r.FSPACE[0]+(l.frame?2/e.em:0):0);for(F=0;F<=u;F++){q+=K[F]}v=Math.max((G-q)/(u+1),v)}v=e.Em(v);for(F=0;F<=u;F++){I[F]=v}}n=true}var E=0;if(l.fspace){E=r.FSPACE[0]}var s=[],D=[],h=[],o=[];var t=r.rows[0];for(F=0;F<=u;F++){o[F]=r.W[F];if(I[F]==="auto"){s.push(F)}else{if(I[F]==="fit"){D.push(F)}else{if(I[F].match(/%$/)){h.push(F)}else{o[F]=this.CHTMLlength2em(I[F],o[F])}}}E+=o[F]+K[F];if(t[F]){t[F].style.width=e.Em(o[F])}}if(l.frame){E+=2/e.em}var C=(D.length>0);if(n){if(y){for(F=0;F<=u;F++){cell=t[F].style;if(I[F]==="auto"&&!C){cell.width=""}else{if(I[F]==="fit"){cell.width=""}else{if(I[F].match(/%$/)){cell.width=I[F]}else{cell.minWidth=cell.maxWidth=cell.width}}}}}else{if(G>E){var k=0;for(H=0,B=h.length;HE&&D.length){var x=(G-E)/D.length;for(H=0,B=D.length;Ht*z){z=t*p}z+=y;z*=t;D+=z}else{D+=p-t*z+n;z-=t*n;z*=-t}}var o=e.addElement(w,"mjx-box",{style:{width:"100%","text-align":q.indentalign}});o.appendChild(B);var C=e.Element("mjx-itable");B.style.display="inline-table";if(!B.style.width){B.style.width="auto"}C.style.verticalAlign="top";B.style.verticalAlign=e.Em(k.T-k.B-k.H[0]);w.style.verticalAlign="";if(z){if(q.indentalign===b.INDENTALIGN.CENTER){B.style.marginLeft=e.Em(z);B.style.marginRight=e.Em(-z)}else{var u="margin"+(q.indentalign===b.INDENTALIGN.RIGHT?"Right":"Left");B.style[u]=e.Em(z)}}if(k.CALIGN[c]==="left"){w.insertBefore(C,o);C.style.marginRight=e.Em(-k.W[c]-y);if(y){C.style.marginLeft=e.Em(y)}}else{w.appendChild(C);C.style.marginLeft=e.Em(-k.W[c]+y)}var l=k.labels,j=0;if(h.fspace){j=k.FSPACE[0]+(h.frame?1/e.em:0)}for(var x=0,v=l.length;x1){h.h*=k;h.d*=k}}}else{h.w=Math.max(h.w,this.CHTMLlength2em(j,h.w))}}}}return l}});MathJax.Hub.Startup.signal.Post("CommonHTML mtable Ready");MathJax.Ajax.loadComplete(e.autoloadDir+"/mtable.js")});
+(function(i,b,e,g){var h;var j,a,d;var f="'Times New Roman',Times,STIXGeneral,serif";var m={".MJXp-script":{"font-size":".8em"},".MJXp-right":{"-webkit-transform-origin":"right","-moz-transform-origin":"right","-ms-transform-origin":"right","-o-transform-origin":"right","transform-origin":"right"},".MJXp-bold":{"font-weight":"bold"},".MJXp-italic":{"font-style":"italic"},".MJXp-scr":{"font-family":"MathJax_Script,"+f},".MJXp-frak":{"font-family":"MathJax_Fraktur,"+f},".MJXp-sf":{"font-family":"MathJax_SansSerif,"+f},".MJXp-cal":{"font-family":"MathJax_Caligraphic,"+f},".MJXp-mono":{"font-family":"MathJax_Typewriter,"+f},".MJXp-largeop":{"font-size":"150%"},".MJXp-largeop.MJXp-int":{"vertical-align":"-.2em"},".MJXp-math":{display:"inline-block","line-height":"1.2","text-indent":"0","font-family":f,"white-space":"nowrap","border-collapse":"collapse"},".MJXp-display":{display:"block","text-align":"center",margin:"1em 0"},".MJXp-math span":{display:"inline-block"},".MJXp-box":{display:"block!important","text-align":"center"},".MJXp-box:after":{content:'" "'},".MJXp-rule":{display:"block!important","margin-top":".1em"},".MJXp-char":{display:"block!important"},".MJXp-mo":{margin:"0 .15em"},".MJXp-mfrac":{margin:"0 .125em","vertical-align":".25em"},".MJXp-denom":{display:"inline-table!important",width:"100%"},".MJXp-denom > *":{display:"table-row!important"},".MJXp-surd":{"vertical-align":"top"},".MJXp-surd > *":{display:"block!important"},".MJXp-script-box > * ":{display:"table!important",height:"50%"},".MJXp-script-box > * > *":{display:"table-cell!important","vertical-align":"top"},".MJXp-script-box > *:last-child > *":{"vertical-align":"bottom"},".MJXp-script-box > * > * > *":{display:"block!important"},".MJXp-mphantom":{visibility:"hidden"},".MJXp-munderover, .MJXp-munder":{display:"inline-table!important"},".MJXp-over":{display:"inline-block!important","text-align":"center"},".MJXp-over > *":{display:"block!important"},".MJXp-munderover > *, .MJXp-munder > *":{display:"table-row!important"},".MJXp-mtable":{"vertical-align":".25em",margin:"0 .125em"},".MJXp-mtable > *":{display:"inline-table!important","vertical-align":"middle"},".MJXp-mtr":{display:"table-row!important"},".MJXp-mtd":{display:"table-cell!important","text-align":"center",padding:".5em 0 0 .5em"},".MJXp-mtr > .MJXp-mtd:first-child":{"padding-left":0},".MJXp-mtr:first-child > .MJXp-mtd":{"padding-top":0},".MJXp-mlabeledtr":{display:"table-row!important"},".MJXp-mlabeledtr > .MJXp-mtd:first-child":{"padding-left":0},".MJXp-mlabeledtr:first-child > .MJXp-mtd":{"padding-top":0},".MJXp-merror":{"background-color":"#FFFF88",color:"#CC0000",border:"1px solid #CC0000",padding:"1px 3px","font-style":"normal","font-size":"90%"}};(function(){for(var n=0;n<10;n++){var o="scaleX(."+n+")";m[".MJXp-scale"+n]={"-webkit-transform":o,"-moz-transform":o,"-ms-transform":o,"-o-transform":o,transform:o}}})();var k=1000000;var c="V",l="H";g.Augment({settings:b.config.menuSettings,config:{styles:m},hideProcessedMath:false,maxStretchyParts:1000,Config:function(){if(!this.require){this.require=[]}this.SUPER(arguments).Config.call(this);var n=this.settings;if(n.scale){this.config.scale=n.scale}this.require.push(MathJax.OutputJax.extensionDir+"/MathEvents.js")},Startup:function(){j=MathJax.Extension.MathEvents.Event;a=MathJax.Extension.MathEvents.Touch;d=MathJax.Extension.MathEvents.Hover;this.ContextMenu=j.ContextMenu;this.Mousedown=j.AltContextMenu;this.Mouseover=d.Mouseover;this.Mouseout=d.Mouseout;this.Mousemove=d.Mousemove;var n=e.addElement(document.body,"div",{style:{width:"5in"}});this.pxPerInch=n.offsetWidth/5;n.parentNode.removeChild(n);return i.Styles(this.config.styles,["InitializePHTML",this])},InitializePHTML:function(){},preTranslate:function(p){var s=p.jax[this.id],t,q=s.length,u,r,v,o,n;for(t=0;tthis.PHTML.h){this.PHTML.h=q.PHTML.h}if(q.PHTML.d>this.PHTML.d){this.PHTML.d=q.PHTML.d}if(q.PHTML.t>this.PHTML.t){this.PHTML.t=q.PHTML.t}if(q.PHTML.b>this.PHTML.b){this.PHTML.b=q.PHTML.b}}}else{if(n.forceChild){e.addElement(p,"span")}}},PHTMLstretchChild:function(q,p,s){var r=this.data[q];if(r&&r.PHTMLcanStretch("Vertical",p,s)){var t=this.PHTML,o=r.PHTML,n=o.w;r.PHTMLstretchV(p,s);t.w+=o.w-n;if(o.h>t.h){t.h=o.h}if(o.d>t.d){t.d=o.d}}},PHTMLcreateSpan:function(n){if(!this.PHTML){this.PHTML={}}this.PHTML={w:0,h:0,d:0,l:0,r:0,t:0,b:0};if(this.inferred){return n}if(this.type==="mo"&&this.data.join("")==="\u222B"){g.lastIsInt=true}else{if(this.type!=="mspace"||this.width!=="negativethinmathspace"){g.lastIsInt=false}}if(!this.PHTMLspanID){this.PHTMLspanID=g.GetID()}var o=(this.id||"MJXp-Span-"+this.PHTMLspanID);return e.addElement(n,"span",{className:"MJXp-"+this.type,id:o})},PHTMLspanElement:function(){if(!this.PHTMLspanID){return null}return document.getElementById(this.id||"MJXp-Span-"+this.PHTMLspanID)},PHTMLhandleToken:function(o){var n=this.getValues("mathvariant");if(n.mathvariant!==h.VARIANT.NORMAL){o.className+=" "+g.VARIANT[n.mathvariant]}},PHTMLhandleStyle:function(n){if(this.style){n.style.cssText=this.style}},PHTMLhandleColor:function(n){if(this.mathcolor){n.style.color=this.mathcolor}if(this.mathbackground){n.style.backgroundColor=this.mathbackground}},PHTMLhandleScriptlevel:function(n){var o=this.Get("scriptlevel");if(o){n.className+=" MJXp-script"}},PHTMLhandleText:function(y,A){var v,p;var z=0,o=0,q=0;for(var s=0,r=A.length;s=55296&&p<56319){s++;p=(((p-55296)<<10)+(A.charCodeAt(s)-56320))+65536}var t=0.7,u=0.22,x=0.5;if(p<127){if(v.match(/[A-Za-ehik-or-xz0-9]/)){u=0}if(v.match(/[A-HK-Z]/)){x=0.67}else{if(v.match(/[IJ]/)){x=0.36}}if(v.match(/[acegm-su-z]/)){t=0.45}else{if(v.match(/[ij]/)){t=0.75}}if(v.match(/[ijlt]/)){x=0.28}}if(g.DELIMITERS[v]){x=g.DELIMITERS[v].w||0.4}if(t>z){z=t}if(u>o){o=u}q+=x}if(!this.CHML){this.PHTML={}}this.PHTML={h:0.9,d:0.3,w:q,l:0,r:0,t:z,b:o};e.addText(y,A)},PHTMLbboxFor:function(o){if(this.data[o]&&this.data[o].PHTML){return this.data[o].PHTML}return{w:0,h:0,d:0,l:0,r:0,t:0,b:0}},PHTMLcanStretch:function(q,o,p){if(this.isEmbellished()){var n=this.Core();if(n&&n!==this){return n.PHTMLcanStretch(q,o,p)}}return false},PHTMLstretchV:function(n,o){},PHTMLstretchH:function(n){},CoreParent:function(){var n=this;while(n&&n.isEmbellished()&&n.CoreMO()===this&&!n.isa(h.math)){n=n.Parent()}return n},CoreText:function(n){if(!n){return""}if(n.isEmbellished()){return n.CoreMO().data.join("")}while((n.isa(h.mrow)||n.isa(h.TeXAtom)||n.isa(h.mstyle)||n.isa(h.mphantom))&&n.data.length===1&&n.data[0]){n=n.data[0]}if(!n.isToken){return""}else{return n.data.join("")}}});h.chars.Augment({toPreviewHTML:function(n){var o=this.toString().replace(/[\u2061-\u2064]/g,"");this.PHTMLhandleText(n,o)}});h.entity.Augment({toPreviewHTML:function(n){var o=this.toString().replace(/[\u2061-\u2064]/g,"");this.PHTMLhandleText(n,o)}});h.math.Augment({toPreviewHTML:function(n){n=this.PHTMLdefaultSpan(n);if(this.Get("display")==="block"){n.className+=" MJXp-display"}return n}});h.mo.Augment({toPreviewHTML:function(o){o=this.PHTMLdefaultSpan(o);this.PHTMLadjustAccent(o);var n=this.getValues("lspace","rspace","scriptlevel","displaystyle","largeop");if(n.scriptlevel===0){this.PHTML.l=g.length2em(n.lspace);this.PHTML.r=g.length2em(n.rspace);o.style.marginLeft=g.Em(this.PHTML.l);o.style.marginRight=g.Em(this.PHTML.r)}else{this.PHTML.l=0.15;this.PHTML.r=0.1}if(n.displaystyle&&n.largeop){var p=e.Element("span",{className:"MJXp-largeop"});p.appendChild(o.firstChild);o.appendChild(p);this.PHTML.h*=1.2;this.PHTML.d*=1.2;if(this.data.join("")==="\u222B"){p.className+=" MJXp-int"}}return o},PHTMLadjustAccent:function(p){var o=this.CoreParent();if(o&&o.isa(h.munderover)&&this.CoreText(o.data[o.base]).length===1){var q=o.data[o.over],n=o.data[o.under];var s=this.data.join(""),r;if(q&&this===q.CoreMO()&&o.Get("accent")){r=g.REMAPACCENT[s]}else{if(n&&this===n.CoreMO()&&o.Get("accentunder")){r=g.REMAPACCENTUNDER[s]}}if(r){s=p.innerHTML=r}if(s.match(/[\u02C6-\u02DC\u00A8]/)){this.PHTML.acc=-0.52}else{if(s==="\u2192"){this.PHTML.acc=-0.15;this.PHTML.vec=true}}}},PHTMLcanStretch:function(q,o,p){if(!this.Get("stretchy")){return false}var r=this.data.join("");if(r.length>1){return false}r=g.DELIMITERS[r];var n=(r&&r.dir===q.substr(0,1));if(n){n=(this.PHTML.h!==o||this.PHTML.d!==p||(this.Get("minsize",true)||this.Get("maxsize",true)))}return n},PHTMLstretchV:function(p,u){var o=this.PHTMLspanElement(),t=this.PHTML;var n=this.getValues("symmetric","maxsize","minsize");if(n.symmetric){l=2*Math.max(p-0.25,u+0.25)}else{l=p+u}n.maxsize=g.length2em(n.maxsize,t.h+t.d);n.minsize=g.length2em(n.minsize,t.h+t.d);l=Math.max(n.minsize,Math.min(n.maxsize,l));var s=l/(t.h+t.d-0.3);var q=e.Element("span",{style:{"font-size":g.Em(s)}});if(s>1.25){var r=Math.ceil(1.25/s*10);q.className="MJXp-right MJXp-scale"+r;q.style.marginLeft=g.Em(t.w*(r/10-1)+0.07);t.w*=s*r/10}q.appendChild(o.firstChild);o.appendChild(q);if(n.symmetric){o.style.verticalAlign=g.Em(0.25*(1-s))}}});h.mspace.Augment({toPreviewHTML:function(q){q=this.PHTMLdefaultSpan(q);var o=this.getValues("height","depth","width");var n=g.length2em(o.width),p=g.length2em(o.height),s=g.length2em(o.depth);var r=this.PHTML;r.w=n;r.h=p;r.d=s;if(n<0){if(!g.lastIsInt){q.style.marginLeft=g.Em(n)}n=0}q.style.width=g.Em(n);q.style.height=g.Em(p+s);if(s){q.style.verticalAlign=g.Em(-s)}return q}});h.mpadded.Augment({toPreviewHTML:function(u){u=this.PHTMLdefaultSpan(u,{childSpans:true,className:"MJXp-box",forceChild:true});var o=u.firstChild;var v=this.getValues("width","height","depth","lspace","voffset");var s=this.PHTMLdimen(v.lspace);var q=0,n=0,t=s.len,r=-s.len,p=0;if(v.width!==""){s=this.PHTMLdimen(v.width,"w",0);if(s.pm){r+=s.len}else{u.style.width=g.Em(s.len)}}if(v.height!==""){s=this.PHTMLdimen(v.height,"h",0);if(!s.pm){q+=-this.PHTMLbboxFor(0).h}q+=s.len}if(v.depth!==""){s=this.PHTMLdimen(v.depth,"d",0);if(!s.pm){n+=-this.PHTMLbboxFor(0).d;p+=-s.len}n+=s.len}if(v.voffset!==""){s=this.PHTMLdimen(v.voffset);q-=s.len;n+=s.len;p+=s.len}if(q){o.style.marginTop=g.Em(q)}if(n){o.style.marginBottom=g.Em(n)}if(t){o.style.marginLeft=g.Em(t)}if(r){o.style.marginRight=g.Em(r)}if(p){u.style.verticalAlign=g.Em(p)}return u},PHTMLdimen:function(q,r,n){if(n==null){n=-k}q=String(q);var o=q.match(/width|height|depth/);var p=(o?this.PHTML[o[0].charAt(0)]:(r?this.PHTML[r]:0));return{len:g.length2em(q,p)||0,pm:!!q.match(/^[-+]/)}}});h.munderover.Augment({toPreviewHTML:function(r){var t=this.getValues("displaystyle","accent","accentunder","align");var n=this.data[this.base];if(!t.displaystyle&&n!=null&&(n.movablelimits||n.CoreMO().Get("movablelimits"))){r=h.msubsup.prototype.toPreviewHTML.call(this,r);r.className=r.className.replace(/munderover/,"msubsup");return r}r=this.PHTMLdefaultSpan(r,{childSpans:true,className:"",noBBox:true});var p=this.PHTMLbboxFor(this.over),v=this.PHTMLbboxFor(this.under),u=this.PHTMLbboxFor(this.base),s=this.PHTML,o=p.acc;if(this.data[this.over]){if(r.lastChild.firstChild){r.lastChild.firstChild.style.marginLeft=p.l=r.lastChild.firstChild.style.marginRight=p.r=0}var q=e.Element("span",{},[["span",{className:"MJXp-over"}]]);q.firstChild.appendChild(r.lastChild);if(r.childNodes.length>(this.data[this.under]?1:0)){q.firstChild.appendChild(r.firstChild)}this.data[this.over].PHTMLhandleScriptlevel(q.firstChild.firstChild);if(o!=null){if(p.vec){q.firstChild.firstChild.firstChild.style.fontSize="60%";p.h*=0.6;p.d*=0.6;p.w*=0.6}o=o-p.d+0.1;if(u.t!=null){o+=u.t-u.h}q.firstChild.firstChild.style.marginBottom=g.Em(o)}if(r.firstChild){r.insertBefore(q,r.firstChild)}else{r.appendChild(q)}}if(this.data[this.under]){if(r.lastChild.firstChild){r.lastChild.firstChild.style.marginLeft=v.l=r.lastChild.firstChild.marginRight=v.r=0}this.data[this.under].PHTMLhandleScriptlevel(r.lastChild)}s.w=Math.max(0.8*p.w,0.8*v.w,u.w);s.h=0.8*(p.h+p.d+(o||0))+u.h;s.d=u.d+0.8*(v.h+v.d);return r}});h.msubsup.Augment({toPreviewHTML:function(q){q=this.PHTMLdefaultSpan(q,{noBBox:true});if(!this.data[this.base]){if(q.firstChild){q.insertBefore(e.Element("span"),q.firstChild)}else{q.appendChild(e.Element("span"))}}var s=this.data[this.base],p=this.data[this.sub],n=this.data[this.sup];if(!s){s={bbox:{h:0.8,d:0.2}}}q.firstChild.style.marginRight=".05em";var o=Math.max(0.4,s.PHTML.h-0.4),u=Math.max(0.2,s.PHTML.d+0.1);var t=this.PHTML;if(n&&p){var r=e.Element("span",{className:"MJXp-script-box",style:{height:g.Em(o+n.PHTML.h*0.8+u+p.PHTML.d*0.8),"vertical-align":g.Em(-u-p.PHTML.d*0.8)}},[["span",{},[["span",{},[["span",{style:{"margin-bottom":g.Em(-(n.PHTML.d-0.05))}}]]]]],["span",{},[["span",{},[["span",{style:{"margin-top":g.Em(-(n.PHTML.h-0.05))}}]]]]]]);p.PHTMLhandleScriptlevel(r.firstChild);n.PHTMLhandleScriptlevel(r.lastChild);r.firstChild.firstChild.firstChild.appendChild(q.lastChild);r.lastChild.firstChild.firstChild.appendChild(q.lastChild);q.appendChild(r);t.h=Math.max(s.PHTML.h,n.PHTML.h*0.8+o);t.d=Math.max(s.PHTML.d,p.PHTML.d*0.8+u);t.w=s.PHTML.w+Math.max(n.PHTML.w,p.PHTML.w)+0.07}else{if(n){q.lastChild.style.verticalAlign=g.Em(o);n.PHTMLhandleScriptlevel(q.lastChild);t.h=Math.max(s.PHTML.h,n.PHTML.h*0.8+o);t.d=Math.max(s.PHTML.d,n.PHTML.d*0.8-o);t.w=s.PHTML.w+n.PHTML.w+0.07}else{if(p){q.lastChild.style.verticalAlign=g.Em(-u);p.PHTMLhandleScriptlevel(q.lastChild);t.h=Math.max(s.PHTML.h,p.PHTML.h*0.8-u);t.d=Math.max(s.PHTML.d,p.PHTML.d*0.8+u);t.w=s.PHTML.w+p.PHTML.w+0.07}}}return q}});h.mfrac.Augment({toPreviewHTML:function(r){r=this.PHTMLdefaultSpan(r,{childSpans:true,className:"MJXp-box",forceChild:true,noBBox:true});var o=this.getValues("linethickness","displaystyle");if(!o.displaystyle){if(this.data[0]){this.data[0].PHTMLhandleScriptlevel(r.firstChild)}if(this.data[1]){this.data[1].PHTMLhandleScriptlevel(r.lastChild)}}var n=e.Element("span",{className:"MJXp-box"},[["span",{className:"MJXp-denom"},[["span",{},[["span",{className:"MJXp-rule",style:{height:"1em"}}]]],["span"]]]]);n.firstChild.lastChild.appendChild(r.lastChild);r.appendChild(n);var s=this.PHTMLbboxFor(0),p=this.PHTMLbboxFor(1),v=this.PHTML;v.w=Math.max(s.w,p.w)*0.8;v.h=s.h+s.d+0.1+0.25;v.d=p.h+p.d-0.25;v.l=v.r=0.125;o.linethickness=Math.max(0,g.length2em(o.linethickness||"0",0));if(o.linethickness){var u=n.firstChild.firstChild.firstChild;var q=g.Em(o.linethickness);u.style.borderTop="none";u.style.borderBottom=(o.linethickness<0.15?"1px":q)+" solid";u.style.margin=q+" 0";q=o.linethickness;n.style.marginTop=g.Em(3*q-1.2);r.style.verticalAlign=g.Em(1.5*q+0.1);v.h+=1.5*q-0.1;v.d+=1.5*q}else{n.style.marginTop="-.7em"}return r}});h.msqrt.Augment({toPreviewHTML:function(n){n=this.PHTMLdefaultSpan(n,{childSpans:true,className:"MJXp-box",forceChild:true,noBBox:true});this.PHTMLlayoutRoot(n,n.firstChild);return n},PHTMLlayoutRoot:function(u,n){var v=this.PHTMLbboxFor(0);var q=Math.ceil((v.h+v.d+0.14)*100),w=g.Em(14/q);var r=e.Element("span",{className:"MJXp-surd"},[["span",{style:{"font-size":q+"%","margin-top":w}},["\u221A"]]]);var s=e.Element("span",{className:"MJXp-root"},[["span",{className:"MJXp-rule",style:{"border-top":".08em solid"}}]]);var p=(1.2/2.2)*q/100;if(q>150){var o=Math.ceil(150/q*10);r.firstChild.className="MJXp-right MJXp-scale"+o;r.firstChild.style.marginLeft=g.Em(p*(o/10-1)/q*100);p=p*o/10;s.firstChild.style.borderTopWidth=g.Em(0.08/Math.sqrt(o/10))}s.appendChild(n);u.appendChild(r);u.appendChild(s);this.PHTML.h=v.h+0.18;this.PHTML.d=v.d;this.PHTML.w=v.w+p;return u}});h.mroot.Augment({toPreviewHTML:function(q){q=this.PHTMLdefaultSpan(q,{childSpans:true,className:"MJXp-box",forceChild:true,noBBox:true});var p=this.PHTMLbboxFor(1),n=q.removeChild(q.lastChild);var t=this.PHTMLlayoutRoot(e.Element("span"),q.firstChild);n.className="MJXp-script";var u=parseInt(t.firstChild.firstChild.style.fontSize);var o=0.55*(u/120)+p.d*0.8,s=-0.6*(u/120);if(u>150){s*=0.95*Math.ceil(150/u*10)/10}n.style.marginRight=g.Em(s);n.style.verticalAlign=g.Em(o);if(-s>p.w*0.8){n.style.marginLeft=g.Em(-s-p.w*0.8)}q.appendChild(n);q.appendChild(t);this.PHTML.w+=Math.max(0,p.w*0.8+s);this.PHTML.h=Math.max(this.PHTML.h,p.h*0.8+o);return q},PHTMLlayoutRoot:h.msqrt.prototype.PHTMLlayoutRoot});h.mfenced.Augment({toPreviewHTML:function(q){q=this.PHTMLcreateSpan(q);this.PHTMLhandleStyle(q);this.PHTMLhandleColor(q);this.addFakeNodes();this.PHTMLaddChild(q,"open",{});for(var p=0,n=this.data.length;ps){s=x.w}}}var o=this.PHTML;o.w=s;o.h=y/2+0.25;o.d=y/2-0.25;o.l=o.r=0.125;return E}});h.mlabeledtr.Augment({PHTMLdefaultSpan:function(q,o){if(!o){o={}}q=this.PHTMLcreateSpan(q);this.PHTMLhandleStyle(q);this.PHTMLhandleColor(q);if(this.isToken){this.PHTMLhandleToken(q)}for(var p=1,n=this.data.length;p/g,"")}catch(k){if(!k.restart){throw k}return MathJax.Callback.After(["HandleMML",this,l],k.restart)}n.setAttribute("data-mathml",i);j=f.addElement(n,"span",{isMathJax:true,unselectable:"on",className:"MJX_Assistive_MathML"+(h.root.Get("display")==="block"?" MJX_Assistive_MathML_Block":"")});try{j.innerHTML=i}catch(k){}n.style.position="relative";n.setAttribute("role","presentation");n.firstChild.setAttribute("aria-hidden","true");j.setAttribute("role","presentation")}l.i++}l.callback()}};b.Startup.signal.Post("AssistiveMML Ready")})(MathJax.Ajax,MathJax.Callback,MathJax.Hub,MathJax.HTML);MathJax.Callback.Queue(["Require",MathJax.Ajax,"[MathJax]/extensions/toMathML.js"],["loadComplete",MathJax.Ajax,"[MathJax]/extensions/AssistiveMML.js"],function(){MathJax.Hub.Register.StartupHook("End Config",["Config",MathJax.Extension.AssistiveMML])});
+!function(a,b){var c,d,e=a.config.menuSettings,f=Function.prototype.bind?function(a,b){return a.bind(b)}:function(a,b){return function(){a.apply(b,arguments)}},g=Object.keys||function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b},h=MathJax.Ajax.config.path;h.a11y||(h.a11y=a.config.root+"/extensions/a11y");var i=b["accessibility-menu"]={version:"1.5.0",prefix:"",defaults:{},modules:[],MakeOption:function(a){return i.prefix+a},GetOption:function(a){return e[i.MakeOption(a)]},AddDefaults:function(){for(var a,b=g(i.defaults),c=0;a=b[c];c++){var d=i.MakeOption(a);void 0===e[d]&&(e[d]=i.defaults[a])}},AddMenu:function(){for(var a,b=Array(this.modules.length),e=0;a=this.modules[e];e++)b[e]=a.placeHolder;var f=d.FindId("Accessibility");if(f)b.unshift(c.RULE()),f.submenu.items.push.apply(f.submenu.items,b);else{var g=(d.FindId("Settings","Renderer")||{}).submenu;g&&(b.unshift(c.RULE()),b.unshift(g.items.pop()),b.unshift(g.items.pop())),b.unshift("Accessibility");var f=c.SUBMENU.apply(c.SUBMENU,b),h=d.IndexOfId("Locale");h?d.items.splice(h,0,f):d.items.push(c.RULE(),f)}},Register:function(a){i.defaults[a.option]=!1,i.modules.push(a)},Startup:function(){c=MathJax.Menu.ITEM,d=MathJax.Menu.menu;for(var a,b=0;a=this.modules[b];b++)a.CreateMenu();this.AddMenu()},LoadExtensions:function(){for(var b,c=[],d=0;b=this.modules[d];d++)e[b.option]&&c.push(b.module);return c.length?a.Startup.loadArray(c):null}},j=MathJax.Extension.ModuleLoader=MathJax.Object.Subclass({option:"",name:["",""],module:"",placeHolder:null,submenu:!1,extension:null,Init:function(a,b,c,d,e){this.option=a,this.name=[b.replace(/ /g,""),b],this.module=c,this.extension=d,this.submenu=e||!1},CreateMenu:function(){var a=f(this.Load,this);this.submenu?this.placeHolder=c.SUBMENU(this.name,c.CHECKBOX(["Activate","Activate"],i.MakeOption(this.option),{action:a}),c.RULE(),c.COMMAND(["OptionsWhenActive","(Options when Active)"],null,{disabled:!0})):this.placeHolder=c.CHECKBOX(this.name,i.MakeOption(this.option),{action:a})},Load:function(){a.Queue(["Require",MathJax.Ajax,this.module,["Enable",this]])},Enable:function(a){var b=MathJax.Extension[this.extension];b&&(b.Enable(!0,!0),MathJax.Menu.saveCookie())}});i.Register(j("collapsible","Collapsible Math","[a11y]/collapsible.js","collapsible")),i.Register(j("autocollapse","Auto Collapse","[a11y]/auto-collapse.js","auto-collapse")),i.Register(j("explorer","Explorer","[a11y]/explorer.js","explorer",!0)),i.AddDefaults(),a.Register.StartupHook("End Extensions",function(){a.Register.StartupHook("MathMenu Ready",function(){i.Startup(),a.Startup.signal.Post("Accessibility Menu Ready")},5)},5),MathJax.Hub.Register.StartupHook("End Cookie",function(){MathJax.Callback.Queue(["LoadExtensions",i],["loadComplete",MathJax.Ajax,"[a11y]/accessibility-menu.js"])})}(MathJax.Hub,MathJax.Extension);MathJax.Ajax.loadComplete("[MathJax]/config/AM_CHTML-full.js");
diff --git a/spyder/plugins/help/utils/js/mathjax/config/AM_CHTML.js b/spyder/plugins/help/utils/js/mathjax/config/AM_CHTML.js
new file mode 100644
index 00000000000..f280fc2c50e
--- /dev/null
+++ b/spyder/plugins/help/utils/js/mathjax/config/AM_CHTML.js
@@ -0,0 +1,49 @@
+/*
+ * /MathJax/config/AM_CHTML.js
+ *
+ * Copyright (c) 2010-2018 The MathJax Consortium
+ *
+ * Part of the MathJax library.
+ * See http://www.mathjax.org for details.
+ *
+ * Licensed under the Apache License, Version 2.0;
+ * you may not use this file except in compliance with the License.
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+MathJax.Ajax.Preloading(
+ "[MathJax]/jax/input/AsciiMath/config.js",
+ "[MathJax]/jax/output/CommonHTML/config.js",
+ "[MathJax]/jax/output/PreviewHTML/config.js",
+ "[MathJax]/extensions/asciimath2jax.js",
+ "[MathJax]/extensions/MathEvents.js",
+ "[MathJax]/extensions/MathZoom.js",
+ "[MathJax]/extensions/MathMenu.js",
+ "[MathJax]/jax/element/mml/jax.js",
+ "[MathJax]/extensions/toMathML.js",
+ "[MathJax]/jax/input/AsciiMath/jax.js",
+ "[MathJax]/jax/output/PreviewHTML/jax.js",
+ "[MathJax]/extensions/fast-preview.js",
+ "[MathJax]/extensions/AssistiveMML.js",
+ "[MathJax]/extensions/a11y/accessibility-menu.js"
+);
+
+MathJax.Hub.Config({
+ extensions: ['[a11y]/accessibility-menu.js']
+});
+
+MathJax.InputJax.AsciiMath=MathJax.InputJax({id:"AsciiMath",version:"2.7.5",directory:MathJax.InputJax.directory+"/AsciiMath",extensionDir:MathJax.InputJax.extensionDir+"/AsciiMath",config:{fixphi:true,useMathMLspacing:true,displaystyle:true,decimalsign:"."}});MathJax.InputJax.AsciiMath.Register("math/asciimath");MathJax.InputJax.AsciiMath.loadComplete("config.js");
+MathJax.OutputJax.CommonHTML=MathJax.OutputJax({id:"CommonHTML",version:"2.7.5",directory:MathJax.OutputJax.directory+"/CommonHTML",extensionDir:MathJax.OutputJax.extensionDir+"/CommonHTML",autoloadDir:MathJax.OutputJax.directory+"/CommonHTML/autoload",fontDir:MathJax.OutputJax.directory+"/CommonHTML/fonts",webfontDir:MathJax.OutputJax.fontDir+"/HTML-CSS",config:{matchFontHeight:true,scale:100,minScaleAdjust:50,mtextFontInherit:false,undefinedFamily:"STIXGeneral,'Cambria Math','Arial Unicode MS',serif",EqnChunk:(MathJax.Hub.Browser.isMobile?20:100),EqnChunkFactor:1.5,EqnChunkDelay:100,linebreaks:{automatic:false,width:"container"}}});if(!MathJax.Hub.config.delayJaxRegistration){MathJax.OutputJax.CommonHTML.Register("jax/mml")}MathJax.OutputJax.CommonHTML.loadComplete("config.js");
+MathJax.OutputJax.PreviewHTML=MathJax.OutputJax({id:"PreviewHTML",version:"2.7.5",directory:MathJax.OutputJax.directory+"/PreviewHTML",extensionDir:MathJax.OutputJax.extensionDir+"/PreviewHTML",noFastPreview:true,config:{scale:100,minScaleAdjust:50,mtextFontInherit:false,linebreaks:{automatic:false,width:"container"}}});if(!MathJax.Hub.config.delayJaxRegistration){MathJax.OutputJax.PreviewHTML.Register("jax/mml")}MathJax.OutputJax.PreviewHTML.loadComplete("config.js");
+MathJax.Extension.asciimath2jax={version:"2.7.5",config:{delimiters:[["`","`"]],skipTags:["script","noscript","style","textarea","pre","code","annotation","annotation-xml"],ignoreClass:"asciimath2jax_ignore",processClass:"asciimath2jax_process",preview:"AsciiMath"},ignoreTags:{br:(MathJax.Hub.Browser.isMSIE&&document.documentMode<9?"\n":" "),wbr:"","#comment":""},PreProcess:function(a){if(!this.configured){this.config=MathJax.Hub.CombineConfig("asciimath2jax",this.config);if(this.config.Augment){MathJax.Hub.Insert(this,this.config.Augment)}this.configured=true}if(typeof(a)==="string"){a=document.getElementById(a)}if(!a){a=document.body}if(this.createPatterns()){this.scanElement(a,a.nextSibling)}},createPatterns:function(){var d=[],c,a,b=this.config;this.match={};if(b.delimiters.length===0){return false}for(c=0,a=b.delimiters.length;c0){this.HoverFadeTimer(q,q.hover.inc);return}s.parentNode.removeChild(s);if(r){r.parentNode.removeChild(r)}if(q.hover.remove){clearTimeout(q.hover.remove)}delete q.hover},HoverFadeTimer:function(q,s,r){q.hover.inc=s;if(!q.hover.timer){q.hover.timer=setTimeout(g(["HoverFade",this,q]),(r||o.fadeDelay))}},HoverMenu:function(q){if(!q){q=window.event}return b[this.jax].ContextMenu(q,this.math,true)},ClearHover:function(q){if(q.hover.remove){clearTimeout(q.hover.remove)}if(q.hover.timer){clearTimeout(q.hover.timer)}f.ClearHoverTimer();delete q.hover},Px:function(q){if(Math.abs(q)<0.006){return"0px"}return q.toFixed(2).replace(/\.?0+$/,"")+"px"},getImages:function(){if(k.discoverable){var q=new Image();q.src=o.button.src}}};var a=c.Touch={last:0,delay:500,start:function(r){var q=new Date().getTime();var s=(q-a.lastt){z.style.height=t+"px";z.style.width=(x.zW+this.scrollSize)+"px"}if(z.offsetWidth>l){z.style.width=l+"px";z.style.height=(x.zH+this.scrollSize)+"px"}}if(this.operaPositionBug){z.style.width=Math.min(l,x.zW)+"px"}if(z.offsetWidth>m&&z.offsetWidth-m=9);h.msiePositionBug=!m;h.msieSizeBug=l.versionAtLeast("7.0")&&(!document.documentMode||n===7||n===8);h.msieZIndexBug=(n<=7);h.msieInlineBlockAlignBug=(n<=7);h.msieTrapEventBug=!window.addEventListener;if(document.compatMode==="BackCompat"){h.scrollSize=52}if(m){delete i.styles["#MathJax_Zoom"].filter}},Opera:function(l){h.operaPositionBug=true;h.operaRefreshBug=true}});h.topImg=(h.msieInlineBlockAlignBug?d.Element("img",{style:{width:0,height:0,position:"relative"},src:"about:blank"}):d.Element("span",{style:{width:0,height:0,display:"inline-block"}}));if(h.operaPositionBug||h.msieTopBug){h.topImg.style.border="1px solid"}MathJax.Callback.Queue(["StartupHook",MathJax.Hub.Register,"Begin Styles",{}],["Styles",f,i.styles],["Post",a.Startup.signal,"MathZoom Ready"],["loadComplete",f,"[MathJax]/extensions/MathZoom.js"])})(MathJax.Hub,MathJax.HTML,MathJax.Ajax,MathJax.OutputJax["HTML-CSS"],MathJax.OutputJax.NativeMML);
+(function(f,o,q,e,r){var p="2.7.5";var d=MathJax.Callback.Signal("menu");MathJax.Extension.MathMenu={version:p,signal:d};var t=function(u){return MathJax.Localization._.apply(MathJax.Localization,[["MathMenu",u]].concat([].slice.call(arguments,1)))};var i=MathJax.Object.isArray;var a=f.Browser.isPC,l=f.Browser.isMSIE,m=((document.documentMode||0)>8);var j=(a?null:"5px");var s=f.CombineConfig("MathMenu",{delay:150,showRenderer:true,showMathPlayer:true,showFontMenu:false,showContext:false,showDiscoverable:false,showLocale:true,showLocaleURL:false,semanticsAnnotations:{TeX:["TeX","LaTeX","application/x-tex"],StarMath:["StarMath 5.0"],Maple:["Maple"],ContentMathML:["MathML-Content","application/mathml-content+xml"],OpenMath:["OpenMath"]},windowSettings:{status:"no",toolbar:"no",locationbar:"no",menubar:"no",directories:"no",personalbar:"no",resizable:"yes",scrollbars:"yes",width:400,height:300,left:Math.round((screen.width-400)/2),top:Math.round((screen.height-300)/3)},styles:{"#MathJax_About":{position:"fixed",left:"50%",width:"auto","text-align":"center",border:"3px outset",padding:"1em 2em","background-color":"#DDDDDD",color:"black",cursor:"default","font-family":"message-box","font-size":"120%","font-style":"normal","text-indent":0,"text-transform":"none","line-height":"normal","letter-spacing":"normal","word-spacing":"normal","word-wrap":"normal","white-space":"nowrap","float":"none","z-index":201,"border-radius":"15px","-webkit-border-radius":"15px","-moz-border-radius":"15px","-khtml-border-radius":"15px","box-shadow":"0px 10px 20px #808080","-webkit-box-shadow":"0px 10px 20px #808080","-moz-box-shadow":"0px 10px 20px #808080","-khtml-box-shadow":"0px 10px 20px #808080",filter:"progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')"},"#MathJax_About.MathJax_MousePost":{outline:"none"},".MathJax_Menu":{position:"absolute","background-color":"white",color:"black",width:"auto",padding:(a?"2px":"5px 0px"),border:"1px solid #CCCCCC",margin:0,cursor:"default",font:"menu","text-align":"left","text-indent":0,"text-transform":"none","line-height":"normal","letter-spacing":"normal","word-spacing":"normal","word-wrap":"normal","white-space":"nowrap","float":"none","z-index":201,"border-radius":j,"-webkit-border-radius":j,"-moz-border-radius":j,"-khtml-border-radius":j,"box-shadow":"0px 10px 20px #808080","-webkit-box-shadow":"0px 10px 20px #808080","-moz-box-shadow":"0px 10px 20px #808080","-khtml-box-shadow":"0px 10px 20px #808080",filter:"progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')"},".MathJax_MenuItem":{padding:(a?"2px 2em":"1px 2em"),background:"transparent"},".MathJax_MenuArrow":{position:"absolute",right:".5em","padding-top":".25em",color:"#666666","font-family":(l?"'Arial unicode MS'":null),"font-size":".75em"},".MathJax_MenuActive .MathJax_MenuArrow":{color:"white"},".MathJax_MenuArrow.RTL":{left:".5em",right:"auto"},".MathJax_MenuCheck":{position:"absolute",left:".7em","font-family":(l?"'Arial unicode MS'":null)},".MathJax_MenuCheck.RTL":{right:".7em",left:"auto"},".MathJax_MenuRadioCheck":{position:"absolute",left:(a?"1em":".7em")},".MathJax_MenuRadioCheck.RTL":{right:(a?"1em":".7em"),left:"auto"},".MathJax_MenuLabel":{padding:(a?"2px 2em 4px 1.33em":"1px 2em 3px 1.33em"),"font-style":"italic"},".MathJax_MenuRule":{"border-top":(a?"1px solid #CCCCCC":"1px solid #DDDDDD"),margin:(a?"4px 1px 0px":"4px 3px")},".MathJax_MenuDisabled":{color:"GrayText"},".MathJax_MenuActive":{"background-color":(a?"Highlight":"#606872"),color:(a?"HighlightText":"white")},".MathJax_MenuDisabled:focus, .MathJax_MenuLabel:focus":{"background-color":"#E8E8E8"},".MathJax_ContextMenu:focus":{outline:"none"},".MathJax_ContextMenu .MathJax_MenuItem:focus":{outline:"none"},"#MathJax_AboutClose":{top:".2em",right:".2em"},".MathJax_Menu .MathJax_MenuClose":{top:"-10px",left:"-10px"},".MathJax_MenuClose":{position:"absolute",cursor:"pointer",display:"inline-block",border:"2px solid #AAA","border-radius":"18px","-webkit-border-radius":"18px","-moz-border-radius":"18px","-khtml-border-radius":"18px","font-family":"'Courier New',Courier","font-size":"24px",color:"#F0F0F0"},".MathJax_MenuClose span":{display:"block","background-color":"#AAA",border:"1.5px solid","border-radius":"18px","-webkit-border-radius":"18px","-moz-border-radius":"18px","-khtml-border-radius":"18px","line-height":0,padding:"8px 0 6px"},".MathJax_MenuClose:hover":{color:"white!important",border:"2px solid #CCC!important"},".MathJax_MenuClose:hover span":{"background-color":"#CCC!important"},".MathJax_MenuClose:hover:focus":{outline:"none"}}});var n,k,b;f.Register.StartupHook("MathEvents Ready",function(){n=MathJax.Extension.MathEvents.Event.False;k=MathJax.Extension.MathEvents.Hover;b=MathJax.Extension.MathEvents.Event.KEY});var h=MathJax.Object.Subclass({Keydown:function(u,v){switch(u.keyCode){case b.ESCAPE:this.Remove(u,v);break;case b.RIGHT:this.Right(u,v);break;case b.LEFT:this.Left(u,v);break;case b.UP:this.Up(u,v);break;case b.DOWN:this.Down(u,v);break;case b.RETURN:case b.SPACE:this.Space(u,v);break;default:return;break}return n(u)},Escape:function(u,v){},Right:function(u,v){},Left:function(u,v){},Up:function(u,v){},Down:function(u,v){},Space:function(u,v){}},{});var g=MathJax.Menu=h.Subclass({version:p,items:[],posted:false,title:null,margin:5,Init:function(u){this.items=[].slice.call(arguments,0)},With:function(u){if(u){f.Insert(this,u)}return this},Post:function(M,E,B){if(!M){M=window.event||{}}var I=document.getElementById("MathJax_MenuFrame");if(!I){I=g.Background(this);delete c.lastItem;delete c.lastMenu;delete g.skipUp;d.Post(["post",g.jax]);g.isRTL=(MathJax.Localization.fontDirection()==="rtl")}var v=o.Element("div",{onmouseup:g.Mouseup,ondblclick:n,ondragstart:n,onselectstart:n,oncontextmenu:n,menuItem:this,className:"MathJax_Menu",onkeydown:g.Keydown,role:"menu"});if(M.type==="contextmenu"||M.type==="mouseover"){v.className+=" MathJax_ContextMenu"}if(!B){MathJax.Localization.setCSS(v)}for(var N=0,K=this.items.length;NA-this.margin){H=A-v.offsetWidth-this.margin}if(g.isMobile){H=Math.max(5,H-Math.floor(v.offsetWidth/2));F-=20}g.skipUp=M.isContextMenu}else{var z="left",J=E.offsetWidth;H=(g.isMobile?30:J-2);F=0;while(E&&E!==I){H+=E.offsetLeft;F+=E.offsetTop;E=E.parentNode}if(!g.isMobile){if((g.isRTL&&H-J-v.offsetWidth>this.margin)||(!g.isRTL&&H+v.offsetWidth>A-this.margin)){z="right";H=Math.max(this.margin,H-J-v.offsetWidth+6)}}if(!a){v.style["borderRadiusTop"+z]=0;v.style["WebkitBorderRadiusTop"+z]=0;v.style["MozBorderRadiusTop"+z]=0;v.style["KhtmlBorderRadiusTop"+z]=0}}v.style.left=H+"px";v.style.top=F+"px";if(document.selection&&document.selection.empty){document.selection.empty()}var G=window.pageXOffset||document.documentElement.scrollLeft;var D=window.pageYOffset||document.documentElement.scrollTop;g.Focus(v);if(M.type==="keydown"){g.skipMouseoverFromKey=true;setTimeout(function(){delete g.skipMouseoverFromKey},s.delay)}window.scrollTo(G,D);return n(M)},Remove:function(u,v){d.Post(["unpost",g.jax]);var w=document.getElementById("MathJax_MenuFrame");if(w){w.parentNode.removeChild(w);if(this.msieFixedPositionBug){detachEvent("onresize",g.Resize)}}if(g.jax.hover){delete g.jax.hover.nofade;k.UnHover(g.jax)}g.Unfocus(v);if(u.type==="mousedown"){g.CurrentNode().blur()}return n(u)},Find:function(u){return this.FindN(1,u,[].slice.call(arguments,1))},FindId:function(u){return this.FindN(0,u,[].slice.call(arguments,1))},FindN:function(y,v,x){for(var w=0,u=this.items.length;w0){u.oldTabIndex=u.tabIndex}u.tabIndex=-1}},SetTabIndex:function(){var v=g.AllNodes();for(var w=0,u;u=v[w];w++){if(u.oldTabIndex!==undefined){u.tabIndex=u.oldTabIndex;delete u.oldTabIndex}else{u.tabIndex=f.getTabOrder(u)}}},Mod:function(u,v){return((u%v)+v)%v},IndexOf:(Array.prototype.indexOf?function(u,v,w){return u.indexOf(v,w)}:function(u,x,y){for(var w=(y||0),v=u.length;w=0&&c.GetMenuNode(w).menuItem!==v[u].menuItem){v[u].menuItem.posted=false;v[u].parentNode.removeChild(v[u]);u--}},Touchstart:function(u,v){return this.TouchEvent(u,v,"Mousedown")},Touchend:function(u,v){return this.TouchEvent(u,v,"Mouseup")},TouchEvent:function(v,w,u){if(this!==c.lastItem){if(c.lastMenu){g.Event(v,c.lastMenu,"Mouseout")}g.Event(v,w,"Mouseover",true);c.lastItem=this;c.lastMenu=w}if(this.nativeTouch){return null}g.Event(v,w,u);return false},Remove:function(u,v){v=v.parentNode.menuItem;return v.Remove(u,v)},With:function(u){if(u){f.Insert(this,u)}return this},isRTL:function(){return g.isRTL},rtlClass:function(){return(this.isRTL()?" RTL":"")}},{GetMenuNode:function(u){return u.parentNode}});g.ENTRY=g.ITEM.Subclass({role:"menuitem",Attributes:function(u){u=f.Insert({onmouseover:g.Mouseover,onmouseout:g.Mouseout,onmousedown:g.Mousedown,onkeydown:g.Keydown,"aria-disabled":!!this.disabled},u);u=this.SUPER(arguments).Attributes.call(this,u);if(this.disabled){u.className+=" MathJax_MenuDisabled"}return u},MoveVertical:function(u,E,w){var x=c.GetMenuNode(E);var D=[];for(var z=0,C=x.menuItem.items,y;y=C[z];z++){if(!y.hidden){D.push(y)}}var B=g.IndexOf(D,this);if(B===-1){return}var A=D.length;var v=x.childNodes;do{B=g.Mod(w(B),A)}while(D[B].hidden||!v[B].role||v[B].role==="separator");this.Deactivate(E);D[B].Activate(u,v[B])},Up:function(v,u){this.MoveVertical(v,u,function(w){return w-1})},Down:function(v,u){this.MoveVertical(v,u,function(w){return w+1})},Right:function(v,u){this.MoveHorizontal(v,u,g.Right,!this.isRTL())},Left:function(v,u){this.MoveHorizontal(v,u,g.Left,this.isRTL())},MoveHorizontal:function(A,z,u,B){var x=c.GetMenuNode(z);if(x.menuItem===g.menu&&A.shiftKey){u(A,z)}if(B){return}if(x.menuItem!==g.menu){this.Deactivate(z)}var v=x.previousSibling.childNodes;var y=v.length;while(y--){var w=v[y];if(w.menuItem.submenu&&w.menuItem.submenu===x.menuItem){g.Focus(w);break}}this.RemoveSubmenus(z)},Space:function(u,v){this.Mouseup(u,v)},Activate:function(u,v){this.Deactivate(v);if(!this.disabled){v.className+=" MathJax_MenuActive"}this.DeactivateSubmenus(v);g.Focus(v)},Deactivate:function(u){u.className=u.className.replace(/ MathJax_MenuActive/,"")}});g.ITEM.COMMAND=g.ENTRY.Subclass({action:function(){},Init:function(u,w,v){if(!i(u)){u=[u,u]}this.name=u;this.action=w;this.With(v)},Label:function(u,v){return[this.Name()]},Mouseup:function(u,v){if(!this.disabled){this.Remove(u,v);d.Post(["command",this]);this.action.call(this,u)}return n(u)}});g.ITEM.SUBMENU=g.ENTRY.Subclass({submenu:null,marker:"\u25BA",markerRTL:"\u25C4",Attributes:function(u){u=f.Insert({"aria-haspopup":"true"},u);u=this.SUPER(arguments).Attributes.call(this,u);return u},Init:function(u,w){if(!i(u)){u=[u,u]}this.name=u;var v=1;if(!(w instanceof g.ITEM)){this.With(w),v++}this.submenu=g.apply(g,[].slice.call(arguments,v))},Label:function(u,v){this.submenu.posted=false;return[this.Name()+" ",["span",{className:"MathJax_MenuArrow"+this.rtlClass()},[this.isRTL()?this.markerRTL:this.marker]]]},Timer:function(u,v){this.ClearTimer();u={type:u.type,clientX:u.clientX,clientY:u.clientY};this.timer=setTimeout(e(["Mouseup",this,u,v]),s.delay)},ClearTimer:function(){if(this.timer){clearTimeout(this.timer)}},Touchend:function(v,x){var w=this.submenu.posted;var u=this.SUPER(arguments).Touchend.apply(this,arguments);if(w){this.Deactivate(x);delete c.lastItem;delete c.lastMenu}return u},Mouseout:function(u,v){if(!this.submenu.posted){this.Deactivate(v)}this.ClearTimer()},Mouseover:function(u,v){this.Activate(u,v)},Mouseup:function(u,v){if(!this.disabled){if(!this.submenu.posted){this.ClearTimer();this.submenu.Post(u,v,this.ltr);g.Focus(v)}else{this.DeactivateSubmenus(v)}}return n(u)},Activate:function(u,v){if(!this.disabled){this.Deactivate(v);v.className+=" MathJax_MenuActive"}if(!this.submenu.posted){this.DeactivateSubmenus(v);if(!g.isMobile){this.Timer(u,v)}}g.Focus(v)},MoveVertical:function(w,v,u){this.ClearTimer();this.SUPER(arguments).MoveVertical.apply(this,arguments)},MoveHorizontal:function(w,y,v,x){if(!x){this.SUPER(arguments).MoveHorizontal.apply(this,arguments);return}if(this.disabled){return}if(!this.submenu.posted){this.Activate(w,y);return}var u=c.GetMenuNode(y).nextSibling.childNodes;if(u.length>0){this.submenu.items[0].Activate(w,u[0])}}});g.ITEM.RADIO=g.ENTRY.Subclass({variable:null,marker:(a?"\u25CF":"\u2713"),role:"menuitemradio",Attributes:function(v){var u=s.settings[this.variable]===this.value?"true":"false";v=f.Insert({"aria-checked":u},v);v=this.SUPER(arguments).Attributes.call(this,v);return v},Init:function(v,u,w){if(!i(v)){v=[v,v]}this.name=v;this.variable=u;this.With(w);if(this.value==null){this.value=this.name[0]}},Label:function(v,w){var u={className:"MathJax_MenuRadioCheck"+this.rtlClass()};if(s.settings[this.variable]!==this.value){u={style:{display:"none"}}}return[["span",u,[this.marker]]," "+this.Name()]},Mouseup:function(x,y){if(!this.disabled){var z=y.parentNode.childNodes;for(var v=0,u=z.length;v/g,">");var y=t("EqSource","MathJax Equation Source");if(g.isMobile){u.document.open();u.document.write(""+y+" ");u.document.write(""+z+"
");u.document.write("
");u.document.write("");u.document.close()}else{u.document.open();u.document.write(""+y+" ");u.document.write(""+z+"
");u.document.write("");u.document.close();var v=u.document.body.firstChild;setTimeout(function(){var B=(u.outerHeight-u.innerHeight)||30,A=(u.outerWidth-u.innerWidth)||30,w,E;A=Math.max(140,Math.min(Math.floor(0.5*screen.width),v.offsetWidth+A+25));B=Math.max(40,Math.min(Math.floor(0.5*screen.height),v.offsetHeight+B+25));if(g.prototype.msieHeightBug){B+=35}u.resizeTo(A,B);var D;try{D=x.screenX}catch(C){}if(x&&D!=null){w=Math.max(0,Math.min(x.screenX-Math.floor(A/2),screen.width-A-20));E=Math.max(0,Math.min(x.screenY-Math.floor(B/2),screen.height-B-20));u.moveTo(w,E)}},50)}};g.Scale=function(){var z=["CommonHTML","HTML-CSS","SVG","NativeMML","PreviewHTML"],u=z.length,y=100,w,v;for(w=0;w7;g.Augment({margin:20,msieBackgroundBug:((document.documentMode||0)<9),msieFixedPositionBug:(v||!w),msieAboutBug:v,msieHeightBug:((document.documentMode||0)<9)});if(m){delete s.styles["#MathJax_About"].filter;delete s.styles[".MathJax_Menu"].filter}},Firefox:function(u){g.skipMouseover=u.isMobile&&u.versionAtLeast("6.0");g.skipMousedown=u.isMobile}});g.isMobile=f.Browser.isMobile;g.noContextMenu=f.Browser.noContextMenu;g.CreateLocaleMenu=function(){if(!g.menu){return}var z=g.menu.Find("Language").submenu,w=z.items;var v=[],B=MathJax.Localization.strings;for(var A in B){if(B.hasOwnProperty(A)){v.push(A)}}v=v.sort();z.items=[];for(var x=0,u=v.length;x0||this.Get("scriptlevel")>0)&&g>=0){return""}return this.TEXSPACELENGTH[Math.abs(g)]},TEXSPACELENGTH:["",a.LENGTH.THINMATHSPACE,a.LENGTH.MEDIUMMATHSPACE,a.LENGTH.THICKMATHSPACE],TEXSPACE:[[0,-1,2,3,0,0,0,1],[-1,-1,0,3,0,0,0,1],[2,2,0,0,2,0,0,2],[3,3,0,0,3,0,0,3],[0,0,0,0,0,0,0,0],[0,-1,2,3,0,0,0,1],[1,1,0,1,1,1,1,1],[1,-1,2,3,1,0,1,1]],autoDefault:function(e){return""},isSpacelike:function(){return false},isEmbellished:function(){return false},Core:function(){return this},CoreMO:function(){return this},childIndex:function(g){if(g==null){return}for(var f=0,e=this.data.length;f=55296&&e.charCodeAt(0)<56320)?a.VARIANT.ITALIC:a.VARIANT.NORMAL)}return""},setTeXclass:function(f){this.getPrevClass(f);var e=this.data.join("");if(e.length>1&&e.match(/^[a-z][a-z0-9]*$/i)&&this.texClass===a.TEXCLASS.ORD){this.texClass=a.TEXCLASS.OP;this.autoOP=true}return this}});a.mn=a.mbase.Subclass({type:"mn",isToken:true,texClass:a.TEXCLASS.ORD,defaults:{mathvariant:a.INHERIT,mathsize:a.INHERIT,mathbackground:a.INHERIT,mathcolor:a.INHERIT,dir:a.INHERIT}});a.mo=a.mbase.Subclass({type:"mo",isToken:true,defaults:{mathvariant:a.INHERIT,mathsize:a.INHERIT,mathbackground:a.INHERIT,mathcolor:a.INHERIT,dir:a.INHERIT,form:a.AUTO,fence:a.AUTO,separator:a.AUTO,lspace:a.AUTO,rspace:a.AUTO,stretchy:a.AUTO,symmetric:a.AUTO,maxsize:a.AUTO,minsize:a.AUTO,largeop:a.AUTO,movablelimits:a.AUTO,accent:a.AUTO,linebreak:a.LINEBREAK.AUTO,lineleading:a.INHERIT,linebreakstyle:a.AUTO,linebreakmultchar:a.INHERIT,indentalign:a.INHERIT,indentshift:a.INHERIT,indenttarget:a.INHERIT,indentalignfirst:a.INHERIT,indentshiftfirst:a.INHERIT,indentalignlast:a.INHERIT,indentshiftlast:a.INHERIT,texClass:a.AUTO},defaultDef:{form:a.FORM.INFIX,fence:false,separator:false,lspace:a.LENGTH.THICKMATHSPACE,rspace:a.LENGTH.THICKMATHSPACE,stretchy:false,symmetric:false,maxsize:a.SIZE.INFINITY,minsize:"0em",largeop:false,movablelimits:false,accent:false,linebreak:a.LINEBREAK.AUTO,lineleading:"1ex",linebreakstyle:"before",indentalign:a.INDENTALIGN.AUTO,indentshift:"0",indenttarget:"",indentalignfirst:a.INDENTALIGN.INDENTALIGN,indentshiftfirst:a.INDENTSHIFT.INDENTSHIFT,indentalignlast:a.INDENTALIGN.INDENTALIGN,indentshiftlast:a.INDENTSHIFT.INDENTSHIFT,texClass:a.TEXCLASS.REL},SPACE_ATTR:{lspace:1,rspace:2},useMMLspacing:3,hasMMLspacing:function(){if(this.useMMLspacing){return true}return this.form&&(this.OPTABLE[this.form]||{})[this.data.join("")]},autoDefault:function(g,n){var l=this.def;if(!l){if(g==="form"){return this.getForm()}var k=this.data.join("");var f=[this.Get("form"),a.FORM.INFIX,a.FORM.POSTFIX,a.FORM.PREFIX];for(var h=0,e=f.length;h=55296&&k<56320){k=(((k-55296)<<10)+(j.charCodeAt(1)-56320))+65536}for(var g=0,e=this.RANGES.length;g=0;e--){if(this.data[0]&&!this.data[e].isSpacelike()){return this.data[e]}}return null},Core:function(){if(!(this.isEmbellished())||typeof(this.core)==="undefined"){return this}return this.data[this.core]},CoreMO:function(){if(!(this.isEmbellished())||typeof(this.core)==="undefined"){return this}return this.data[this.core].CoreMO()},toString:function(){if(this.inferred){return"["+this.data.join(",")+"]"}return this.SUPER(arguments).toString.call(this)},setTeXclass:function(g){var f,e=this.data.length;if((this.open||this.close)&&(!g||!g.fnOP)){this.getPrevClass(g);g=null;for(f=0;f0){e++}return e},adjustChild_texprimestyle:function(e){if(e==this.den){return true}return this.Get("texprimestyle")},setTeXclass:a.mbase.setSeparateTeXclasses});a.msqrt=a.mbase.Subclass({type:"msqrt",inferRow:true,linebreakContainer:true,texClass:a.TEXCLASS.ORD,setTeXclass:a.mbase.setSeparateTeXclasses,adjustChild_texprimestyle:function(e){return true}});a.mroot=a.mbase.Subclass({type:"mroot",linebreakContainer:true,texClass:a.TEXCLASS.ORD,adjustChild_displaystyle:function(e){if(e===1){return false}return this.Get("displaystyle")},adjustChild_scriptlevel:function(f){var e=this.Get("scriptlevel");if(f===1){e+=2}return e},adjustChild_texprimestyle:function(e){if(e===0){return true}return this.Get("texprimestyle")},setTeXclass:a.mbase.setSeparateTeXclasses});a.mstyle=a.mbase.Subclass({type:"mstyle",isSpacelike:a.mbase.childrenSpacelike,isEmbellished:a.mbase.childEmbellished,Core:a.mbase.childCore,CoreMO:a.mbase.childCoreMO,inferRow:true,defaults:{scriptlevel:a.INHERIT,displaystyle:a.INHERIT,scriptsizemultiplier:Math.sqrt(1/2),scriptminsize:"8pt",mathbackground:a.INHERIT,mathcolor:a.INHERIT,dir:a.INHERIT,infixlinebreakstyle:a.LINEBREAKSTYLE.BEFORE,decimalseparator:"."},adjustChild_scriptlevel:function(g){var f=this.scriptlevel;if(f==null){f=this.Get("scriptlevel")}else{if(String(f).match(/^ *[-+]/)){var e=this.Get("scriptlevel",null,true);f=e+parseInt(f)}}return f},inheritFromMe:true,noInherit:{mpadded:{width:true,height:true,depth:true,lspace:true,voffset:true},mtable:{width:true,height:true,depth:true,align:true}},getRemoved:{fontfamily:"fontFamily",fontweight:"fontWeight",fontstyle:"fontStyle",fontsize:"fontSize"},setTeXclass:a.mbase.setChildTeXclass});a.merror=a.mbase.Subclass({type:"merror",inferRow:true,linebreakContainer:true,texClass:a.TEXCLASS.ORD});a.mpadded=a.mbase.Subclass({type:"mpadded",inferRow:true,isSpacelike:a.mbase.childrenSpacelike,isEmbellished:a.mbase.childEmbellished,Core:a.mbase.childCore,CoreMO:a.mbase.childCoreMO,defaults:{mathbackground:a.INHERIT,mathcolor:a.INHERIT,width:"",height:"",depth:"",lspace:0,voffset:0},setTeXclass:a.mbase.setChildTeXclass});a.mphantom=a.mbase.Subclass({type:"mphantom",texClass:a.TEXCLASS.ORD,inferRow:true,isSpacelike:a.mbase.childrenSpacelike,isEmbellished:a.mbase.childEmbellished,Core:a.mbase.childCore,CoreMO:a.mbase.childCoreMO,setTeXclass:a.mbase.setChildTeXclass});a.mfenced=a.mbase.Subclass({type:"mfenced",defaults:{mathbackground:a.INHERIT,mathcolor:a.INHERIT,open:"(",close:")",separators:","},addFakeNodes:function(){var f=this.getValues("open","close","separators");f.open=f.open.replace(/[ \t\n\r]/g,"");f.close=f.close.replace(/[ \t\n\r]/g,"");f.separators=f.separators.replace(/[ \t\n\r]/g,"");if(f.open!==""){this.SetData("open",a.mo(f.open).With({fence:true,form:a.FORM.PREFIX,texClass:a.TEXCLASS.OPEN}))}if(f.separators!==""){while(f.separators.length0){return false}return this.Get("displaystyle")},adjustChild_scriptlevel:function(f){var e=this.Get("scriptlevel");if(f>0){e++}return e},adjustChild_texprimestyle:function(e){if(e===this.sub){return true}return this.Get("texprimestyle")},setTeXclass:a.mbase.setBaseTeXclasses});a.msub=a.msubsup.Subclass({type:"msub"});a.msup=a.msubsup.Subclass({type:"msup",sub:2,sup:1});a.mmultiscripts=a.msubsup.Subclass({type:"mmultiscripts",adjustChild_texprimestyle:function(e){if(e%2===1){return true}return this.Get("texprimestyle")}});a.mprescripts=a.mbase.Subclass({type:"mprescripts"});a.none=a.mbase.Subclass({type:"none"});a.munderover=a.mbase.Subclass({type:"munderover",base:0,under:1,over:2,sub:1,sup:2,ACCENTS:["","accentunder","accent"],linebreakContainer:true,isEmbellished:a.mbase.childEmbellished,Core:a.mbase.childCore,CoreMO:a.mbase.childCoreMO,defaults:{mathbackground:a.INHERIT,mathcolor:a.INHERIT,accent:a.AUTO,accentunder:a.AUTO,align:a.ALIGN.CENTER,texClass:a.AUTO,subscriptshift:"",superscriptshift:""},autoDefault:function(e){if(e==="texClass"){return(this.isEmbellished()?this.CoreMO().Get(e):a.TEXCLASS.ORD)}if(e==="accent"&&this.data[this.over]){return this.data[this.over].CoreMO().Get("accent")}if(e==="accentunder"&&this.data[this.under]){return this.data[this.under].CoreMO().Get("accent")}return false},adjustChild_displaystyle:function(e){if(e>0){return false}return this.Get("displaystyle")},adjustChild_scriptlevel:function(g){var f=this.Get("scriptlevel");var e=(this.data[this.base]&&!this.Get("displaystyle")&&this.data[this.base].CoreMO().Get("movablelimits"));if(g==this.under&&(e||!this.Get("accentunder"))){f++}if(g==this.over&&(e||!this.Get("accent"))){f++}return f},adjustChild_texprimestyle:function(e){if(e===this.base&&this.data[this.over]){return true}return this.Get("texprimestyle")},setTeXclass:a.mbase.setBaseTeXclasses});a.munder=a.munderover.Subclass({type:"munder"});a.mover=a.munderover.Subclass({type:"mover",over:1,under:2,sup:1,sub:2,ACCENTS:["","accent","accentunder"]});a.mtable=a.mbase.Subclass({type:"mtable",defaults:{mathbackground:a.INHERIT,mathcolor:a.INHERIT,align:a.ALIGN.AXIS,rowalign:a.ALIGN.BASELINE,columnalign:a.ALIGN.CENTER,groupalign:"{left}",alignmentscope:true,columnwidth:a.WIDTH.AUTO,width:a.WIDTH.AUTO,rowspacing:"1ex",columnspacing:".8em",rowlines:a.LINES.NONE,columnlines:a.LINES.NONE,frame:a.LINES.NONE,framespacing:"0.4em 0.5ex",equalrows:false,equalcolumns:false,displaystyle:false,side:a.SIDE.RIGHT,minlabelspacing:"0.8em",texClass:a.TEXCLASS.ORD,useHeight:1},adjustChild_displaystyle:function(){return(this.displaystyle!=null?this.displaystyle:this.defaults.displaystyle)},inheritFromMe:true,noInherit:{mover:{align:true},munder:{align:true},munderover:{align:true},mtable:{align:true,rowalign:true,columnalign:true,groupalign:true,alignmentscope:true,columnwidth:true,width:true,rowspacing:true,columnspacing:true,rowlines:true,columnlines:true,frame:true,framespacing:true,equalrows:true,equalcolumns:true,displaystyle:true,side:true,minlabelspacing:true,texClass:true,useHeight:1}},linebreakContainer:true,Append:function(){for(var f=0,e=arguments.length;f>10)+55296)+String.fromCharCode((e&1023)+56320)}});a.xml=a.mbase.Subclass({type:"xml",Init:function(){this.div=document.createElement("div");return this.SUPER(arguments).Init.apply(this,arguments)},Append:function(){for(var f=0,e=arguments.length;f":d.REL,"?":[1,1,b.CLOSE],"\\":d.ORD,"^":d.ORD11,_:d.ORD11,"|":[2,2,b.ORD,{fence:true,stretchy:true,symmetric:true}],"#":d.ORD,"$":d.ORD,"\u002E":[0,3,b.PUNCT,{separator:true}],"\u02B9":d.ORD,"\u0300":d.ACCENT,"\u0301":d.ACCENT,"\u0303":d.WIDEACCENT,"\u0304":d.ACCENT,"\u0306":d.ACCENT,"\u0307":d.ACCENT,"\u0308":d.ACCENT,"\u030C":d.ACCENT,"\u0332":d.WIDEACCENT,"\u0338":d.REL4,"\u2015":[0,0,b.ORD,{stretchy:true}],"\u2017":[0,0,b.ORD,{stretchy:true}],"\u2020":d.BIN3,"\u2021":d.BIN3,"\u20D7":d.ACCENT,"\u2111":d.ORD,"\u2113":d.ORD,"\u2118":d.ORD,"\u211C":d.ORD,"\u2205":d.ORD,"\u221E":d.ORD,"\u2305":d.BIN3,"\u2306":d.BIN3,"\u2322":d.REL4,"\u2323":d.REL4,"\u2329":d.OPEN,"\u232A":d.CLOSE,"\u23AA":d.ORD,"\u23AF":[0,0,b.ORD,{stretchy:true}],"\u23B0":d.OPEN,"\u23B1":d.CLOSE,"\u2500":d.ORD,"\u25EF":d.BIN3,"\u2660":d.ORD,"\u2661":d.ORD,"\u2662":d.ORD,"\u2663":d.ORD,"\u3008":d.OPEN,"\u3009":d.CLOSE,"\uFE37":d.WIDEACCENT,"\uFE38":d.WIDEACCENT}}},{OPTYPES:d});var c=a.mo.prototype.OPTABLE;c.infix["^"]=d.WIDEREL;c.infix._=d.WIDEREL;c.prefix["\u2223"]=d.OPEN;c.prefix["\u2225"]=d.OPEN;c.postfix["\u2223"]=d.CLOSE;c.postfix["\u2225"]=d.CLOSE})(MathJax.ElementJax.mml);MathJax.ElementJax.mml.loadComplete("jax.js");
+MathJax.Hub.Register.LoadHook("[MathJax]/jax/element/mml/jax.js",function(){var c="2.7.5";var a=MathJax.ElementJax.mml,b=MathJax.Hub.config.menuSettings;a.mbase.Augment({toMathML:function(l){var h=(this.inferred&&this.parent.inferRow);if(l==null){l=""}var f=this.type,e=this.toMathMLattributes();if(f==="mspace"){return l+"<"+f+e+" />"}var k=[],j=(this.isToken?"":l+(h?"":" "));for(var g=0,d=this.data.length;g ")}}}if(this.isToken||this.isChars){return l+"<"+f+e+">"+k.join("")+""+f+">"}if(h){return k.join("\n")}if(k.length===0||(k.length===1&&k[0]==="")){return l+"<"+f+e+" />"}return l+"<"+f+e+">\n"+k.join("\n")+"\n"+l+""+f+">"},toMathMLattributes:function(){var j=(this.type==="mstyle"?a.math.prototype.defaults:this.defaults);var h=(this.attrNames||a.copyAttributeNames),g=a.skipAttributes,l=a.copyAttributes;var e=[];if(this.type==="math"&&(!this.attr||!("xmlns" in this.attr))){e.push('xmlns="http://www.w3.org/1998/Math/MathML"')}if(!this.attrNames){for(var k in j){if(!g[k]&&!l[k]&&j.hasOwnProperty(k)){if(this[k]!=null&&this[k]!==j[k]){if(this.Get(k,null,1)!==this[k]){e.push(k+'="'+this.toMathMLattribute(this[k])+'"')}}}}}for(var f=0,d=h.length;f126||(k<32&&k!==10&&k!==13&&k!==9)){f[g]=""+k.toString(16).toUpperCase()+";"}else{var j={"&":"&","<":"<",">":">",'"':"""}[f[g]];if(j){f[g]=j}}}else{if(g+11);var p=this.type,k=this.toMathMLattributes();var j=[],o=d+(g?" "+(n?" ":""):"")+" ";for(var h=0,f=this.data.length;h ")}}if(j.length===0||(j.length===1&&j[0]==="")){if(!g){return"<"+p+k+" />"}j.push(o+" ")}if(g){if(n){j.unshift(d+" ");j.push(d+" ")}j.unshift(d+" ");var l=e.originalText.replace(/[&<>]/g,function(i){return{">":">","<":"<","&":"&"}[i]});j.push(d+' '+l+" ");j.push(d+" ")}return d+"<"+p+k+">\n"+j.join("\n")+"\n"+d+""+p+">"}});a.msubsup.Augment({toMathML:function(j){var f=this.type;if(this.data[this.sup]==null){f="msub"}if(this.data[this.sub]==null){f="msup"}var e=this.toMathMLattributes();delete this.data[0].inferred;var h=[];for(var g=0,d=this.data.length;g\n"+h.join("\n")+"\n"+j+""+f+">"}});a.munderover.Augment({toMathML:function(k){var f=this.type;var j=this.data[this.base];if(j&&j.isa(a.TeXAtom)&&j.movablelimits&&!j.Get("displaystyle")){type="msubsup";if(this.data[this.under]==null){f="msup"}if(this.data[this.over]==null){f="msub"}}else{if(this.data[this.under]==null){f="mover"}if(this.data[this.over]==null){f="munder"}}var e=this.toMathMLattributes();delete this.data[0].inferred;var h=[];for(var g=0,d=this.data.length;g\n"+h.join("\n")+"\n"+k+""+f+">"}});a.TeXAtom.Augment({toMathML:function(e){var d=this.toMathMLattributes();if(!d&&this.data[0].data.length===1){return e.substr(2)+this.data[0].toMathML(e)}return e+"\n"+this.data[0].toMathML(e+" ")+"\n"+e+" "}});a.chars.Augment({toMathML:function(d){return(d||"")+this.toMathMLquote(this.toString())}});a.entity.Augment({toMathML:function(d){return(d||"")+"&"+this.toMathMLquote(this.data[0])+";"}});a.xml.Augment({toMathML:function(d){return(d||"")+this.toString()}});MathJax.Hub.Register.StartupHook("TeX mathchoice Ready",function(){a.TeXmathchoice.Augment({toMathML:function(d){return this.Core().toMathML(d)}})});MathJax.Hub.Startup.signal.Post("toMathML Ready")});MathJax.Ajax.loadComplete("[MathJax]/extensions/toMathML.js");
+(function(aa){var g;var X=MathJax.Object.Subclass({firstChild:null,lastChild:null,Init:function(){this.childNodes=[]},appendChild:function(ab){if(ab.parent){ab.parent.removeChild(ab)}if(this.lastChild){this.lastChild.nextSibling=ab}if(!this.firstChild){this.firstChild=ab}this.childNodes.push(ab);ab.parent=this;this.lastChild=ab;return ab},removeChild:function(ad){for(var ac=0,ab=this.childNodes.length;ac=ab-1){this.lastChild=ae}this.childNodes[ad]=ae;ae.nextSibling=ac.nextSibling;ac.nextSibling=ac.parent=null;return ac},hasChildNodes:function(ab){return(this.childNodes.length>0)},toString:function(){return"{"+this.childNodes.join("")+"}"}});var x=function(){g=MathJax.ElementJax.mml;var ab=g.mbase.prototype.Init;g.mbase.Augment({firstChild:null,lastChild:null,nodeValue:null,nextSibling:null,Init:function(){var ac=ab.apply(this,arguments)||this;ac.childNodes=ac.data;ac.nodeName=ac.type;return ac},appendChild:function(af){if(af.parent){af.parent.removeChild(af)}var ad=arguments;if(af.isa(X)){ad=af.childNodes;af.data=af.childNodes=[];af.firstChild=af.lastChild=null}for(var ae=0,ac=ad.length;ae=ac-1){this.lastChild=af}this.SetData(ae,af);af.nextSibling=ad.nextSibling;ad.nextSibling=ad.parent=null;return ad},hasChildNodes:function(ac){return(this.childNodes.length>0)},setAttribute:function(ac,ad){this[ac]=ad}})};var Q={};var e={getElementById:true,createElementNS:function(ac,ab){var ad=g[ab]();if(ab==="mo"&&aa.config.useMathMLspacing){ad.useMMLspacing=128}return ad},createTextNode:function(ab){return g.chars(ab).With({nodeValue:ab})},createDocumentFragment:function(){return X()}};var J={appName:"MathJax"};var C="blue";var o=true;var v=true;var d=".";var f=true;var l=(J.appName.slice(0,9)=="Microsoft");function E(ab){if(l){return e.createElement(ab)}else{return e.createElementNS("http://www.w3.org/1999/xhtml",ab)}}var W="http://www.w3.org/1998/Math/MathML";function P(ab){if(l){return e.createElement("m:"+ab)}else{return e.createElementNS(W,ab)}}function O(ab,ad){var ac;if(l){ac=e.createElement("m:"+ab)}else{ac=e.createElementNS(W,ab)}if(ad){ac.appendChild(ad)}return ac}function u(ab,ac){z.push({input:ab,tag:"mo",output:ac,tex:null,ttype:V});B()}function r(ab){z.push(ab);B()}var D=["\uD835\uDC9C","\u212C","\uD835\uDC9E","\uD835\uDC9F","\u2130","\u2131","\uD835\uDCA2","\u210B","\u2110","\uD835\uDCA5","\uD835\uDCA6","\u2112","\u2133","\uD835\uDCA9","\uD835\uDCAA","\uD835\uDCAB","\uD835\uDCAC","\u211B","\uD835\uDCAE","\uD835\uDCAF","\uD835\uDCB0","\uD835\uDCB1","\uD835\uDCB2","\uD835\uDCB3","\uD835\uDCB4","\uD835\uDCB5","\uD835\uDCB6","\uD835\uDCB7","\uD835\uDCB8","\uD835\uDCB9","\u212F","\uD835\uDCBB","\u210A","\uD835\uDCBD","\uD835\uDCBE","\uD835\uDCBF","\uD835\uDCC0","\uD835\uDCC1","\uD835\uDCC2","\uD835\uDCC3","\u2134","\uD835\uDCC5","\uD835\uDCC6","\uD835\uDCC7","\uD835\uDCC8","\uD835\uDCC9","\uD835\uDCCA","\uD835\uDCCB","\uD835\uDCCC","\uD835\uDCCD","\uD835\uDCCE","\uD835\uDCCF"];var H=["\uD835\uDD04","\uD835\uDD05","\u212D","\uD835\uDD07","\uD835\uDD08","\uD835\uDD09","\uD835\uDD0A","\u210C","\u2111","\uD835\uDD0D","\uD835\uDD0E","\uD835\uDD0F","\uD835\uDD10","\uD835\uDD11","\uD835\uDD12","\uD835\uDD13","\uD835\uDD14","\u211C","\uD835\uDD16","\uD835\uDD17","\uD835\uDD18","\uD835\uDD19","\uD835\uDD1A","\uD835\uDD1B","\uD835\uDD1C","\u2128","\uD835\uDD1E","\uD835\uDD1F","\uD835\uDD20","\uD835\uDD21","\uD835\uDD22","\uD835\uDD23","\uD835\uDD24","\uD835\uDD25","\uD835\uDD26","\uD835\uDD27","\uD835\uDD28","\uD835\uDD29","\uD835\uDD2A","\uD835\uDD2B","\uD835\uDD2C","\uD835\uDD2D","\uD835\uDD2E","\uD835\uDD2F","\uD835\uDD30","\uD835\uDD31","\uD835\uDD32","\uD835\uDD33","\uD835\uDD34","\uD835\uDD35","\uD835\uDD36","\uD835\uDD37"];var w=["\uD835\uDD38","\uD835\uDD39","\u2102","\uD835\uDD3B","\uD835\uDD3C","\uD835\uDD3D","\uD835\uDD3E","\u210D","\uD835\uDD40","\uD835\uDD41","\uD835\uDD42","\uD835\uDD43","\uD835\uDD44","\u2115","\uD835\uDD46","\u2119","\u211A","\u211D","\uD835\uDD4A","\uD835\uDD4B","\uD835\uDD4C","\uD835\uDD4D","\uD835\uDD4E","\uD835\uDD4F","\uD835\uDD50","\u2124","\uD835\uDD52","\uD835\uDD53","\uD835\uDD54","\uD835\uDD55","\uD835\uDD56","\uD835\uDD57","\uD835\uDD58","\uD835\uDD59","\uD835\uDD5A","\uD835\uDD5B","\uD835\uDD5C","\uD835\uDD5D","\uD835\uDD5E","\uD835\uDD5F","\uD835\uDD60","\uD835\uDD61","\uD835\uDD62","\uD835\uDD63","\uD835\uDD64","\uD835\uDD65","\uD835\uDD66","\uD835\uDD67","\uD835\uDD68","\uD835\uDD69","\uD835\uDD6A","\uD835\uDD6B"];var c=0,A=1,U=2,i=3,b=4,h=5,a=6,L=7,V=8,m=9,Y=10,K=15;var k={input:'"',tag:"mtext",output:"mbox",tex:null,ttype:Y};var z=[{input:"alpha",tag:"mi",output:"\u03B1",tex:null,ttype:c},{input:"beta",tag:"mi",output:"\u03B2",tex:null,ttype:c},{input:"chi",tag:"mi",output:"\u03C7",tex:null,ttype:c},{input:"delta",tag:"mi",output:"\u03B4",tex:null,ttype:c},{input:"Delta",tag:"mo",output:"\u0394",tex:null,ttype:c},{input:"epsi",tag:"mi",output:"\u03B5",tex:"epsilon",ttype:c},{input:"varepsilon",tag:"mi",output:"\u025B",tex:null,ttype:c},{input:"eta",tag:"mi",output:"\u03B7",tex:null,ttype:c},{input:"gamma",tag:"mi",output:"\u03B3",tex:null,ttype:c},{input:"Gamma",tag:"mo",output:"\u0393",tex:null,ttype:c},{input:"iota",tag:"mi",output:"\u03B9",tex:null,ttype:c},{input:"kappa",tag:"mi",output:"\u03BA",tex:null,ttype:c},{input:"lambda",tag:"mi",output:"\u03BB",tex:null,ttype:c},{input:"Lambda",tag:"mo",output:"\u039B",tex:null,ttype:c},{input:"lamda",tag:"mi",output:"\u03BB",tex:null,ttype:c},{input:"Lamda",tag:"mo",output:"\u039B",tex:null,ttype:c},{input:"mu",tag:"mi",output:"\u03BC",tex:null,ttype:c},{input:"nu",tag:"mi",output:"\u03BD",tex:null,ttype:c},{input:"omega",tag:"mi",output:"\u03C9",tex:null,ttype:c},{input:"Omega",tag:"mo",output:"\u03A9",tex:null,ttype:c},{input:"phi",tag:"mi",output:f?"\u03D5":"\u03C6",tex:null,ttype:c},{input:"varphi",tag:"mi",output:f?"\u03C6":"\u03D5",tex:null,ttype:c},{input:"Phi",tag:"mo",output:"\u03A6",tex:null,ttype:c},{input:"pi",tag:"mi",output:"\u03C0",tex:null,ttype:c},{input:"Pi",tag:"mo",output:"\u03A0",tex:null,ttype:c},{input:"psi",tag:"mi",output:"\u03C8",tex:null,ttype:c},{input:"Psi",tag:"mi",output:"\u03A8",tex:null,ttype:c},{input:"rho",tag:"mi",output:"\u03C1",tex:null,ttype:c},{input:"sigma",tag:"mi",output:"\u03C3",tex:null,ttype:c},{input:"Sigma",tag:"mo",output:"\u03A3",tex:null,ttype:c},{input:"tau",tag:"mi",output:"\u03C4",tex:null,ttype:c},{input:"theta",tag:"mi",output:"\u03B8",tex:null,ttype:c},{input:"vartheta",tag:"mi",output:"\u03D1",tex:null,ttype:c},{input:"Theta",tag:"mo",output:"\u0398",tex:null,ttype:c},{input:"upsilon",tag:"mi",output:"\u03C5",tex:null,ttype:c},{input:"xi",tag:"mi",output:"\u03BE",tex:null,ttype:c},{input:"Xi",tag:"mo",output:"\u039E",tex:null,ttype:c},{input:"zeta",tag:"mi",output:"\u03B6",tex:null,ttype:c},{input:"*",tag:"mo",output:"\u22C5",tex:"cdot",ttype:c},{input:"**",tag:"mo",output:"\u2217",tex:"ast",ttype:c},{input:"***",tag:"mo",output:"\u22C6",tex:"star",ttype:c},{input:"//",tag:"mo",output:"/",tex:null,ttype:c},{input:"\\\\",tag:"mo",output:"\\",tex:"backslash",ttype:c},{input:"setminus",tag:"mo",output:"\\",tex:null,ttype:c},{input:"xx",tag:"mo",output:"\u00D7",tex:"times",ttype:c},{input:"|><",tag:"mo",output:"\u22C9",tex:"ltimes",ttype:c},{input:"><|",tag:"mo",output:"\u22CA",tex:"rtimes",ttype:c},{input:"|><|",tag:"mo",output:"\u22C8",tex:"bowtie",ttype:c},{input:"-:",tag:"mo",output:"\u00F7",tex:"div",ttype:c},{input:"divide",tag:"mo",output:"-:",tex:null,ttype:V},{input:"@",tag:"mo",output:"\u2218",tex:"circ",ttype:c},{input:"o+",tag:"mo",output:"\u2295",tex:"oplus",ttype:c},{input:"ox",tag:"mo",output:"\u2297",tex:"otimes",ttype:c},{input:"o.",tag:"mo",output:"\u2299",tex:"odot",ttype:c},{input:"sum",tag:"mo",output:"\u2211",tex:null,ttype:L},{input:"prod",tag:"mo",output:"\u220F",tex:null,ttype:L},{input:"^^",tag:"mo",output:"\u2227",tex:"wedge",ttype:c},{input:"^^^",tag:"mo",output:"\u22C0",tex:"bigwedge",ttype:L},{input:"vv",tag:"mo",output:"\u2228",tex:"vee",ttype:c},{input:"vvv",tag:"mo",output:"\u22C1",tex:"bigvee",ttype:L},{input:"nn",tag:"mo",output:"\u2229",tex:"cap",ttype:c},{input:"nnn",tag:"mo",output:"\u22C2",tex:"bigcap",ttype:L},{input:"uu",tag:"mo",output:"\u222A",tex:"cup",ttype:c},{input:"uuu",tag:"mo",output:"\u22C3",tex:"bigcup",ttype:L},{input:"!=",tag:"mo",output:"\u2260",tex:"ne",ttype:c},{input:":=",tag:"mo",output:":=",tex:null,ttype:c},{input:"lt",tag:"mo",output:"<",tex:null,ttype:c},{input:"<=",tag:"mo",output:"\u2264",tex:"le",ttype:c},{input:"lt=",tag:"mo",output:"\u2264",tex:"leq",ttype:c},{input:"gt",tag:"mo",output:">",tex:null,ttype:c},{input:">=",tag:"mo",output:"\u2265",tex:"ge",ttype:c},{input:"gt=",tag:"mo",output:"\u2265",tex:"geq",ttype:c},{input:"-<",tag:"mo",output:"\u227A",tex:"prec",ttype:c},{input:"-lt",tag:"mo",output:"\u227A",tex:null,ttype:c},{input:">-",tag:"mo",output:"\u227B",tex:"succ",ttype:c},{input:"-<=",tag:"mo",output:"\u2AAF",tex:"preceq",ttype:c},{input:">-=",tag:"mo",output:"\u2AB0",tex:"succeq",ttype:c},{input:"in",tag:"mo",output:"\u2208",tex:null,ttype:c},{input:"!in",tag:"mo",output:"\u2209",tex:"notin",ttype:c},{input:"sub",tag:"mo",output:"\u2282",tex:"subset",ttype:c},{input:"sup",tag:"mo",output:"\u2283",tex:"supset",ttype:c},{input:"sube",tag:"mo",output:"\u2286",tex:"subseteq",ttype:c},{input:"supe",tag:"mo",output:"\u2287",tex:"supseteq",ttype:c},{input:"-=",tag:"mo",output:"\u2261",tex:"equiv",ttype:c},{input:"~=",tag:"mo",output:"\u2245",tex:"cong",ttype:c},{input:"~~",tag:"mo",output:"\u2248",tex:"approx",ttype:c},{input:"prop",tag:"mo",output:"\u221D",tex:"propto",ttype:c},{input:"and",tag:"mtext",output:"and",tex:null,ttype:a},{input:"or",tag:"mtext",output:"or",tex:null,ttype:a},{input:"not",tag:"mo",output:"\u00AC",tex:"neg",ttype:c},{input:"=>",tag:"mo",output:"\u21D2",tex:"implies",ttype:c},{input:"if",tag:"mo",output:"if",tex:null,ttype:a},{input:"<=>",tag:"mo",output:"\u21D4",tex:"iff",ttype:c},{input:"AA",tag:"mo",output:"\u2200",tex:"forall",ttype:c},{input:"EE",tag:"mo",output:"\u2203",tex:"exists",ttype:c},{input:"_|_",tag:"mo",output:"\u22A5",tex:"bot",ttype:c},{input:"TT",tag:"mo",output:"\u22A4",tex:"top",ttype:c},{input:"|--",tag:"mo",output:"\u22A2",tex:"vdash",ttype:c},{input:"|==",tag:"mo",output:"\u22A8",tex:"models",ttype:c},{input:"(",tag:"mo",output:"(",tex:"left(",ttype:b},{input:")",tag:"mo",output:")",tex:"right)",ttype:h},{input:"[",tag:"mo",output:"[",tex:"left[",ttype:b},{input:"]",tag:"mo",output:"]",tex:"right]",ttype:h},{input:"{",tag:"mo",output:"{",tex:null,ttype:b},{input:"}",tag:"mo",output:"}",tex:null,ttype:h},{input:"|",tag:"mo",output:"|",tex:null,ttype:m},{input:":|:",tag:"mo",output:"|",tex:null,ttype:c},{input:"|:",tag:"mo",output:"|",tex:null,ttype:b},{input:":|",tag:"mo",output:"|",tex:null,ttype:h},{input:"(:",tag:"mo",output:"\u2329",tex:"langle",ttype:b},{input:":)",tag:"mo",output:"\u232A",tex:"rangle",ttype:h},{input:"<<",tag:"mo",output:"\u2329",tex:null,ttype:b},{input:">>",tag:"mo",output:"\u232A",tex:null,ttype:h},{input:"{:",tag:"mo",output:"{:",tex:null,ttype:b,invisible:true},{input:":}",tag:"mo",output:":}",tex:null,ttype:h,invisible:true},{input:"int",tag:"mo",output:"\u222B",tex:null,ttype:c},{input:"dx",tag:"mi",output:"{:d x:}",tex:null,ttype:V},{input:"dy",tag:"mi",output:"{:d y:}",tex:null,ttype:V},{input:"dz",tag:"mi",output:"{:d z:}",tex:null,ttype:V},{input:"dt",tag:"mi",output:"{:d t:}",tex:null,ttype:V},{input:"oint",tag:"mo",output:"\u222E",tex:null,ttype:c},{input:"del",tag:"mo",output:"\u2202",tex:"partial",ttype:c},{input:"grad",tag:"mo",output:"\u2207",tex:"nabla",ttype:c},{input:"+-",tag:"mo",output:"\u00B1",tex:"pm",ttype:c},{input:"O/",tag:"mo",output:"\u2205",tex:"emptyset",ttype:c},{input:"oo",tag:"mo",output:"\u221E",tex:"infty",ttype:c},{input:"aleph",tag:"mo",output:"\u2135",tex:null,ttype:c},{input:"...",tag:"mo",output:"...",tex:"ldots",ttype:c},{input:":.",tag:"mo",output:"\u2234",tex:"therefore",ttype:c},{input:":'",tag:"mo",output:"\u2235",tex:"because",ttype:c},{input:"/_",tag:"mo",output:"\u2220",tex:"angle",ttype:c},{input:"/_\\",tag:"mo",output:"\u25B3",tex:"triangle",ttype:c},{input:"'",tag:"mo",output:"\u2032",tex:"prime",ttype:c},{input:"tilde",tag:"mover",output:"~",tex:null,ttype:A,acc:true},{input:"\\ ",tag:"mo",output:"\u00A0",tex:null,ttype:c},{input:"frown",tag:"mo",output:"\u2322",tex:null,ttype:c},{input:"quad",tag:"mo",output:"\u00A0\u00A0",tex:null,ttype:c},{input:"qquad",tag:"mo",output:"\u00A0\u00A0\u00A0\u00A0",tex:null,ttype:c},{input:"cdots",tag:"mo",output:"\u22EF",tex:null,ttype:c},{input:"vdots",tag:"mo",output:"\u22EE",tex:null,ttype:c},{input:"ddots",tag:"mo",output:"\u22F1",tex:null,ttype:c},{input:"diamond",tag:"mo",output:"\u22C4",tex:null,ttype:c},{input:"square",tag:"mo",output:"\u25A1",tex:null,ttype:c},{input:"|__",tag:"mo",output:"\u230A",tex:"lfloor",ttype:c},{input:"__|",tag:"mo",output:"\u230B",tex:"rfloor",ttype:c},{input:"|~",tag:"mo",output:"\u2308",tex:"lceiling",ttype:c},{input:"~|",tag:"mo",output:"\u2309",tex:"rceiling",ttype:c},{input:"CC",tag:"mo",output:"\u2102",tex:null,ttype:c},{input:"NN",tag:"mo",output:"\u2115",tex:null,ttype:c},{input:"QQ",tag:"mo",output:"\u211A",tex:null,ttype:c},{input:"RR",tag:"mo",output:"\u211D",tex:null,ttype:c},{input:"ZZ",tag:"mo",output:"\u2124",tex:null,ttype:c},{input:"f",tag:"mi",output:"f",tex:null,ttype:A,func:true},{input:"g",tag:"mi",output:"g",tex:null,ttype:A,func:true},{input:"lim",tag:"mo",output:"lim",tex:null,ttype:L},{input:"Lim",tag:"mo",output:"Lim",tex:null,ttype:L},{input:"sin",tag:"mo",output:"sin",tex:null,ttype:A,func:true},{input:"cos",tag:"mo",output:"cos",tex:null,ttype:A,func:true},{input:"tan",tag:"mo",output:"tan",tex:null,ttype:A,func:true},{input:"sinh",tag:"mo",output:"sinh",tex:null,ttype:A,func:true},{input:"cosh",tag:"mo",output:"cosh",tex:null,ttype:A,func:true},{input:"tanh",tag:"mo",output:"tanh",tex:null,ttype:A,func:true},{input:"cot",tag:"mo",output:"cot",tex:null,ttype:A,func:true},{input:"sec",tag:"mo",output:"sec",tex:null,ttype:A,func:true},{input:"csc",tag:"mo",output:"csc",tex:null,ttype:A,func:true},{input:"arcsin",tag:"mo",output:"arcsin",tex:null,ttype:A,func:true},{input:"arccos",tag:"mo",output:"arccos",tex:null,ttype:A,func:true},{input:"arctan",tag:"mo",output:"arctan",tex:null,ttype:A,func:true},{input:"coth",tag:"mo",output:"coth",tex:null,ttype:A,func:true},{input:"sech",tag:"mo",output:"sech",tex:null,ttype:A,func:true},{input:"csch",tag:"mo",output:"csch",tex:null,ttype:A,func:true},{input:"exp",tag:"mo",output:"exp",tex:null,ttype:A,func:true},{input:"abs",tag:"mo",output:"abs",tex:null,ttype:A,rewriteleftright:["|","|"]},{input:"norm",tag:"mo",output:"norm",tex:null,ttype:A,rewriteleftright:["\u2225","\u2225"]},{input:"floor",tag:"mo",output:"floor",tex:null,ttype:A,rewriteleftright:["\u230A","\u230B"]},{input:"ceil",tag:"mo",output:"ceil",tex:null,ttype:A,rewriteleftright:["\u2308","\u2309"]},{input:"log",tag:"mo",output:"log",tex:null,ttype:A,func:true},{input:"ln",tag:"mo",output:"ln",tex:null,ttype:A,func:true},{input:"det",tag:"mo",output:"det",tex:null,ttype:A,func:true},{input:"dim",tag:"mo",output:"dim",tex:null,ttype:c},{input:"mod",tag:"mo",output:"mod",tex:null,ttype:c},{input:"gcd",tag:"mo",output:"gcd",tex:null,ttype:A,func:true},{input:"lcm",tag:"mo",output:"lcm",tex:null,ttype:A,func:true},{input:"lub",tag:"mo",output:"lub",tex:null,ttype:c},{input:"glb",tag:"mo",output:"glb",tex:null,ttype:c},{input:"min",tag:"mo",output:"min",tex:null,ttype:L},{input:"max",tag:"mo",output:"max",tex:null,ttype:L},{input:"Sin",tag:"mo",output:"Sin",tex:null,ttype:A,func:true},{input:"Cos",tag:"mo",output:"Cos",tex:null,ttype:A,func:true},{input:"Tan",tag:"mo",output:"Tan",tex:null,ttype:A,func:true},{input:"Arcsin",tag:"mo",output:"Arcsin",tex:null,ttype:A,func:true},{input:"Arccos",tag:"mo",output:"Arccos",tex:null,ttype:A,func:true},{input:"Arctan",tag:"mo",output:"Arctan",tex:null,ttype:A,func:true},{input:"Sinh",tag:"mo",output:"Sinh",tex:null,ttype:A,func:true},{input:"Cosh",tag:"mo",output:"Cosh",tex:null,ttype:A,func:true},{input:"Tanh",tag:"mo",output:"Tanh",tex:null,ttype:A,func:true},{input:"Cot",tag:"mo",output:"Cot",tex:null,ttype:A,func:true},{input:"Sec",tag:"mo",output:"Sec",tex:null,ttype:A,func:true},{input:"Csc",tag:"mo",output:"Csc",tex:null,ttype:A,func:true},{input:"Log",tag:"mo",output:"Log",tex:null,ttype:A,func:true},{input:"Ln",tag:"mo",output:"Ln",tex:null,ttype:A,func:true},{input:"Abs",tag:"mo",output:"abs",tex:null,ttype:A,notexcopy:true,rewriteleftright:["|","|"]},{input:"uarr",tag:"mo",output:"\u2191",tex:"uparrow",ttype:c},{input:"darr",tag:"mo",output:"\u2193",tex:"downarrow",ttype:c},{input:"rarr",tag:"mo",output:"\u2192",tex:"rightarrow",ttype:c},{input:"->",tag:"mo",output:"\u2192",tex:"to",ttype:c},{input:">->",tag:"mo",output:"\u21A3",tex:"rightarrowtail",ttype:c},{input:"->>",tag:"mo",output:"\u21A0",tex:"twoheadrightarrow",ttype:c},{input:">->>",tag:"mo",output:"\u2916",tex:"twoheadrightarrowtail",ttype:c},{input:"|->",tag:"mo",output:"\u21A6",tex:"mapsto",ttype:c},{input:"larr",tag:"mo",output:"\u2190",tex:"leftarrow",ttype:c},{input:"harr",tag:"mo",output:"\u2194",tex:"leftrightarrow",ttype:c},{input:"rArr",tag:"mo",output:"\u21D2",tex:"Rightarrow",ttype:c},{input:"lArr",tag:"mo",output:"\u21D0",tex:"Leftarrow",ttype:c},{input:"hArr",tag:"mo",output:"\u21D4",tex:"Leftrightarrow",ttype:c},{input:"sqrt",tag:"msqrt",output:"sqrt",tex:null,ttype:A},{input:"root",tag:"mroot",output:"root",tex:null,ttype:U},{input:"frac",tag:"mfrac",output:"/",tex:null,ttype:U},{input:"/",tag:"mfrac",output:"/",tex:null,ttype:i},{input:"stackrel",tag:"mover",output:"stackrel",tex:null,ttype:U},{input:"overset",tag:"mover",output:"stackrel",tex:null,ttype:U},{input:"underset",tag:"munder",output:"stackrel",tex:null,ttype:U},{input:"_",tag:"msub",output:"_",tex:null,ttype:i},{input:"^",tag:"msup",output:"^",tex:null,ttype:i},{input:"hat",tag:"mover",output:"\u005E",tex:null,ttype:A,acc:true},{input:"bar",tag:"mover",output:"\u00AF",tex:"overline",ttype:A,acc:true},{input:"vec",tag:"mover",output:"\u2192",tex:null,ttype:A,acc:true},{input:"dot",tag:"mover",output:".",tex:null,ttype:A,acc:true},{input:"ddot",tag:"mover",output:"..",tex:null,ttype:A,acc:true},{input:"overarc",tag:"mover",output:"\u23DC",tex:"overparen",ttype:A,acc:true},{input:"ul",tag:"munder",output:"\u0332",tex:"underline",ttype:A,acc:true},{input:"ubrace",tag:"munder",output:"\u23DF",tex:"underbrace",ttype:K,acc:true},{input:"obrace",tag:"mover",output:"\u23DE",tex:"overbrace",ttype:K,acc:true},{input:"text",tag:"mtext",output:"text",tex:null,ttype:Y},{input:"mbox",tag:"mtext",output:"mbox",tex:null,ttype:Y},{input:"color",tag:"mstyle",ttype:U},{input:"id",tag:"mrow",ttype:U},{input:"class",tag:"mrow",ttype:U},{input:"cancel",tag:"menclose",output:"cancel",tex:null,ttype:A},k,{input:"bb",tag:"mstyle",atname:"mathvariant",atval:"bold",output:"bb",tex:null,ttype:A},{input:"mathbf",tag:"mstyle",atname:"mathvariant",atval:"bold",output:"mathbf",tex:null,ttype:A},{input:"sf",tag:"mstyle",atname:"mathvariant",atval:"sans-serif",output:"sf",tex:null,ttype:A},{input:"mathsf",tag:"mstyle",atname:"mathvariant",atval:"sans-serif",output:"mathsf",tex:null,ttype:A},{input:"bbb",tag:"mstyle",atname:"mathvariant",atval:"double-struck",output:"bbb",tex:null,ttype:A,codes:w},{input:"mathbb",tag:"mstyle",atname:"mathvariant",atval:"double-struck",output:"mathbb",tex:null,ttype:A,codes:w},{input:"cc",tag:"mstyle",atname:"mathvariant",atval:"script",output:"cc",tex:null,ttype:A,codes:D},{input:"mathcal",tag:"mstyle",atname:"mathvariant",atval:"script",output:"mathcal",tex:null,ttype:A,codes:D},{input:"tt",tag:"mstyle",atname:"mathvariant",atval:"monospace",output:"tt",tex:null,ttype:A},{input:"mathtt",tag:"mstyle",atname:"mathvariant",atval:"monospace",output:"mathtt",tex:null,ttype:A},{input:"fr",tag:"mstyle",atname:"mathvariant",atval:"fraktur",output:"fr",tex:null,ttype:A,codes:H},{input:"mathfrak",tag:"mstyle",atname:"mathvariant",atval:"fraktur",output:"mathfrak",tex:null,ttype:A,codes:H}];function T(ac,ab){if(ac.input>ab.input){return 1}else{return -1}}var S=[];function n(){var ac;var ab=z.length;for(ac=0;ac>1;if(ac[ab]=S[ab]}s=y;if(af!=""){y=z[ae].ttype;return z[ae]}y=c;ab=1;ak=ah.slice(0,1);var ai=true;while("0"<=ak&&ak<="9"&&ab<=ah.length){ak=ah.slice(ab,ab+1);ab++}if(ak==d){ak=ah.slice(ab,ab+1);if("0"<=ak&&ak<="9"){ai=false;ab++;while("0"<=ak&&ak<="9"&&ab<=ah.length){ak=ah.slice(ab,ab+1);ab++}}}if((ai&&ab>1)||ab>2){ak=ah.slice(0,ab-1);aj="mn"}else{ab=2;ak=ah.slice(0,1);aj=(("A">ak||ak>"Z")&&("a">ak||ak>"z")?"mo":"mi")}if(ak=="-"&&s==i){y=i;return{input:ak,tag:aj,output:ak,ttype:A,func:true}}return{input:ak,tag:aj,output:ak,ttype:c}}function R(ac){var ab;if(!ac.hasChildNodes()){return}if(ac.firstChild.hasChildNodes()&&(ac.nodeName=="mrow"||ac.nodeName=="M:MROW")){ab=ac.firstChild.firstChild.nodeValue;if(ab=="("||ab=="["||ab=="{"){ac.removeChild(ac.firstChild)}}if(ac.lastChild.hasChildNodes()&&(ac.nodeName=="mrow"||ac.nodeName=="M:MROW")){ab=ac.lastChild.firstChild.nodeValue;if(ab==")"||ab=="]"||ab=="}"){ac.removeChild(ac.lastChild)}}}var F,s,y;function G(ai){var ad,ac,al,af,ak,ag=e.createDocumentFragment();ai=p(ai,0);ad=j(ai);if(ad==null||ad.ttype==h&&F>0){return[null,ai]}if(ad.ttype==V){ai=ad.output+p(ai,ad.input.length);ad=j(ai)}switch(ad.ttype){case L:case c:ai=p(ai,ad.input.length);return[O(ad.tag,e.createTextNode(ad.output)),ai];case b:F++;ai=p(ai,ad.input.length);al=q(ai,true);F--;if(typeof ad.invisible=="boolean"&&ad.invisible){ac=O("mrow",al[0])}else{ac=O("mo",e.createTextNode(ad.output));ac=O("mrow",ac);ac.appendChild(al[0])}return[ac,al[1]];case Y:if(ad!=k){ai=p(ai,ad.input.length)}if(ai.charAt(0)=="{"){af=ai.indexOf("}")}else{if(ai.charAt(0)=="("){af=ai.indexOf(")")}else{if(ai.charAt(0)=="["){af=ai.indexOf("]")}else{if(ad==k){af=ai.slice(1).indexOf('"')+1}else{af=0}}}}if(af==-1){af=ai.length}ak=ai.slice(1,af);if(ak.charAt(0)==" "){ac=O("mspace");ac.setAttribute("width","1ex");ag.appendChild(ac)}ag.appendChild(O(ad.tag,e.createTextNode(ak)));if(ak.charAt(ak.length-1)==" "){ac=O("mspace");ac.setAttribute("width","1ex");ag.appendChild(ac)}ai=p(ai,af+1);return[O("mrow",ag),ai];case K:case A:ai=p(ai,ad.input.length);al=G(ai);if(al[0]==null){return[O(ad.tag,e.createTextNode(ad.output)),ai]}if(typeof ad.func=="boolean"&&ad.func){ak=ai.charAt(0);if(ak=="^"||ak=="_"||ak=="/"||ak=="|"||ak==","||(ad.input.length==1&&ad.input.match(/\w/)&&ak!="(")){return[O(ad.tag,e.createTextNode(ad.output)),ai]}else{ac=O("mrow",O(ad.tag,e.createTextNode(ad.output)));ac.appendChild(al[0]);return[ac,al[1]]}}R(al[0]);if(ad.input=="sqrt"){return[O(ad.tag,al[0]),al[1]]}else{if(typeof ad.rewriteleftright!="undefined"){ac=O("mrow",O("mo",e.createTextNode(ad.rewriteleftright[0])));ac.appendChild(al[0]);ac.appendChild(O("mo",e.createTextNode(ad.rewriteleftright[1])));return[ac,al[1]]}else{if(ad.input=="cancel"){ac=O(ad.tag,al[0]);ac.setAttribute("notation","updiagonalstrike");return[ac,al[1]]}else{if(typeof ad.acc=="boolean"&&ad.acc){ac=O(ad.tag,al[0]);var ah=O("mo",e.createTextNode(ad.output));if(ad.input=="vec"&&((al[0].nodeName=="mrow"&&al[0].childNodes.length==1&&al[0].firstChild.firstChild.nodeValue!==null&&al[0].firstChild.firstChild.nodeValue.length==1)||(al[0].firstChild.nodeValue!==null&&al[0].firstChild.nodeValue.length==1))){ah.setAttribute("stretchy",false)}ac.appendChild(ah);return[ac,al[1]]}else{if(!l&&typeof ad.codes!="undefined"){for(af=0;af64&&ak.charCodeAt(ae)<91){aj=aj+ad.codes[ak.charCodeAt(ae)-65]}else{if(ak.charCodeAt(ae)>96&&ak.charCodeAt(ae)<123){aj=aj+ad.codes[ak.charCodeAt(ae)-71]}else{aj=aj+ak.charAt(ae)}}}if(al[0].nodeName=="mi"){al[0]=O("mo").appendChild(e.createTextNode(aj))}else{al[0].replaceChild(O("mo").appendChild(e.createTextNode(aj)),al[0].childNodes[af])}}}}ac=O(ad.tag,al[0]);ac.setAttribute(ad.atname,ad.atval);return[ac,al[1]]}}}}case U:ai=p(ai,ad.input.length);al=G(ai);if(al[0]==null){return[O("mo",e.createTextNode(ad.input)),ai]}R(al[0]);var ab=G(al[1]);if(ab[0]==null){return[O("mo",e.createTextNode(ad.input)),ai]}R(ab[0]);if(["color","class","id"].indexOf(ad.input)>=0){if(ai.charAt(0)=="{"){af=ai.indexOf("}")}else{if(ai.charAt(0)=="("){af=ai.indexOf(")")}else{if(ai.charAt(0)=="["){af=ai.indexOf("]")}}}ak=ai.slice(1,af);ac=O(ad.tag,ab[0]);if(ad.input==="color"){ac.setAttribute("mathcolor",ak)}else{if(ad.input==="class"){ac.setAttribute("class",ak)}else{if(ad.input==="id"){ac.setAttribute("id",ak)}}}return[ac,ab[1]]}if(ad.input=="root"||ad.output=="stackrel"){ag.appendChild(ab[0])}ag.appendChild(al[0]);if(ad.input=="frac"){ag.appendChild(ab[0])}return[O(ad.tag,ag),ab[1]];case i:ai=p(ai,ad.input.length);return[O("mo",e.createTextNode(ad.output)),ai];case a:ai=p(ai,ad.input.length);ac=O("mspace");ac.setAttribute("width","1ex");ag.appendChild(ac);ag.appendChild(O(ad.tag,e.createTextNode(ad.output)));ac=O("mspace");ac.setAttribute("width","1ex");ag.appendChild(ac);return[O("mrow",ag),ai];case m:F++;ai=p(ai,ad.input.length);al=q(ai,false);F--;ak="";if(al[0].lastChild!=null){ak=al[0].lastChild.firstChild.nodeValue}if(ak=="|"&&ai.charAt(0)!==","){ac=O("mo",e.createTextNode(ad.output));ac=O("mrow",ac);ac.appendChild(al[0]);return[ac,al[1]]}else{ac=O("mo",e.createTextNode("\u2223"));ac=O("mrow",ac);return[ac,ai]}default:ai=p(ai,ad.input.length);return[O(ad.tag,e.createTextNode(ad.output)),ai]}}function t(ah){var af,ai,ag,ae,ab,ad;ah=p(ah,0);ai=j(ah);ab=G(ah);ae=ab[0];ah=ab[1];af=j(ah);if(af.ttype==i&&af.input!="/"){ah=p(ah,af.input.length);ab=G(ah);if(ab[0]==null){ab[0]=O("mo",e.createTextNode("\u25A1"))}else{R(ab[0])}ah=ab[1];ad=(ai.ttype==L||ai.ttype==K);if(af.input=="_"){ag=j(ah);if(ag.input=="^"){ah=p(ah,ag.input.length);var ac=G(ah);R(ac[0]);ah=ac[1];ae=O((ad?"munderover":"msubsup"),ae);ae.appendChild(ab[0]);ae.appendChild(ac[0]);ae=O("mrow",ae)}else{ae=O((ad?"munder":"msub"),ae);ae.appendChild(ab[0])}}else{if(af.input=="^"&&ad){ae=O("mover",ae);ae.appendChild(ab[0])}else{ae=O(af.tag,ae);ae.appendChild(ab[0])}}if(typeof ai.func!="undefined"&&ai.func){ag=j(ah);if(ag.ttype!=i&&ag.ttype!=h){ab=t(ah);ae=O("mrow",ae);ae.appendChild(ab[0]);ah=ab[1]}}}return[ae,ah]}function q(ak,aj){var ao,al,ag,ar,ah=e.createDocumentFragment();do{ak=p(ak,0);ag=t(ak);al=ag[0];ak=ag[1];ao=j(ak);if(ao.ttype==i&&ao.input=="/"){ak=p(ak,ao.input.length);ag=t(ak);if(ag[0]==null){ag[0]=O("mo",e.createTextNode("\u25A1"))}else{R(ag[0])}ak=ag[1];R(al);al=O(ao.tag,al);al.appendChild(ag[0]);ah.appendChild(al);ao=j(ak)}else{if(al!=undefined){ah.appendChild(al)}}}while((ao.ttype!=h&&(ao.ttype!=m||aj)||F==0)&&ao!=null&&ao.output!="");if(ao.ttype==h||ao.ttype==m){var at=ah.childNodes.length;if(at>0&&ah.childNodes[at-1].nodeName=="mrow"&&ah.childNodes[at-1].lastChild&&ah.childNodes[at-1].lastChild.firstChild){var av=ah.childNodes[at-1].lastChild.firstChild.nodeValue;if(av==")"||av=="]"){var ac=ah.childNodes[at-1].firstChild.firstChild.nodeValue;if(ac=="("&&av==")"&&ao.output!="}"||ac=="["&&av=="]"){var ad=[];var ap=true;var am=ah.childNodes.length;for(ar=0;ap&&ar1){ap=ad[ar].length==ad[ar-2].length}}ap=ap&&(ad.length>1||ad[0].length>0);var af=[];if(ap){var ae,ab,ai,an,au=e.createDocumentFragment();for(ar=0;ar2){ah.removeChild(ah.firstChild);ah.removeChild(ah.firstChild)}au.appendChild(O("mtr",ae))}al=O("mtable",au);al.setAttribute("columnlines",af.join(" "));if(typeof ao.invisible=="boolean"&&ao.invisible){al.setAttribute("columnalign","left")}ah.replaceChild(al,ah.firstChild)}}}}ak=p(ak,ao.input.length);if(typeof ao.invisible!="boolean"||!ao.invisible){al=O("mo",e.createTextNode(ao.output));ah.appendChild(al)}}return[ah,ak]}function M(ad,ac){var ae,ab;F=0;ad=ad.replace(/ /g,"");ad=ad.replace(/>/g,">");ad=ad.replace(/</g,"<");ae=q(ad.replace(/^\s+/g,""),false)[0];ab=O("mstyle",ae);if(C!=""){ab.setAttribute("mathcolor",C)}if(mathfontsize!=""){ab.setAttribute("fontsize",mathfontsize);ab.setAttribute("mathsize",mathfontsize)}if(mathfontfamily!=""){ab.setAttribute("fontfamily",mathfontfamily);ab.setAttribute("mathvariant",mathfontfamily)}if(o){ab.setAttribute("displaystyle","true")}ab=O("math",ab);if(v){ab.setAttribute("title",ad.replace(/\s+/g," "))}return ab}v=false;mathfontfamily="";C="";mathfontsize="";(function(){for(var ac=0,ab=z.length;ac *":{display:"table-row!important"},".MJXp-surd":{"vertical-align":"top"},".MJXp-surd > *":{display:"block!important"},".MJXp-script-box > * ":{display:"table!important",height:"50%"},".MJXp-script-box > * > *":{display:"table-cell!important","vertical-align":"top"},".MJXp-script-box > *:last-child > *":{"vertical-align":"bottom"},".MJXp-script-box > * > * > *":{display:"block!important"},".MJXp-mphantom":{visibility:"hidden"},".MJXp-munderover, .MJXp-munder":{display:"inline-table!important"},".MJXp-over":{display:"inline-block!important","text-align":"center"},".MJXp-over > *":{display:"block!important"},".MJXp-munderover > *, .MJXp-munder > *":{display:"table-row!important"},".MJXp-mtable":{"vertical-align":".25em",margin:"0 .125em"},".MJXp-mtable > *":{display:"inline-table!important","vertical-align":"middle"},".MJXp-mtr":{display:"table-row!important"},".MJXp-mtd":{display:"table-cell!important","text-align":"center",padding:".5em 0 0 .5em"},".MJXp-mtr > .MJXp-mtd:first-child":{"padding-left":0},".MJXp-mtr:first-child > .MJXp-mtd":{"padding-top":0},".MJXp-mlabeledtr":{display:"table-row!important"},".MJXp-mlabeledtr > .MJXp-mtd:first-child":{"padding-left":0},".MJXp-mlabeledtr:first-child > .MJXp-mtd":{"padding-top":0},".MJXp-merror":{"background-color":"#FFFF88",color:"#CC0000",border:"1px solid #CC0000",padding:"1px 3px","font-style":"normal","font-size":"90%"}};(function(){for(var n=0;n<10;n++){var o="scaleX(."+n+")";m[".MJXp-scale"+n]={"-webkit-transform":o,"-moz-transform":o,"-ms-transform":o,"-o-transform":o,transform:o}}})();var k=1000000;var c="V",l="H";g.Augment({settings:b.config.menuSettings,config:{styles:m},hideProcessedMath:false,maxStretchyParts:1000,Config:function(){if(!this.require){this.require=[]}this.SUPER(arguments).Config.call(this);var n=this.settings;if(n.scale){this.config.scale=n.scale}this.require.push(MathJax.OutputJax.extensionDir+"/MathEvents.js")},Startup:function(){j=MathJax.Extension.MathEvents.Event;a=MathJax.Extension.MathEvents.Touch;d=MathJax.Extension.MathEvents.Hover;this.ContextMenu=j.ContextMenu;this.Mousedown=j.AltContextMenu;this.Mouseover=d.Mouseover;this.Mouseout=d.Mouseout;this.Mousemove=d.Mousemove;var n=e.addElement(document.body,"div",{style:{width:"5in"}});this.pxPerInch=n.offsetWidth/5;n.parentNode.removeChild(n);return i.Styles(this.config.styles,["InitializePHTML",this])},InitializePHTML:function(){},preTranslate:function(p){var s=p.jax[this.id],t,q=s.length,u,r,v,o,n;for(t=0;tthis.PHTML.h){this.PHTML.h=q.PHTML.h}if(q.PHTML.d>this.PHTML.d){this.PHTML.d=q.PHTML.d}if(q.PHTML.t>this.PHTML.t){this.PHTML.t=q.PHTML.t}if(q.PHTML.b>this.PHTML.b){this.PHTML.b=q.PHTML.b}}}else{if(n.forceChild){e.addElement(p,"span")}}},PHTMLstretchChild:function(q,p,s){var r=this.data[q];if(r&&r.PHTMLcanStretch("Vertical",p,s)){var t=this.PHTML,o=r.PHTML,n=o.w;r.PHTMLstretchV(p,s);t.w+=o.w-n;if(o.h>t.h){t.h=o.h}if(o.d>t.d){t.d=o.d}}},PHTMLcreateSpan:function(n){if(!this.PHTML){this.PHTML={}}this.PHTML={w:0,h:0,d:0,l:0,r:0,t:0,b:0};if(this.inferred){return n}if(this.type==="mo"&&this.data.join("")==="\u222B"){g.lastIsInt=true}else{if(this.type!=="mspace"||this.width!=="negativethinmathspace"){g.lastIsInt=false}}if(!this.PHTMLspanID){this.PHTMLspanID=g.GetID()}var o=(this.id||"MJXp-Span-"+this.PHTMLspanID);return e.addElement(n,"span",{className:"MJXp-"+this.type,id:o})},PHTMLspanElement:function(){if(!this.PHTMLspanID){return null}return document.getElementById(this.id||"MJXp-Span-"+this.PHTMLspanID)},PHTMLhandleToken:function(o){var n=this.getValues("mathvariant");if(n.mathvariant!==h.VARIANT.NORMAL){o.className+=" "+g.VARIANT[n.mathvariant]}},PHTMLhandleStyle:function(n){if(this.style){n.style.cssText=this.style}},PHTMLhandleColor:function(n){if(this.mathcolor){n.style.color=this.mathcolor}if(this.mathbackground){n.style.backgroundColor=this.mathbackground}},PHTMLhandleScriptlevel:function(n){var o=this.Get("scriptlevel");if(o){n.className+=" MJXp-script"}},PHTMLhandleText:function(y,A){var v,p;var z=0,o=0,q=0;for(var s=0,r=A.length;s=55296&&p<56319){s++;p=(((p-55296)<<10)+(A.charCodeAt(s)-56320))+65536}var t=0.7,u=0.22,x=0.5;if(p<127){if(v.match(/[A-Za-ehik-or-xz0-9]/)){u=0}if(v.match(/[A-HK-Z]/)){x=0.67}else{if(v.match(/[IJ]/)){x=0.36}}if(v.match(/[acegm-su-z]/)){t=0.45}else{if(v.match(/[ij]/)){t=0.75}}if(v.match(/[ijlt]/)){x=0.28}}if(g.DELIMITERS[v]){x=g.DELIMITERS[v].w||0.4}if(t>z){z=t}if(u>o){o=u}q+=x}if(!this.CHML){this.PHTML={}}this.PHTML={h:0.9,d:0.3,w:q,l:0,r:0,t:z,b:o};e.addText(y,A)},PHTMLbboxFor:function(o){if(this.data[o]&&this.data[o].PHTML){return this.data[o].PHTML}return{w:0,h:0,d:0,l:0,r:0,t:0,b:0}},PHTMLcanStretch:function(q,o,p){if(this.isEmbellished()){var n=this.Core();if(n&&n!==this){return n.PHTMLcanStretch(q,o,p)}}return false},PHTMLstretchV:function(n,o){},PHTMLstretchH:function(n){},CoreParent:function(){var n=this;while(n&&n.isEmbellished()&&n.CoreMO()===this&&!n.isa(h.math)){n=n.Parent()}return n},CoreText:function(n){if(!n){return""}if(n.isEmbellished()){return n.CoreMO().data.join("")}while((n.isa(h.mrow)||n.isa(h.TeXAtom)||n.isa(h.mstyle)||n.isa(h.mphantom))&&n.data.length===1&&n.data[0]){n=n.data[0]}if(!n.isToken){return""}else{return n.data.join("")}}});h.chars.Augment({toPreviewHTML:function(n){var o=this.toString().replace(/[\u2061-\u2064]/g,"");this.PHTMLhandleText(n,o)}});h.entity.Augment({toPreviewHTML:function(n){var o=this.toString().replace(/[\u2061-\u2064]/g,"");this.PHTMLhandleText(n,o)}});h.math.Augment({toPreviewHTML:function(n){n=this.PHTMLdefaultSpan(n);if(this.Get("display")==="block"){n.className+=" MJXp-display"}return n}});h.mo.Augment({toPreviewHTML:function(o){o=this.PHTMLdefaultSpan(o);this.PHTMLadjustAccent(o);var n=this.getValues("lspace","rspace","scriptlevel","displaystyle","largeop");if(n.scriptlevel===0){this.PHTML.l=g.length2em(n.lspace);this.PHTML.r=g.length2em(n.rspace);o.style.marginLeft=g.Em(this.PHTML.l);o.style.marginRight=g.Em(this.PHTML.r)}else{this.PHTML.l=0.15;this.PHTML.r=0.1}if(n.displaystyle&&n.largeop){var p=e.Element("span",{className:"MJXp-largeop"});p.appendChild(o.firstChild);o.appendChild(p);this.PHTML.h*=1.2;this.PHTML.d*=1.2;if(this.data.join("")==="\u222B"){p.className+=" MJXp-int"}}return o},PHTMLadjustAccent:function(p){var o=this.CoreParent();if(o&&o.isa(h.munderover)&&this.CoreText(o.data[o.base]).length===1){var q=o.data[o.over],n=o.data[o.under];var s=this.data.join(""),r;if(q&&this===q.CoreMO()&&o.Get("accent")){r=g.REMAPACCENT[s]}else{if(n&&this===n.CoreMO()&&o.Get("accentunder")){r=g.REMAPACCENTUNDER[s]}}if(r){s=p.innerHTML=r}if(s.match(/[\u02C6-\u02DC\u00A8]/)){this.PHTML.acc=-0.52}else{if(s==="\u2192"){this.PHTML.acc=-0.15;this.PHTML.vec=true}}}},PHTMLcanStretch:function(q,o,p){if(!this.Get("stretchy")){return false}var r=this.data.join("");if(r.length>1){return false}r=g.DELIMITERS[r];var n=(r&&r.dir===q.substr(0,1));if(n){n=(this.PHTML.h!==o||this.PHTML.d!==p||(this.Get("minsize",true)||this.Get("maxsize",true)))}return n},PHTMLstretchV:function(p,u){var o=this.PHTMLspanElement(),t=this.PHTML;var n=this.getValues("symmetric","maxsize","minsize");if(n.symmetric){l=2*Math.max(p-0.25,u+0.25)}else{l=p+u}n.maxsize=g.length2em(n.maxsize,t.h+t.d);n.minsize=g.length2em(n.minsize,t.h+t.d);l=Math.max(n.minsize,Math.min(n.maxsize,l));var s=l/(t.h+t.d-0.3);var q=e.Element("span",{style:{"font-size":g.Em(s)}});if(s>1.25){var r=Math.ceil(1.25/s*10);q.className="MJXp-right MJXp-scale"+r;q.style.marginLeft=g.Em(t.w*(r/10-1)+0.07);t.w*=s*r/10}q.appendChild(o.firstChild);o.appendChild(q);if(n.symmetric){o.style.verticalAlign=g.Em(0.25*(1-s))}}});h.mspace.Augment({toPreviewHTML:function(q){q=this.PHTMLdefaultSpan(q);var o=this.getValues("height","depth","width");var n=g.length2em(o.width),p=g.length2em(o.height),s=g.length2em(o.depth);var r=this.PHTML;r.w=n;r.h=p;r.d=s;if(n<0){if(!g.lastIsInt){q.style.marginLeft=g.Em(n)}n=0}q.style.width=g.Em(n);q.style.height=g.Em(p+s);if(s){q.style.verticalAlign=g.Em(-s)}return q}});h.mpadded.Augment({toPreviewHTML:function(u){u=this.PHTMLdefaultSpan(u,{childSpans:true,className:"MJXp-box",forceChild:true});var o=u.firstChild;var v=this.getValues("width","height","depth","lspace","voffset");var s=this.PHTMLdimen(v.lspace);var q=0,n=0,t=s.len,r=-s.len,p=0;if(v.width!==""){s=this.PHTMLdimen(v.width,"w",0);if(s.pm){r+=s.len}else{u.style.width=g.Em(s.len)}}if(v.height!==""){s=this.PHTMLdimen(v.height,"h",0);if(!s.pm){q+=-this.PHTMLbboxFor(0).h}q+=s.len}if(v.depth!==""){s=this.PHTMLdimen(v.depth,"d",0);if(!s.pm){n+=-this.PHTMLbboxFor(0).d;p+=-s.len}n+=s.len}if(v.voffset!==""){s=this.PHTMLdimen(v.voffset);q-=s.len;n+=s.len;p+=s.len}if(q){o.style.marginTop=g.Em(q)}if(n){o.style.marginBottom=g.Em(n)}if(t){o.style.marginLeft=g.Em(t)}if(r){o.style.marginRight=g.Em(r)}if(p){u.style.verticalAlign=g.Em(p)}return u},PHTMLdimen:function(q,r,n){if(n==null){n=-k}q=String(q);var o=q.match(/width|height|depth/);var p=(o?this.PHTML[o[0].charAt(0)]:(r?this.PHTML[r]:0));return{len:g.length2em(q,p)||0,pm:!!q.match(/^[-+]/)}}});h.munderover.Augment({toPreviewHTML:function(r){var t=this.getValues("displaystyle","accent","accentunder","align");var n=this.data[this.base];if(!t.displaystyle&&n!=null&&(n.movablelimits||n.CoreMO().Get("movablelimits"))){r=h.msubsup.prototype.toPreviewHTML.call(this,r);r.className=r.className.replace(/munderover/,"msubsup");return r}r=this.PHTMLdefaultSpan(r,{childSpans:true,className:"",noBBox:true});var p=this.PHTMLbboxFor(this.over),v=this.PHTMLbboxFor(this.under),u=this.PHTMLbboxFor(this.base),s=this.PHTML,o=p.acc;if(this.data[this.over]){if(r.lastChild.firstChild){r.lastChild.firstChild.style.marginLeft=p.l=r.lastChild.firstChild.style.marginRight=p.r=0}var q=e.Element("span",{},[["span",{className:"MJXp-over"}]]);q.firstChild.appendChild(r.lastChild);if(r.childNodes.length>(this.data[this.under]?1:0)){q.firstChild.appendChild(r.firstChild)}this.data[this.over].PHTMLhandleScriptlevel(q.firstChild.firstChild);if(o!=null){if(p.vec){q.firstChild.firstChild.firstChild.style.fontSize="60%";p.h*=0.6;p.d*=0.6;p.w*=0.6}o=o-p.d+0.1;if(u.t!=null){o+=u.t-u.h}q.firstChild.firstChild.style.marginBottom=g.Em(o)}if(r.firstChild){r.insertBefore(q,r.firstChild)}else{r.appendChild(q)}}if(this.data[this.under]){if(r.lastChild.firstChild){r.lastChild.firstChild.style.marginLeft=v.l=r.lastChild.firstChild.marginRight=v.r=0}this.data[this.under].PHTMLhandleScriptlevel(r.lastChild)}s.w=Math.max(0.8*p.w,0.8*v.w,u.w);s.h=0.8*(p.h+p.d+(o||0))+u.h;s.d=u.d+0.8*(v.h+v.d);return r}});h.msubsup.Augment({toPreviewHTML:function(q){q=this.PHTMLdefaultSpan(q,{noBBox:true});if(!this.data[this.base]){if(q.firstChild){q.insertBefore(e.Element("span"),q.firstChild)}else{q.appendChild(e.Element("span"))}}var s=this.data[this.base],p=this.data[this.sub],n=this.data[this.sup];if(!s){s={bbox:{h:0.8,d:0.2}}}q.firstChild.style.marginRight=".05em";var o=Math.max(0.4,s.PHTML.h-0.4),u=Math.max(0.2,s.PHTML.d+0.1);var t=this.PHTML;if(n&&p){var r=e.Element("span",{className:"MJXp-script-box",style:{height:g.Em(o+n.PHTML.h*0.8+u+p.PHTML.d*0.8),"vertical-align":g.Em(-u-p.PHTML.d*0.8)}},[["span",{},[["span",{},[["span",{style:{"margin-bottom":g.Em(-(n.PHTML.d-0.05))}}]]]]],["span",{},[["span",{},[["span",{style:{"margin-top":g.Em(-(n.PHTML.h-0.05))}}]]]]]]);p.PHTMLhandleScriptlevel(r.firstChild);n.PHTMLhandleScriptlevel(r.lastChild);r.firstChild.firstChild.firstChild.appendChild(q.lastChild);r.lastChild.firstChild.firstChild.appendChild(q.lastChild);q.appendChild(r);t.h=Math.max(s.PHTML.h,n.PHTML.h*0.8+o);t.d=Math.max(s.PHTML.d,p.PHTML.d*0.8+u);t.w=s.PHTML.w+Math.max(n.PHTML.w,p.PHTML.w)+0.07}else{if(n){q.lastChild.style.verticalAlign=g.Em(o);n.PHTMLhandleScriptlevel(q.lastChild);t.h=Math.max(s.PHTML.h,n.PHTML.h*0.8+o);t.d=Math.max(s.PHTML.d,n.PHTML.d*0.8-o);t.w=s.PHTML.w+n.PHTML.w+0.07}else{if(p){q.lastChild.style.verticalAlign=g.Em(-u);p.PHTMLhandleScriptlevel(q.lastChild);t.h=Math.max(s.PHTML.h,p.PHTML.h*0.8-u);t.d=Math.max(s.PHTML.d,p.PHTML.d*0.8+u);t.w=s.PHTML.w+p.PHTML.w+0.07}}}return q}});h.mfrac.Augment({toPreviewHTML:function(r){r=this.PHTMLdefaultSpan(r,{childSpans:true,className:"MJXp-box",forceChild:true,noBBox:true});var o=this.getValues("linethickness","displaystyle");if(!o.displaystyle){if(this.data[0]){this.data[0].PHTMLhandleScriptlevel(r.firstChild)}if(this.data[1]){this.data[1].PHTMLhandleScriptlevel(r.lastChild)}}var n=e.Element("span",{className:"MJXp-box"},[["span",{className:"MJXp-denom"},[["span",{},[["span",{className:"MJXp-rule",style:{height:"1em"}}]]],["span"]]]]);n.firstChild.lastChild.appendChild(r.lastChild);r.appendChild(n);var s=this.PHTMLbboxFor(0),p=this.PHTMLbboxFor(1),v=this.PHTML;v.w=Math.max(s.w,p.w)*0.8;v.h=s.h+s.d+0.1+0.25;v.d=p.h+p.d-0.25;v.l=v.r=0.125;o.linethickness=Math.max(0,g.length2em(o.linethickness||"0",0));if(o.linethickness){var u=n.firstChild.firstChild.firstChild;var q=g.Em(o.linethickness);u.style.borderTop="none";u.style.borderBottom=(o.linethickness<0.15?"1px":q)+" solid";u.style.margin=q+" 0";q=o.linethickness;n.style.marginTop=g.Em(3*q-1.2);r.style.verticalAlign=g.Em(1.5*q+0.1);v.h+=1.5*q-0.1;v.d+=1.5*q}else{n.style.marginTop="-.7em"}return r}});h.msqrt.Augment({toPreviewHTML:function(n){n=this.PHTMLdefaultSpan(n,{childSpans:true,className:"MJXp-box",forceChild:true,noBBox:true});this.PHTMLlayoutRoot(n,n.firstChild);return n},PHTMLlayoutRoot:function(u,n){var v=this.PHTMLbboxFor(0);var q=Math.ceil((v.h+v.d+0.14)*100),w=g.Em(14/q);var r=e.Element("span",{className:"MJXp-surd"},[["span",{style:{"font-size":q+"%","margin-top":w}},["\u221A"]]]);var s=e.Element("span",{className:"MJXp-root"},[["span",{className:"MJXp-rule",style:{"border-top":".08em solid"}}]]);var p=(1.2/2.2)*q/100;if(q>150){var o=Math.ceil(150/q*10);r.firstChild.className="MJXp-right MJXp-scale"+o;r.firstChild.style.marginLeft=g.Em(p*(o/10-1)/q*100);p=p*o/10;s.firstChild.style.borderTopWidth=g.Em(0.08/Math.sqrt(o/10))}s.appendChild(n);u.appendChild(r);u.appendChild(s);this.PHTML.h=v.h+0.18;this.PHTML.d=v.d;this.PHTML.w=v.w+p;return u}});h.mroot.Augment({toPreviewHTML:function(q){q=this.PHTMLdefaultSpan(q,{childSpans:true,className:"MJXp-box",forceChild:true,noBBox:true});var p=this.PHTMLbboxFor(1),n=q.removeChild(q.lastChild);var t=this.PHTMLlayoutRoot(e.Element("span"),q.firstChild);n.className="MJXp-script";var u=parseInt(t.firstChild.firstChild.style.fontSize);var o=0.55*(u/120)+p.d*0.8,s=-0.6*(u/120);if(u>150){s*=0.95*Math.ceil(150/u*10)/10}n.style.marginRight=g.Em(s);n.style.verticalAlign=g.Em(o);if(-s>p.w*0.8){n.style.marginLeft=g.Em(-s-p.w*0.8)}q.appendChild(n);q.appendChild(t);this.PHTML.w+=Math.max(0,p.w*0.8+s);this.PHTML.h=Math.max(this.PHTML.h,p.h*0.8+o);return q},PHTMLlayoutRoot:h.msqrt.prototype.PHTMLlayoutRoot});h.mfenced.Augment({toPreviewHTML:function(q){q=this.PHTMLcreateSpan(q);this.PHTMLhandleStyle(q);this.PHTMLhandleColor(q);this.addFakeNodes();this.PHTMLaddChild(q,"open",{});for(var p=0,n=this.data.length;ps){s=x.w}}}var o=this.PHTML;o.w=s;o.h=y/2+0.25;o.d=y/2-0.25;o.l=o.r=0.125;return E}});h.mlabeledtr.Augment({PHTMLdefaultSpan:function(q,o){if(!o){o={}}q=this.PHTMLcreateSpan(q);this.PHTMLhandleStyle(q);this.PHTMLhandleColor(q);if(this.isToken){this.PHTMLhandleToken(q)}for(var p=1,n=this.data.length;p/g,"")}catch(k){if(!k.restart){throw k}return MathJax.Callback.After(["HandleMML",this,l],k.restart)}n.setAttribute("data-mathml",i);j=f.addElement(n,"span",{isMathJax:true,unselectable:"on",className:"MJX_Assistive_MathML"+(h.root.Get("display")==="block"?" MJX_Assistive_MathML_Block":"")});try{j.innerHTML=i}catch(k){}n.style.position="relative";n.setAttribute("role","presentation");n.firstChild.setAttribute("aria-hidden","true");j.setAttribute("role","presentation")}l.i++}l.callback()}};b.Startup.signal.Post("AssistiveMML Ready")})(MathJax.Ajax,MathJax.Callback,MathJax.Hub,MathJax.HTML);MathJax.Callback.Queue(["Require",MathJax.Ajax,"[MathJax]/extensions/toMathML.js"],["loadComplete",MathJax.Ajax,"[MathJax]/extensions/AssistiveMML.js"],function(){MathJax.Hub.Register.StartupHook("End Config",["Config",MathJax.Extension.AssistiveMML])});
+!function(a,b){var c,d,e=a.config.menuSettings,f=Function.prototype.bind?function(a,b){return a.bind(b)}:function(a,b){return function(){a.apply(b,arguments)}},g=Object.keys||function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b},h=MathJax.Ajax.config.path;h.a11y||(h.a11y=a.config.root+"/extensions/a11y");var i=b["accessibility-menu"]={version:"1.5.0",prefix:"",defaults:{},modules:[],MakeOption:function(a){return i.prefix+a},GetOption:function(a){return e[i.MakeOption(a)]},AddDefaults:function(){for(var a,b=g(i.defaults),c=0;a=b[c];c++){var d=i.MakeOption(a);void 0===e[d]&&(e[d]=i.defaults[a])}},AddMenu:function(){for(var a,b=Array(this.modules.length),e=0;a=this.modules[e];e++)b[e]=a.placeHolder;var f=d.FindId("Accessibility");if(f)b.unshift(c.RULE()),f.submenu.items.push.apply(f.submenu.items,b);else{var g=(d.FindId("Settings","Renderer")||{}).submenu;g&&(b.unshift(c.RULE()),b.unshift(g.items.pop()),b.unshift(g.items.pop())),b.unshift("Accessibility");var f=c.SUBMENU.apply(c.SUBMENU,b),h=d.IndexOfId("Locale");h?d.items.splice(h,0,f):d.items.push(c.RULE(),f)}},Register:function(a){i.defaults[a.option]=!1,i.modules.push(a)},Startup:function(){c=MathJax.Menu.ITEM,d=MathJax.Menu.menu;for(var a,b=0;a=this.modules[b];b++)a.CreateMenu();this.AddMenu()},LoadExtensions:function(){for(var b,c=[],d=0;b=this.modules[d];d++)e[b.option]&&c.push(b.module);return c.length?a.Startup.loadArray(c):null}},j=MathJax.Extension.ModuleLoader=MathJax.Object.Subclass({option:"",name:["",""],module:"",placeHolder:null,submenu:!1,extension:null,Init:function(a,b,c,d,e){this.option=a,this.name=[b.replace(/ /g,""),b],this.module=c,this.extension=d,this.submenu=e||!1},CreateMenu:function(){var a=f(this.Load,this);this.submenu?this.placeHolder=c.SUBMENU(this.name,c.CHECKBOX(["Activate","Activate"],i.MakeOption(this.option),{action:a}),c.RULE(),c.COMMAND(["OptionsWhenActive","(Options when Active)"],null,{disabled:!0})):this.placeHolder=c.CHECKBOX(this.name,i.MakeOption(this.option),{action:a})},Load:function(){a.Queue(["Require",MathJax.Ajax,this.module,["Enable",this]])},Enable:function(a){var b=MathJax.Extension[this.extension];b&&(b.Enable(!0,!0),MathJax.Menu.saveCookie())}});i.Register(j("collapsible","Collapsible Math","[a11y]/collapsible.js","collapsible")),i.Register(j("autocollapse","Auto Collapse","[a11y]/auto-collapse.js","auto-collapse")),i.Register(j("explorer","Explorer","[a11y]/explorer.js","explorer",!0)),i.AddDefaults(),a.Register.StartupHook("End Extensions",function(){a.Register.StartupHook("MathMenu Ready",function(){i.Startup(),a.Startup.signal.Post("Accessibility Menu Ready")},5)},5),MathJax.Hub.Register.StartupHook("End Cookie",function(){MathJax.Callback.Queue(["LoadExtensions",i],["loadComplete",MathJax.Ajax,"[a11y]/accessibility-menu.js"])})}(MathJax.Hub,MathJax.Extension);MathJax.Ajax.loadComplete("[MathJax]/config/AM_CHTML.js");
diff --git a/spyder/plugins/help/utils/js/mathjax/config/AM_HTMLorMML-full.js b/spyder/plugins/help/utils/js/mathjax/config/AM_HTMLorMML-full.js
new file mode 100644
index 00000000000..81f5a7e4acf
--- /dev/null
+++ b/spyder/plugins/help/utils/js/mathjax/config/AM_HTMLorMML-full.js
@@ -0,0 +1,61 @@
+/*
+ * /MathJax/config/AM_HTMLorMML-full.js
+ *
+ * Copyright (c) 2010-2018 The MathJax Consortium
+ *
+ * Part of the MathJax library.
+ * See http://www.mathjax.org for details.
+ *
+ * Licensed under the Apache License, Version 2.0;
+ * you may not use this file except in compliance with the License.
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+MathJax.Hub.Config({delayJaxRegistration: true});
+
+MathJax.Ajax.Preloading(
+ "[MathJax]/jax/input/AsciiMath/config.js",
+ "[MathJax]/jax/output/HTML-CSS/config.js",
+ "[MathJax]/jax/output/NativeMML/config.js",
+ "[MathJax]/jax/output/PreviewHTML/config.js",
+ "[MathJax]/config/MMLorHTML.js",
+ "[MathJax]/extensions/asciimath2jax.js",
+ "[MathJax]/extensions/MathEvents.js",
+ "[MathJax]/extensions/MathZoom.js",
+ "[MathJax]/extensions/MathMenu.js",
+ "[MathJax]/jax/element/mml/jax.js",
+ "[MathJax]/extensions/toMathML.js",
+ "[MathJax]/jax/input/AsciiMath/jax.js",
+ "[MathJax]/jax/output/NativeMML/jax.js",
+ "[MathJax]/jax/output/HTML-CSS/jax.js",
+ "[MathJax]/jax/output/HTML-CSS/autoload/mtable.js",
+ "[MathJax]/jax/output/PreviewHTML/jax.js",
+ "[MathJax]/extensions/fast-preview.js",
+ "[MathJax]/extensions/AssistiveMML.js",
+ "[MathJax]/extensions/a11y/accessibility-menu.js"
+);
+
+MathJax.Hub.Config({
+ extensions: ['[a11y]/accessibility-menu.js']
+});
+
+MathJax.InputJax.AsciiMath=MathJax.InputJax({id:"AsciiMath",version:"2.7.5",directory:MathJax.InputJax.directory+"/AsciiMath",extensionDir:MathJax.InputJax.extensionDir+"/AsciiMath",config:{fixphi:true,useMathMLspacing:true,displaystyle:true,decimalsign:"."}});MathJax.InputJax.AsciiMath.Register("math/asciimath");MathJax.InputJax.AsciiMath.loadComplete("config.js");
+MathJax.OutputJax["HTML-CSS"]=MathJax.OutputJax({id:"HTML-CSS",version:"2.7.5",directory:MathJax.OutputJax.directory+"/HTML-CSS",extensionDir:MathJax.OutputJax.extensionDir+"/HTML-CSS",autoloadDir:MathJax.OutputJax.directory+"/HTML-CSS/autoload",fontDir:MathJax.OutputJax.directory+"/HTML-CSS/fonts",webfontDir:MathJax.OutputJax.fontDir+"/HTML-CSS",config:{noReflows:true,matchFontHeight:true,scale:100,minScaleAdjust:50,availableFonts:["STIX","TeX"],preferredFont:"TeX",webFont:"TeX",imageFont:"TeX",undefinedFamily:"STIXGeneral,'Arial Unicode MS',serif",mtextFontInherit:false,EqnChunk:(MathJax.Hub.Browser.isMobile?10:50),EqnChunkFactor:1.5,EqnChunkDelay:100,linebreaks:{automatic:false,width:"container"},styles:{".MathJax_Display":{"text-align":"center",margin:"1em 0em"},".MathJax .merror":{"background-color":"#FFFF88",color:"#CC0000",border:"1px solid #CC0000",padding:"1px 3px","font-style":"normal","font-size":"90%"},".MathJax .MJX-monospace":{"font-family":"monospace"},".MathJax .MJX-sans-serif":{"font-family":"sans-serif"},"#MathJax_Tooltip":{"background-color":"InfoBackground",color:"InfoText",border:"1px solid black","box-shadow":"2px 2px 5px #AAAAAA","-webkit-box-shadow":"2px 2px 5px #AAAAAA","-moz-box-shadow":"2px 2px 5px #AAAAAA","-khtml-box-shadow":"2px 2px 5px #AAAAAA",filter:"progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')",padding:"3px 4px","z-index":401}}}});if(MathJax.Hub.Browser.isMSIE&&document.documentMode>=9){delete MathJax.OutputJax["HTML-CSS"].config.styles["#MathJax_Tooltip"].filter}if(!MathJax.Hub.config.delayJaxRegistration){MathJax.OutputJax["HTML-CSS"].Register("jax/mml")}MathJax.Hub.Register.StartupHook("End Config",[function(b,c){var a=b.Insert({minBrowserVersion:{Firefox:3,Opera:9.52,MSIE:6,Chrome:0.3,Safari:2,Konqueror:4},inlineMathDelimiters:["$","$"],displayMathDelimiters:["$$","$$"],multilineDisplay:true,minBrowserTranslate:function(f){var e=b.getJaxFor(f),k=["[Math]"],j;var h=document.createElement("span",{className:"MathJax_Preview"});if(e.inputJax==="TeX"){if(e.root.Get("displaystyle")){j=a.displayMathDelimiters;k=[j[0]+e.originalText+j[1]];if(a.multilineDisplay){k=k[0].split(/\n/)}}else{j=a.inlineMathDelimiters;k=[j[0]+e.originalText.replace(/^\s+/,"").replace(/\s+$/,"")+j[1]]}}for(var g=0,d=k.length;g0){this.HoverFadeTimer(q,q.hover.inc);return}s.parentNode.removeChild(s);if(r){r.parentNode.removeChild(r)}if(q.hover.remove){clearTimeout(q.hover.remove)}delete q.hover},HoverFadeTimer:function(q,s,r){q.hover.inc=s;if(!q.hover.timer){q.hover.timer=setTimeout(g(["HoverFade",this,q]),(r||o.fadeDelay))}},HoverMenu:function(q){if(!q){q=window.event}return b[this.jax].ContextMenu(q,this.math,true)},ClearHover:function(q){if(q.hover.remove){clearTimeout(q.hover.remove)}if(q.hover.timer){clearTimeout(q.hover.timer)}f.ClearHoverTimer();delete q.hover},Px:function(q){if(Math.abs(q)<0.006){return"0px"}return q.toFixed(2).replace(/\.?0+$/,"")+"px"},getImages:function(){if(k.discoverable){var q=new Image();q.src=o.button.src}}};var a=c.Touch={last:0,delay:500,start:function(r){var q=new Date().getTime();var s=(q-a.lastt){z.style.height=t+"px";z.style.width=(x.zW+this.scrollSize)+"px"}if(z.offsetWidth>l){z.style.width=l+"px";z.style.height=(x.zH+this.scrollSize)+"px"}}if(this.operaPositionBug){z.style.width=Math.min(l,x.zW)+"px"}if(z.offsetWidth>m&&z.offsetWidth-m=9);h.msiePositionBug=!m;h.msieSizeBug=l.versionAtLeast("7.0")&&(!document.documentMode||n===7||n===8);h.msieZIndexBug=(n<=7);h.msieInlineBlockAlignBug=(n<=7);h.msieTrapEventBug=!window.addEventListener;if(document.compatMode==="BackCompat"){h.scrollSize=52}if(m){delete i.styles["#MathJax_Zoom"].filter}},Opera:function(l){h.operaPositionBug=true;h.operaRefreshBug=true}});h.topImg=(h.msieInlineBlockAlignBug?d.Element("img",{style:{width:0,height:0,position:"relative"},src:"about:blank"}):d.Element("span",{style:{width:0,height:0,display:"inline-block"}}));if(h.operaPositionBug||h.msieTopBug){h.topImg.style.border="1px solid"}MathJax.Callback.Queue(["StartupHook",MathJax.Hub.Register,"Begin Styles",{}],["Styles",f,i.styles],["Post",a.Startup.signal,"MathZoom Ready"],["loadComplete",f,"[MathJax]/extensions/MathZoom.js"])})(MathJax.Hub,MathJax.HTML,MathJax.Ajax,MathJax.OutputJax["HTML-CSS"],MathJax.OutputJax.NativeMML);
+(function(f,o,q,e,r){var p="2.7.5";var d=MathJax.Callback.Signal("menu");MathJax.Extension.MathMenu={version:p,signal:d};var t=function(u){return MathJax.Localization._.apply(MathJax.Localization,[["MathMenu",u]].concat([].slice.call(arguments,1)))};var i=MathJax.Object.isArray;var a=f.Browser.isPC,l=f.Browser.isMSIE,m=((document.documentMode||0)>8);var j=(a?null:"5px");var s=f.CombineConfig("MathMenu",{delay:150,showRenderer:true,showMathPlayer:true,showFontMenu:false,showContext:false,showDiscoverable:false,showLocale:true,showLocaleURL:false,semanticsAnnotations:{TeX:["TeX","LaTeX","application/x-tex"],StarMath:["StarMath 5.0"],Maple:["Maple"],ContentMathML:["MathML-Content","application/mathml-content+xml"],OpenMath:["OpenMath"]},windowSettings:{status:"no",toolbar:"no",locationbar:"no",menubar:"no",directories:"no",personalbar:"no",resizable:"yes",scrollbars:"yes",width:400,height:300,left:Math.round((screen.width-400)/2),top:Math.round((screen.height-300)/3)},styles:{"#MathJax_About":{position:"fixed",left:"50%",width:"auto","text-align":"center",border:"3px outset",padding:"1em 2em","background-color":"#DDDDDD",color:"black",cursor:"default","font-family":"message-box","font-size":"120%","font-style":"normal","text-indent":0,"text-transform":"none","line-height":"normal","letter-spacing":"normal","word-spacing":"normal","word-wrap":"normal","white-space":"nowrap","float":"none","z-index":201,"border-radius":"15px","-webkit-border-radius":"15px","-moz-border-radius":"15px","-khtml-border-radius":"15px","box-shadow":"0px 10px 20px #808080","-webkit-box-shadow":"0px 10px 20px #808080","-moz-box-shadow":"0px 10px 20px #808080","-khtml-box-shadow":"0px 10px 20px #808080",filter:"progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')"},"#MathJax_About.MathJax_MousePost":{outline:"none"},".MathJax_Menu":{position:"absolute","background-color":"white",color:"black",width:"auto",padding:(a?"2px":"5px 0px"),border:"1px solid #CCCCCC",margin:0,cursor:"default",font:"menu","text-align":"left","text-indent":0,"text-transform":"none","line-height":"normal","letter-spacing":"normal","word-spacing":"normal","word-wrap":"normal","white-space":"nowrap","float":"none","z-index":201,"border-radius":j,"-webkit-border-radius":j,"-moz-border-radius":j,"-khtml-border-radius":j,"box-shadow":"0px 10px 20px #808080","-webkit-box-shadow":"0px 10px 20px #808080","-moz-box-shadow":"0px 10px 20px #808080","-khtml-box-shadow":"0px 10px 20px #808080",filter:"progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')"},".MathJax_MenuItem":{padding:(a?"2px 2em":"1px 2em"),background:"transparent"},".MathJax_MenuArrow":{position:"absolute",right:".5em","padding-top":".25em",color:"#666666","font-family":(l?"'Arial unicode MS'":null),"font-size":".75em"},".MathJax_MenuActive .MathJax_MenuArrow":{color:"white"},".MathJax_MenuArrow.RTL":{left:".5em",right:"auto"},".MathJax_MenuCheck":{position:"absolute",left:".7em","font-family":(l?"'Arial unicode MS'":null)},".MathJax_MenuCheck.RTL":{right:".7em",left:"auto"},".MathJax_MenuRadioCheck":{position:"absolute",left:(a?"1em":".7em")},".MathJax_MenuRadioCheck.RTL":{right:(a?"1em":".7em"),left:"auto"},".MathJax_MenuLabel":{padding:(a?"2px 2em 4px 1.33em":"1px 2em 3px 1.33em"),"font-style":"italic"},".MathJax_MenuRule":{"border-top":(a?"1px solid #CCCCCC":"1px solid #DDDDDD"),margin:(a?"4px 1px 0px":"4px 3px")},".MathJax_MenuDisabled":{color:"GrayText"},".MathJax_MenuActive":{"background-color":(a?"Highlight":"#606872"),color:(a?"HighlightText":"white")},".MathJax_MenuDisabled:focus, .MathJax_MenuLabel:focus":{"background-color":"#E8E8E8"},".MathJax_ContextMenu:focus":{outline:"none"},".MathJax_ContextMenu .MathJax_MenuItem:focus":{outline:"none"},"#MathJax_AboutClose":{top:".2em",right:".2em"},".MathJax_Menu .MathJax_MenuClose":{top:"-10px",left:"-10px"},".MathJax_MenuClose":{position:"absolute",cursor:"pointer",display:"inline-block",border:"2px solid #AAA","border-radius":"18px","-webkit-border-radius":"18px","-moz-border-radius":"18px","-khtml-border-radius":"18px","font-family":"'Courier New',Courier","font-size":"24px",color:"#F0F0F0"},".MathJax_MenuClose span":{display:"block","background-color":"#AAA",border:"1.5px solid","border-radius":"18px","-webkit-border-radius":"18px","-moz-border-radius":"18px","-khtml-border-radius":"18px","line-height":0,padding:"8px 0 6px"},".MathJax_MenuClose:hover":{color:"white!important",border:"2px solid #CCC!important"},".MathJax_MenuClose:hover span":{"background-color":"#CCC!important"},".MathJax_MenuClose:hover:focus":{outline:"none"}}});var n,k,b;f.Register.StartupHook("MathEvents Ready",function(){n=MathJax.Extension.MathEvents.Event.False;k=MathJax.Extension.MathEvents.Hover;b=MathJax.Extension.MathEvents.Event.KEY});var h=MathJax.Object.Subclass({Keydown:function(u,v){switch(u.keyCode){case b.ESCAPE:this.Remove(u,v);break;case b.RIGHT:this.Right(u,v);break;case b.LEFT:this.Left(u,v);break;case b.UP:this.Up(u,v);break;case b.DOWN:this.Down(u,v);break;case b.RETURN:case b.SPACE:this.Space(u,v);break;default:return;break}return n(u)},Escape:function(u,v){},Right:function(u,v){},Left:function(u,v){},Up:function(u,v){},Down:function(u,v){},Space:function(u,v){}},{});var g=MathJax.Menu=h.Subclass({version:p,items:[],posted:false,title:null,margin:5,Init:function(u){this.items=[].slice.call(arguments,0)},With:function(u){if(u){f.Insert(this,u)}return this},Post:function(M,E,B){if(!M){M=window.event||{}}var I=document.getElementById("MathJax_MenuFrame");if(!I){I=g.Background(this);delete c.lastItem;delete c.lastMenu;delete g.skipUp;d.Post(["post",g.jax]);g.isRTL=(MathJax.Localization.fontDirection()==="rtl")}var v=o.Element("div",{onmouseup:g.Mouseup,ondblclick:n,ondragstart:n,onselectstart:n,oncontextmenu:n,menuItem:this,className:"MathJax_Menu",onkeydown:g.Keydown,role:"menu"});if(M.type==="contextmenu"||M.type==="mouseover"){v.className+=" MathJax_ContextMenu"}if(!B){MathJax.Localization.setCSS(v)}for(var N=0,K=this.items.length;NA-this.margin){H=A-v.offsetWidth-this.margin}if(g.isMobile){H=Math.max(5,H-Math.floor(v.offsetWidth/2));F-=20}g.skipUp=M.isContextMenu}else{var z="left",J=E.offsetWidth;H=(g.isMobile?30:J-2);F=0;while(E&&E!==I){H+=E.offsetLeft;F+=E.offsetTop;E=E.parentNode}if(!g.isMobile){if((g.isRTL&&H-J-v.offsetWidth>this.margin)||(!g.isRTL&&H+v.offsetWidth>A-this.margin)){z="right";H=Math.max(this.margin,H-J-v.offsetWidth+6)}}if(!a){v.style["borderRadiusTop"+z]=0;v.style["WebkitBorderRadiusTop"+z]=0;v.style["MozBorderRadiusTop"+z]=0;v.style["KhtmlBorderRadiusTop"+z]=0}}v.style.left=H+"px";v.style.top=F+"px";if(document.selection&&document.selection.empty){document.selection.empty()}var G=window.pageXOffset||document.documentElement.scrollLeft;var D=window.pageYOffset||document.documentElement.scrollTop;g.Focus(v);if(M.type==="keydown"){g.skipMouseoverFromKey=true;setTimeout(function(){delete g.skipMouseoverFromKey},s.delay)}window.scrollTo(G,D);return n(M)},Remove:function(u,v){d.Post(["unpost",g.jax]);var w=document.getElementById("MathJax_MenuFrame");if(w){w.parentNode.removeChild(w);if(this.msieFixedPositionBug){detachEvent("onresize",g.Resize)}}if(g.jax.hover){delete g.jax.hover.nofade;k.UnHover(g.jax)}g.Unfocus(v);if(u.type==="mousedown"){g.CurrentNode().blur()}return n(u)},Find:function(u){return this.FindN(1,u,[].slice.call(arguments,1))},FindId:function(u){return this.FindN(0,u,[].slice.call(arguments,1))},FindN:function(y,v,x){for(var w=0,u=this.items.length;w0){u.oldTabIndex=u.tabIndex}u.tabIndex=-1}},SetTabIndex:function(){var v=g.AllNodes();for(var w=0,u;u=v[w];w++){if(u.oldTabIndex!==undefined){u.tabIndex=u.oldTabIndex;delete u.oldTabIndex}else{u.tabIndex=f.getTabOrder(u)}}},Mod:function(u,v){return((u%v)+v)%v},IndexOf:(Array.prototype.indexOf?function(u,v,w){return u.indexOf(v,w)}:function(u,x,y){for(var w=(y||0),v=u.length;w=0&&c.GetMenuNode(w).menuItem!==v[u].menuItem){v[u].menuItem.posted=false;v[u].parentNode.removeChild(v[u]);u--}},Touchstart:function(u,v){return this.TouchEvent(u,v,"Mousedown")},Touchend:function(u,v){return this.TouchEvent(u,v,"Mouseup")},TouchEvent:function(v,w,u){if(this!==c.lastItem){if(c.lastMenu){g.Event(v,c.lastMenu,"Mouseout")}g.Event(v,w,"Mouseover",true);c.lastItem=this;c.lastMenu=w}if(this.nativeTouch){return null}g.Event(v,w,u);return false},Remove:function(u,v){v=v.parentNode.menuItem;return v.Remove(u,v)},With:function(u){if(u){f.Insert(this,u)}return this},isRTL:function(){return g.isRTL},rtlClass:function(){return(this.isRTL()?" RTL":"")}},{GetMenuNode:function(u){return u.parentNode}});g.ENTRY=g.ITEM.Subclass({role:"menuitem",Attributes:function(u){u=f.Insert({onmouseover:g.Mouseover,onmouseout:g.Mouseout,onmousedown:g.Mousedown,onkeydown:g.Keydown,"aria-disabled":!!this.disabled},u);u=this.SUPER(arguments).Attributes.call(this,u);if(this.disabled){u.className+=" MathJax_MenuDisabled"}return u},MoveVertical:function(u,E,w){var x=c.GetMenuNode(E);var D=[];for(var z=0,C=x.menuItem.items,y;y=C[z];z++){if(!y.hidden){D.push(y)}}var B=g.IndexOf(D,this);if(B===-1){return}var A=D.length;var v=x.childNodes;do{B=g.Mod(w(B),A)}while(D[B].hidden||!v[B].role||v[B].role==="separator");this.Deactivate(E);D[B].Activate(u,v[B])},Up:function(v,u){this.MoveVertical(v,u,function(w){return w-1})},Down:function(v,u){this.MoveVertical(v,u,function(w){return w+1})},Right:function(v,u){this.MoveHorizontal(v,u,g.Right,!this.isRTL())},Left:function(v,u){this.MoveHorizontal(v,u,g.Left,this.isRTL())},MoveHorizontal:function(A,z,u,B){var x=c.GetMenuNode(z);if(x.menuItem===g.menu&&A.shiftKey){u(A,z)}if(B){return}if(x.menuItem!==g.menu){this.Deactivate(z)}var v=x.previousSibling.childNodes;var y=v.length;while(y--){var w=v[y];if(w.menuItem.submenu&&w.menuItem.submenu===x.menuItem){g.Focus(w);break}}this.RemoveSubmenus(z)},Space:function(u,v){this.Mouseup(u,v)},Activate:function(u,v){this.Deactivate(v);if(!this.disabled){v.className+=" MathJax_MenuActive"}this.DeactivateSubmenus(v);g.Focus(v)},Deactivate:function(u){u.className=u.className.replace(/ MathJax_MenuActive/,"")}});g.ITEM.COMMAND=g.ENTRY.Subclass({action:function(){},Init:function(u,w,v){if(!i(u)){u=[u,u]}this.name=u;this.action=w;this.With(v)},Label:function(u,v){return[this.Name()]},Mouseup:function(u,v){if(!this.disabled){this.Remove(u,v);d.Post(["command",this]);this.action.call(this,u)}return n(u)}});g.ITEM.SUBMENU=g.ENTRY.Subclass({submenu:null,marker:"\u25BA",markerRTL:"\u25C4",Attributes:function(u){u=f.Insert({"aria-haspopup":"true"},u);u=this.SUPER(arguments).Attributes.call(this,u);return u},Init:function(u,w){if(!i(u)){u=[u,u]}this.name=u;var v=1;if(!(w instanceof g.ITEM)){this.With(w),v++}this.submenu=g.apply(g,[].slice.call(arguments,v))},Label:function(u,v){this.submenu.posted=false;return[this.Name()+" ",["span",{className:"MathJax_MenuArrow"+this.rtlClass()},[this.isRTL()?this.markerRTL:this.marker]]]},Timer:function(u,v){this.ClearTimer();u={type:u.type,clientX:u.clientX,clientY:u.clientY};this.timer=setTimeout(e(["Mouseup",this,u,v]),s.delay)},ClearTimer:function(){if(this.timer){clearTimeout(this.timer)}},Touchend:function(v,x){var w=this.submenu.posted;var u=this.SUPER(arguments).Touchend.apply(this,arguments);if(w){this.Deactivate(x);delete c.lastItem;delete c.lastMenu}return u},Mouseout:function(u,v){if(!this.submenu.posted){this.Deactivate(v)}this.ClearTimer()},Mouseover:function(u,v){this.Activate(u,v)},Mouseup:function(u,v){if(!this.disabled){if(!this.submenu.posted){this.ClearTimer();this.submenu.Post(u,v,this.ltr);g.Focus(v)}else{this.DeactivateSubmenus(v)}}return n(u)},Activate:function(u,v){if(!this.disabled){this.Deactivate(v);v.className+=" MathJax_MenuActive"}if(!this.submenu.posted){this.DeactivateSubmenus(v);if(!g.isMobile){this.Timer(u,v)}}g.Focus(v)},MoveVertical:function(w,v,u){this.ClearTimer();this.SUPER(arguments).MoveVertical.apply(this,arguments)},MoveHorizontal:function(w,y,v,x){if(!x){this.SUPER(arguments).MoveHorizontal.apply(this,arguments);return}if(this.disabled){return}if(!this.submenu.posted){this.Activate(w,y);return}var u=c.GetMenuNode(y).nextSibling.childNodes;if(u.length>0){this.submenu.items[0].Activate(w,u[0])}}});g.ITEM.RADIO=g.ENTRY.Subclass({variable:null,marker:(a?"\u25CF":"\u2713"),role:"menuitemradio",Attributes:function(v){var u=s.settings[this.variable]===this.value?"true":"false";v=f.Insert({"aria-checked":u},v);v=this.SUPER(arguments).Attributes.call(this,v);return v},Init:function(v,u,w){if(!i(v)){v=[v,v]}this.name=v;this.variable=u;this.With(w);if(this.value==null){this.value=this.name[0]}},Label:function(v,w){var u={className:"MathJax_MenuRadioCheck"+this.rtlClass()};if(s.settings[this.variable]!==this.value){u={style:{display:"none"}}}return[["span",u,[this.marker]]," "+this.Name()]},Mouseup:function(x,y){if(!this.disabled){var z=y.parentNode.childNodes;for(var v=0,u=z.length;v/g,">");var y=t("EqSource","MathJax Equation Source");if(g.isMobile){u.document.open();u.document.write(""+y+" ");u.document.write(""+z+"
");u.document.write("
");u.document.write("");u.document.close()}else{u.document.open();u.document.write(""+y+" ");u.document.write(""+z+"
");u.document.write("");u.document.close();var v=u.document.body.firstChild;setTimeout(function(){var B=(u.outerHeight-u.innerHeight)||30,A=(u.outerWidth-u.innerWidth)||30,w,E;A=Math.max(140,Math.min(Math.floor(0.5*screen.width),v.offsetWidth+A+25));B=Math.max(40,Math.min(Math.floor(0.5*screen.height),v.offsetHeight+B+25));if(g.prototype.msieHeightBug){B+=35}u.resizeTo(A,B);var D;try{D=x.screenX}catch(C){}if(x&&D!=null){w=Math.max(0,Math.min(x.screenX-Math.floor(A/2),screen.width-A-20));E=Math.max(0,Math.min(x.screenY-Math.floor(B/2),screen.height-B-20));u.moveTo(w,E)}},50)}};g.Scale=function(){var z=["CommonHTML","HTML-CSS","SVG","NativeMML","PreviewHTML"],u=z.length,y=100,w,v;for(w=0;w7;g.Augment({margin:20,msieBackgroundBug:((document.documentMode||0)<9),msieFixedPositionBug:(v||!w),msieAboutBug:v,msieHeightBug:((document.documentMode||0)<9)});if(m){delete s.styles["#MathJax_About"].filter;delete s.styles[".MathJax_Menu"].filter}},Firefox:function(u){g.skipMouseover=u.isMobile&&u.versionAtLeast("6.0");g.skipMousedown=u.isMobile}});g.isMobile=f.Browser.isMobile;g.noContextMenu=f.Browser.noContextMenu;g.CreateLocaleMenu=function(){if(!g.menu){return}var z=g.menu.Find("Language").submenu,w=z.items;var v=[],B=MathJax.Localization.strings;for(var A in B){if(B.hasOwnProperty(A)){v.push(A)}}v=v.sort();z.items=[];for(var x=0,u=v.length;x0||this.Get("scriptlevel")>0)&&g>=0){return""}return this.TEXSPACELENGTH[Math.abs(g)]},TEXSPACELENGTH:["",a.LENGTH.THINMATHSPACE,a.LENGTH.MEDIUMMATHSPACE,a.LENGTH.THICKMATHSPACE],TEXSPACE:[[0,-1,2,3,0,0,0,1],[-1,-1,0,3,0,0,0,1],[2,2,0,0,2,0,0,2],[3,3,0,0,3,0,0,3],[0,0,0,0,0,0,0,0],[0,-1,2,3,0,0,0,1],[1,1,0,1,1,1,1,1],[1,-1,2,3,1,0,1,1]],autoDefault:function(e){return""},isSpacelike:function(){return false},isEmbellished:function(){return false},Core:function(){return this},CoreMO:function(){return this},childIndex:function(g){if(g==null){return}for(var f=0,e=this.data.length;f=55296&&e.charCodeAt(0)<56320)?a.VARIANT.ITALIC:a.VARIANT.NORMAL)}return""},setTeXclass:function(f){this.getPrevClass(f);var e=this.data.join("");if(e.length>1&&e.match(/^[a-z][a-z0-9]*$/i)&&this.texClass===a.TEXCLASS.ORD){this.texClass=a.TEXCLASS.OP;this.autoOP=true}return this}});a.mn=a.mbase.Subclass({type:"mn",isToken:true,texClass:a.TEXCLASS.ORD,defaults:{mathvariant:a.INHERIT,mathsize:a.INHERIT,mathbackground:a.INHERIT,mathcolor:a.INHERIT,dir:a.INHERIT}});a.mo=a.mbase.Subclass({type:"mo",isToken:true,defaults:{mathvariant:a.INHERIT,mathsize:a.INHERIT,mathbackground:a.INHERIT,mathcolor:a.INHERIT,dir:a.INHERIT,form:a.AUTO,fence:a.AUTO,separator:a.AUTO,lspace:a.AUTO,rspace:a.AUTO,stretchy:a.AUTO,symmetric:a.AUTO,maxsize:a.AUTO,minsize:a.AUTO,largeop:a.AUTO,movablelimits:a.AUTO,accent:a.AUTO,linebreak:a.LINEBREAK.AUTO,lineleading:a.INHERIT,linebreakstyle:a.AUTO,linebreakmultchar:a.INHERIT,indentalign:a.INHERIT,indentshift:a.INHERIT,indenttarget:a.INHERIT,indentalignfirst:a.INHERIT,indentshiftfirst:a.INHERIT,indentalignlast:a.INHERIT,indentshiftlast:a.INHERIT,texClass:a.AUTO},defaultDef:{form:a.FORM.INFIX,fence:false,separator:false,lspace:a.LENGTH.THICKMATHSPACE,rspace:a.LENGTH.THICKMATHSPACE,stretchy:false,symmetric:false,maxsize:a.SIZE.INFINITY,minsize:"0em",largeop:false,movablelimits:false,accent:false,linebreak:a.LINEBREAK.AUTO,lineleading:"1ex",linebreakstyle:"before",indentalign:a.INDENTALIGN.AUTO,indentshift:"0",indenttarget:"",indentalignfirst:a.INDENTALIGN.INDENTALIGN,indentshiftfirst:a.INDENTSHIFT.INDENTSHIFT,indentalignlast:a.INDENTALIGN.INDENTALIGN,indentshiftlast:a.INDENTSHIFT.INDENTSHIFT,texClass:a.TEXCLASS.REL},SPACE_ATTR:{lspace:1,rspace:2},useMMLspacing:3,hasMMLspacing:function(){if(this.useMMLspacing){return true}return this.form&&(this.OPTABLE[this.form]||{})[this.data.join("")]},autoDefault:function(g,n){var l=this.def;if(!l){if(g==="form"){return this.getForm()}var k=this.data.join("");var f=[this.Get("form"),a.FORM.INFIX,a.FORM.POSTFIX,a.FORM.PREFIX];for(var h=0,e=f.length;h=55296&&k<56320){k=(((k-55296)<<10)+(j.charCodeAt(1)-56320))+65536}for(var g=0,e=this.RANGES.length;g=0;e--){if(this.data[0]&&!this.data[e].isSpacelike()){return this.data[e]}}return null},Core:function(){if(!(this.isEmbellished())||typeof(this.core)==="undefined"){return this}return this.data[this.core]},CoreMO:function(){if(!(this.isEmbellished())||typeof(this.core)==="undefined"){return this}return this.data[this.core].CoreMO()},toString:function(){if(this.inferred){return"["+this.data.join(",")+"]"}return this.SUPER(arguments).toString.call(this)},setTeXclass:function(g){var f,e=this.data.length;if((this.open||this.close)&&(!g||!g.fnOP)){this.getPrevClass(g);g=null;for(f=0;f0){e++}return e},adjustChild_texprimestyle:function(e){if(e==this.den){return true}return this.Get("texprimestyle")},setTeXclass:a.mbase.setSeparateTeXclasses});a.msqrt=a.mbase.Subclass({type:"msqrt",inferRow:true,linebreakContainer:true,texClass:a.TEXCLASS.ORD,setTeXclass:a.mbase.setSeparateTeXclasses,adjustChild_texprimestyle:function(e){return true}});a.mroot=a.mbase.Subclass({type:"mroot",linebreakContainer:true,texClass:a.TEXCLASS.ORD,adjustChild_displaystyle:function(e){if(e===1){return false}return this.Get("displaystyle")},adjustChild_scriptlevel:function(f){var e=this.Get("scriptlevel");if(f===1){e+=2}return e},adjustChild_texprimestyle:function(e){if(e===0){return true}return this.Get("texprimestyle")},setTeXclass:a.mbase.setSeparateTeXclasses});a.mstyle=a.mbase.Subclass({type:"mstyle",isSpacelike:a.mbase.childrenSpacelike,isEmbellished:a.mbase.childEmbellished,Core:a.mbase.childCore,CoreMO:a.mbase.childCoreMO,inferRow:true,defaults:{scriptlevel:a.INHERIT,displaystyle:a.INHERIT,scriptsizemultiplier:Math.sqrt(1/2),scriptminsize:"8pt",mathbackground:a.INHERIT,mathcolor:a.INHERIT,dir:a.INHERIT,infixlinebreakstyle:a.LINEBREAKSTYLE.BEFORE,decimalseparator:"."},adjustChild_scriptlevel:function(g){var f=this.scriptlevel;if(f==null){f=this.Get("scriptlevel")}else{if(String(f).match(/^ *[-+]/)){var e=this.Get("scriptlevel",null,true);f=e+parseInt(f)}}return f},inheritFromMe:true,noInherit:{mpadded:{width:true,height:true,depth:true,lspace:true,voffset:true},mtable:{width:true,height:true,depth:true,align:true}},getRemoved:{fontfamily:"fontFamily",fontweight:"fontWeight",fontstyle:"fontStyle",fontsize:"fontSize"},setTeXclass:a.mbase.setChildTeXclass});a.merror=a.mbase.Subclass({type:"merror",inferRow:true,linebreakContainer:true,texClass:a.TEXCLASS.ORD});a.mpadded=a.mbase.Subclass({type:"mpadded",inferRow:true,isSpacelike:a.mbase.childrenSpacelike,isEmbellished:a.mbase.childEmbellished,Core:a.mbase.childCore,CoreMO:a.mbase.childCoreMO,defaults:{mathbackground:a.INHERIT,mathcolor:a.INHERIT,width:"",height:"",depth:"",lspace:0,voffset:0},setTeXclass:a.mbase.setChildTeXclass});a.mphantom=a.mbase.Subclass({type:"mphantom",texClass:a.TEXCLASS.ORD,inferRow:true,isSpacelike:a.mbase.childrenSpacelike,isEmbellished:a.mbase.childEmbellished,Core:a.mbase.childCore,CoreMO:a.mbase.childCoreMO,setTeXclass:a.mbase.setChildTeXclass});a.mfenced=a.mbase.Subclass({type:"mfenced",defaults:{mathbackground:a.INHERIT,mathcolor:a.INHERIT,open:"(",close:")",separators:","},addFakeNodes:function(){var f=this.getValues("open","close","separators");f.open=f.open.replace(/[ \t\n\r]/g,"");f.close=f.close.replace(/[ \t\n\r]/g,"");f.separators=f.separators.replace(/[ \t\n\r]/g,"");if(f.open!==""){this.SetData("open",a.mo(f.open).With({fence:true,form:a.FORM.PREFIX,texClass:a.TEXCLASS.OPEN}))}if(f.separators!==""){while(f.separators.length0){return false}return this.Get("displaystyle")},adjustChild_scriptlevel:function(f){var e=this.Get("scriptlevel");if(f>0){e++}return e},adjustChild_texprimestyle:function(e){if(e===this.sub){return true}return this.Get("texprimestyle")},setTeXclass:a.mbase.setBaseTeXclasses});a.msub=a.msubsup.Subclass({type:"msub"});a.msup=a.msubsup.Subclass({type:"msup",sub:2,sup:1});a.mmultiscripts=a.msubsup.Subclass({type:"mmultiscripts",adjustChild_texprimestyle:function(e){if(e%2===1){return true}return this.Get("texprimestyle")}});a.mprescripts=a.mbase.Subclass({type:"mprescripts"});a.none=a.mbase.Subclass({type:"none"});a.munderover=a.mbase.Subclass({type:"munderover",base:0,under:1,over:2,sub:1,sup:2,ACCENTS:["","accentunder","accent"],linebreakContainer:true,isEmbellished:a.mbase.childEmbellished,Core:a.mbase.childCore,CoreMO:a.mbase.childCoreMO,defaults:{mathbackground:a.INHERIT,mathcolor:a.INHERIT,accent:a.AUTO,accentunder:a.AUTO,align:a.ALIGN.CENTER,texClass:a.AUTO,subscriptshift:"",superscriptshift:""},autoDefault:function(e){if(e==="texClass"){return(this.isEmbellished()?this.CoreMO().Get(e):a.TEXCLASS.ORD)}if(e==="accent"&&this.data[this.over]){return this.data[this.over].CoreMO().Get("accent")}if(e==="accentunder"&&this.data[this.under]){return this.data[this.under].CoreMO().Get("accent")}return false},adjustChild_displaystyle:function(e){if(e>0){return false}return this.Get("displaystyle")},adjustChild_scriptlevel:function(g){var f=this.Get("scriptlevel");var e=(this.data[this.base]&&!this.Get("displaystyle")&&this.data[this.base].CoreMO().Get("movablelimits"));if(g==this.under&&(e||!this.Get("accentunder"))){f++}if(g==this.over&&(e||!this.Get("accent"))){f++}return f},adjustChild_texprimestyle:function(e){if(e===this.base&&this.data[this.over]){return true}return this.Get("texprimestyle")},setTeXclass:a.mbase.setBaseTeXclasses});a.munder=a.munderover.Subclass({type:"munder"});a.mover=a.munderover.Subclass({type:"mover",over:1,under:2,sup:1,sub:2,ACCENTS:["","accent","accentunder"]});a.mtable=a.mbase.Subclass({type:"mtable",defaults:{mathbackground:a.INHERIT,mathcolor:a.INHERIT,align:a.ALIGN.AXIS,rowalign:a.ALIGN.BASELINE,columnalign:a.ALIGN.CENTER,groupalign:"{left}",alignmentscope:true,columnwidth:a.WIDTH.AUTO,width:a.WIDTH.AUTO,rowspacing:"1ex",columnspacing:".8em",rowlines:a.LINES.NONE,columnlines:a.LINES.NONE,frame:a.LINES.NONE,framespacing:"0.4em 0.5ex",equalrows:false,equalcolumns:false,displaystyle:false,side:a.SIDE.RIGHT,minlabelspacing:"0.8em",texClass:a.TEXCLASS.ORD,useHeight:1},adjustChild_displaystyle:function(){return(this.displaystyle!=null?this.displaystyle:this.defaults.displaystyle)},inheritFromMe:true,noInherit:{mover:{align:true},munder:{align:true},munderover:{align:true},mtable:{align:true,rowalign:true,columnalign:true,groupalign:true,alignmentscope:true,columnwidth:true,width:true,rowspacing:true,columnspacing:true,rowlines:true,columnlines:true,frame:true,framespacing:true,equalrows:true,equalcolumns:true,displaystyle:true,side:true,minlabelspacing:true,texClass:true,useHeight:1}},linebreakContainer:true,Append:function(){for(var f=0,e=arguments.length;f>10)+55296)+String.fromCharCode((e&1023)+56320)}});a.xml=a.mbase.Subclass({type:"xml",Init:function(){this.div=document.createElement("div");return this.SUPER(arguments).Init.apply(this,arguments)},Append:function(){for(var f=0,e=arguments.length;f":d.REL,"?":[1,1,b.CLOSE],"\\":d.ORD,"^":d.ORD11,_:d.ORD11,"|":[2,2,b.ORD,{fence:true,stretchy:true,symmetric:true}],"#":d.ORD,"$":d.ORD,"\u002E":[0,3,b.PUNCT,{separator:true}],"\u02B9":d.ORD,"\u0300":d.ACCENT,"\u0301":d.ACCENT,"\u0303":d.WIDEACCENT,"\u0304":d.ACCENT,"\u0306":d.ACCENT,"\u0307":d.ACCENT,"\u0308":d.ACCENT,"\u030C":d.ACCENT,"\u0332":d.WIDEACCENT,"\u0338":d.REL4,"\u2015":[0,0,b.ORD,{stretchy:true}],"\u2017":[0,0,b.ORD,{stretchy:true}],"\u2020":d.BIN3,"\u2021":d.BIN3,"\u20D7":d.ACCENT,"\u2111":d.ORD,"\u2113":d.ORD,"\u2118":d.ORD,"\u211C":d.ORD,"\u2205":d.ORD,"\u221E":d.ORD,"\u2305":d.BIN3,"\u2306":d.BIN3,"\u2322":d.REL4,"\u2323":d.REL4,"\u2329":d.OPEN,"\u232A":d.CLOSE,"\u23AA":d.ORD,"\u23AF":[0,0,b.ORD,{stretchy:true}],"\u23B0":d.OPEN,"\u23B1":d.CLOSE,"\u2500":d.ORD,"\u25EF":d.BIN3,"\u2660":d.ORD,"\u2661":d.ORD,"\u2662":d.ORD,"\u2663":d.ORD,"\u3008":d.OPEN,"\u3009":d.CLOSE,"\uFE37":d.WIDEACCENT,"\uFE38":d.WIDEACCENT}}},{OPTYPES:d});var c=a.mo.prototype.OPTABLE;c.infix["^"]=d.WIDEREL;c.infix._=d.WIDEREL;c.prefix["\u2223"]=d.OPEN;c.prefix["\u2225"]=d.OPEN;c.postfix["\u2223"]=d.CLOSE;c.postfix["\u2225"]=d.CLOSE})(MathJax.ElementJax.mml);MathJax.ElementJax.mml.loadComplete("jax.js");
+MathJax.Hub.Register.LoadHook("[MathJax]/jax/element/mml/jax.js",function(){var c="2.7.5";var a=MathJax.ElementJax.mml,b=MathJax.Hub.config.menuSettings;a.mbase.Augment({toMathML:function(l){var h=(this.inferred&&this.parent.inferRow);if(l==null){l=""}var f=this.type,e=this.toMathMLattributes();if(f==="mspace"){return l+"<"+f+e+" />"}var k=[],j=(this.isToken?"":l+(h?"":" "));for(var g=0,d=this.data.length;g ")}}}if(this.isToken||this.isChars){return l+"<"+f+e+">"+k.join("")+""+f+">"}if(h){return k.join("\n")}if(k.length===0||(k.length===1&&k[0]==="")){return l+"<"+f+e+" />"}return l+"<"+f+e+">\n"+k.join("\n")+"\n"+l+""+f+">"},toMathMLattributes:function(){var j=(this.type==="mstyle"?a.math.prototype.defaults:this.defaults);var h=(this.attrNames||a.copyAttributeNames),g=a.skipAttributes,l=a.copyAttributes;var e=[];if(this.type==="math"&&(!this.attr||!("xmlns" in this.attr))){e.push('xmlns="http://www.w3.org/1998/Math/MathML"')}if(!this.attrNames){for(var k in j){if(!g[k]&&!l[k]&&j.hasOwnProperty(k)){if(this[k]!=null&&this[k]!==j[k]){if(this.Get(k,null,1)!==this[k]){e.push(k+'="'+this.toMathMLattribute(this[k])+'"')}}}}}for(var f=0,d=h.length;f126||(k<32&&k!==10&&k!==13&&k!==9)){f[g]=""+k.toString(16).toUpperCase()+";"}else{var j={"&":"&","<":"<",">":">",'"':"""}[f[g]];if(j){f[g]=j}}}else{if(g+11);var p=this.type,k=this.toMathMLattributes();var j=[],o=d+(g?" "+(n?" ":""):"")+" ";for(var h=0,f=this.data.length;h ")}}if(j.length===0||(j.length===1&&j[0]==="")){if(!g){return"<"+p+k+" />"}j.push(o+" ")}if(g){if(n){j.unshift(d+" ");j.push(d+" ")}j.unshift(d+" ");var l=e.originalText.replace(/[&<>]/g,function(i){return{">":">","<":"<","&":"&"}[i]});j.push(d+' '+l+" ");j.push(d+" ")}return d+"<"+p+k+">\n"+j.join("\n")+"\n"+d+""+p+">"}});a.msubsup.Augment({toMathML:function(j){var f=this.type;if(this.data[this.sup]==null){f="msub"}if(this.data[this.sub]==null){f="msup"}var e=this.toMathMLattributes();delete this.data[0].inferred;var h=[];for(var g=0,d=this.data.length;g\n"+h.join("\n")+"\n"+j+""+f+">"}});a.munderover.Augment({toMathML:function(k){var f=this.type;var j=this.data[this.base];if(j&&j.isa(a.TeXAtom)&&j.movablelimits&&!j.Get("displaystyle")){type="msubsup";if(this.data[this.under]==null){f="msup"}if(this.data[this.over]==null){f="msub"}}else{if(this.data[this.under]==null){f="mover"}if(this.data[this.over]==null){f="munder"}}var e=this.toMathMLattributes();delete this.data[0].inferred;var h=[];for(var g=0,d=this.data.length;g\n"+h.join("\n")+"\n"+k+""+f+">"}});a.TeXAtom.Augment({toMathML:function(e){var d=this.toMathMLattributes();if(!d&&this.data[0].data.length===1){return e.substr(2)+this.data[0].toMathML(e)}return e+"