├── .github └── ISSUE_TEMPLATE │ ├── code-coverage---repair-rejects-valid-code-.md │ └── commands-functionality-bug-report.md ├── .no-sublime-package ├── .pylintrc ├── .readthedocs.yml ├── .travis.yml ├── CHANGELOG.md ├── DEPENDENCES_LICENSE.md ├── LICENSE ├── Main.sublime-menu ├── README.md ├── application ├── README.md ├── __init__py.py ├── application.py ├── build_cache.py └── state_update.py ├── bundles ├── Aenea │ ├── PythonVoiceCodingPluginAeneaServer.py │ ├── PythonVoiceCodingPluginAeneaServer.yapsy-plugin │ └── README.md ├── Caster │ ├── README.md │ ├── python_voice_coding_plugin_caster_v0-5-11.py │ ├── python_voice_coding_plugin_caster_v0-6-11.py │ └── python_voice_coding_plugin_caster_v1-0-0.py └── README.md ├── doc ├── CollectionQueries.md ├── Installation.md ├── Operations.md ├── README.md ├── SelectArgument.md ├── SelectBigROI.md ├── SubIndexing.md └── gif │ ├── README.md │ ├── arg0.gif │ ├── arg1.gif │ ├── arg10.gif │ ├── arg11.gif │ ├── arg12.gif │ ├── arg13.gif │ ├── arg14.gif │ ├── arg15.gif │ ├── arg16.gif │ ├── arg17.gif │ ├── arg18.gif │ ├── arg19.gif │ ├── arg2.gif │ ├── arg20.gif │ ├── arg21.gif │ ├── arg22.gif │ ├── arg3.gif │ ├── arg4.gif │ ├── arg5.gif │ ├── arg6.gif │ ├── arg7.gif │ ├── arg8.gif │ ├── arg9.gif │ ├── big0.gif │ ├── big1.gif │ ├── big10.gif │ ├── big11.gif │ ├── big12.gif │ ├── big2.gif │ ├── big20.gif │ ├── big21.gif │ ├── big22.gif │ ├── big23.gif │ ├── big24.gif │ ├── big25.gif │ ├── big26.gif │ ├── big27.gif │ ├── big28.gif │ ├── big29.gif │ ├── big3.gif │ ├── big30.gif │ ├── big31.gif │ ├── big32.gif │ ├── big33.gif │ ├── big34.gif │ ├── big35.gif │ ├── big36.gif │ ├── big37.gif │ ├── big38.gif │ ├── big39.gif │ ├── big4.gif │ ├── big41.gif │ ├── big42.gif │ ├── big43.gif │ ├── big44.gif │ ├── big5.gif │ ├── big6.gif │ ├── big7.gif │ ├── big8.gif │ ├── big9.gif │ ├── bug1.gif │ ├── bug2.gif │ ├── collect1.gif │ ├── collect2.gif │ ├── collect3.gif │ ├── collect4.gif │ ├── collect5.gif │ ├── collect6.gif │ ├── collect7.gif │ ├── d1.gif │ ├── d2.gif │ ├── d3.gif │ ├── d4.gif │ ├── d5.gif │ ├── d6.gif │ ├── del1.gif │ ├── example_1.gif │ ├── example_2.gif │ ├── example_3.gif │ ├── example_4.gif │ ├── example_5.gif │ ├── example_6.gif │ ├── install1.gif │ ├── install2.gif │ ├── l2.gif │ ├── op1.gif │ ├── op10.gif │ ├── op11.gif │ ├── op12.gif │ ├── op13.gif │ ├── op14.gif │ ├── op15.gif │ ├── op16.gif │ ├── op17.gif │ ├── op19.gif │ ├── op2.gif │ ├── op20.gif │ ├── op21.gif │ ├── op22.gif │ ├── op23.gif │ ├── op24.gif │ ├── op25.gif │ ├── op26.gif │ ├── op28.gif │ ├── op29.gif │ ├── op3.gif │ ├── op30.gif │ ├── op31.gif │ ├── op32.gif │ ├── op33.gif │ ├── op34.gif │ ├── op35.gif │ ├── op36.gif │ ├── op37.gif │ ├── op38.gif │ ├── op4.gif │ ├── op5.gif │ ├── op6.gif │ ├── op7.gif │ ├── op8.gif │ ├── op9.gif │ ├── sub10.gif │ ├── sub11.gif │ ├── sub12.gif │ ├── sub13.gif │ ├── sub14.gif │ ├── sub15.gif │ ├── sub16.gif │ ├── sub17.gif │ ├── sub18.gif │ ├── sub19.gif │ ├── sub2.gif │ ├── sub3.gif │ ├── sub4.gif │ ├── sub5.gif │ ├── sub6.gif │ ├── sub7.gif │ ├── sub8.gif │ └── sub9.gif ├── interface ├── common │ ├── actions.py │ └── utility.py ├── interface.py └── view_info.py ├── library ├── .gitignore ├── BracketMatcher.py ├── LCA.py ├── __init__.py ├── higher.py ├── info.py ├── level_info.py ├── lexical.py ├── modification.py ├── partial.py ├── repair.py ├── selection_node.py └── traverse.py ├── messages.json ├── messages ├── 0.1.0.txt ├── 0.1.1.txt ├── 0.1.2.txt ├── 0.1.3.txt └── install.txt ├── mkdocs.yaml ├── mkdocs.yml ├── python_voice_coding_plugin.py ├── python_voice_coding_plugin.sublime-settings ├── queries ├── README.md ├── __init__.py ├── abstract │ ├── __init__.py │ ├── collection_query.py │ ├── insertion_query.py │ ├── query.py │ └── selection_query.py ├── alternatives.py ├── argument.py ├── big_roi.py ├── collect_class_name.py ├── collect_decorator.py ├── collect_function_name.py ├── collect_imported_value.py ├── collect_module.py ├── collect_parameter.py ├── collect_variable.py ├── delete_alternatives.py ├── insert.py ├── insert_item.py ├── paste_back.py ├── remember_here.py ├── select_back.py ├── select_part.py ├── strategies │ ├── __init__.py │ ├── abstract_vertical.py │ ├── adjective_strategy.py │ ├── item_selection.py │ ├── obtain.py │ ├── primitives.py │ └── state_extraction.py ├── swap_back.py ├── tiebreak.py └── utility.py ├── quick_install_python_voice_coding_plugin.py ├── requirements.txt └── third_party ├── .gitignore ├── README.md ├── astmonkey ├── __init__.py ├── transformers.py ├── utils.py └── visitors.py ├── asttokens ├── __init__.py ├── asttokens.py ├── line_numbers.py ├── mark_tokens.py └── util.py ├── dot_parser.py ├── pydot.py ├── pyparsing.py ├── segment_tree ├── __init__.py ├── operations.py └── segment_tree.py └── six.py /.github/ISSUE_TEMPLATE/code-coverage---repair-rejects-valid-code-.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Code Coverage : Repair Rejects Valid Code ' 3 | about: This concerns bugs where valid code is rejected after being repaired 4 | title: '' 5 | labels: bug, code coverage 6 | assignees: mpourmpoulis 7 | 8 | --- 9 | 10 | 18 | 19 | 20 | 21 | 22 | # Description 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | **Your Code** 31 | 32 | 33 | ```python 34 | 35 | ``` 36 | 37 | 45 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/commands-functionality-bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Commands Functionality Bug Report 3 | about: Report core functionality bugs like a command not running or yielding wrong 4 | result 5 | title: '' 6 | labels: bug 7 | assignees: mpourmpoulis 8 | 9 | --- 10 | 11 | ## Description 12 | 13 | 20 | 21 | **General Information** 22 | 23 | 24 | Plug-In Version: 25 | 26 | **Queries Affected** 27 | 28 | 29 | 30 | - [ ] Argument 31 | 32 | - [ ] Big Roi 33 | 34 | - [ ] Sub Indexing 35 | - [ ] only dedicated Subindexing commands 36 | - [ ] also affect suffixes 37 | 38 | - [ ] Operations 39 | - [ ] Paste 40 | - [ ] Delete 41 | - [ ] Swap 42 | - [ ] Edit 43 | - [ ] Prefix 44 | 45 | - [ ] Collections 46 | 47 | 48 | **Response To Command** 49 | 50 | 51 | 52 | - [ ] the command fails/nothing happens at all 53 | 54 | - [ ] the command select/operates on a wrong result, 55 | - [ ] that did not match your positional description (e.g. grabs an ROI one line above or below the one you wanted) 56 | - [ ] did not match the type of result you are looking for(e.g. you wanted an assertion message but you got assertion condition) 57 | - [ ] or maybe the result was of the correct type and position but it was selected improperly(e.g. you asked for the parameter list of function but the last parameter was not selected) 58 | - [ ] or maybe things are working fine when trying to select a region as a whole but start breaking when you try access smaller pieces of it 59 | - [ ] or perhaps the command did find the correct result but perhaps the alternatives included regions they should not or vice versa. (for instance because the command searched the entire code instead of just the current function or vice versa) 60 | 61 | - [ ] somehow the whole preserving the current state(alternatives,origin,initial_origin and so on) was messed up by the command! For instance, 62 | - [ ] track was lost of initial originand things were pasted back onto the wrong position 63 | - [ ] alternatives were changed when they were supposed not to!(for instance prefix operations are not supposed to do this) 64 | 65 | 66 | - [ ] the command seems to select/operates on a random result 67 | 68 | - [ ] the command has some other unintended behavior 69 | 70 | 71 | 72 | 73 | **Context In Which It Appears** 74 | 75 | 78 | 79 | Does the problem seem to appear or disappear only some of the time? Does there seem to be 80 | 81 | - [ ] spatial context/correlation with the cursor? for instance 82 | - [ ] is it affected by adjustments to the cursor position?() 83 | - [ ] does it make a difference whether you have selected some text or not? 84 | - [ ] does the problem appear only when you're going in one direction? 85 | - [ ] does it have to only do with multiple cursors? 86 | - [ ] or perhaps when switching back-and-forth between single and multiple cursors? 87 | 88 | 89 | 90 | - [ ] a temporal context? 91 | - [ ] does it appear only right after selection query was executed? 92 | - [ ] does it appear only if no one other selection query was executed since the last edit? 93 | - [ ] does it appear only after executing an operation(paste,delete,swap)? 94 | - [ ] does it appear when you perform manual editing between commands? 95 | 96 | - [ ] correlation with a pattern in the code? Such a pattern might be structural, sometimes lexical,in some cases even some piece of incomplete code that was not handled properly. A strong indicator for such a case when introducing small changes to the code has things from working perfectly into breaking. In case you have identified(or you have any suspicion about) this pattern(or maybe patterns), does the error occure when it appears 97 | - [ ] on the target of the query? (For instance there was a bug at some point that sometimes prevented you from selecting arguments from function calls inside with statements) 98 | - [ ] on the origin of the query? 99 | - [ ] in between them perhaps? 100 | - [ ] somewhere inside to the current function/class/indentation block/... 101 | - [ ] anywhere in the code :) 102 | 103 | 104 | 105 | 106 | 107 | **Error Message** 108 | 109 | - [ ] error message appears in a pop-up 110 | 111 | - [ ] an exception trace back is printed in the sublime console(Ctrl + \`) 112 | 113 | - [ ] the command fails silently 114 | 115 | 120 | -------------------------------------------------------------------------------- /.no-sublime-package: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [TYPECHECK] 2 | ignored-modules=sublime,sublime_plugin,package_control 3 | 4 | [MASTER] 5 | # init-hook='import sys; sys.path.append("C:\\Users\\Admin\\AppData\\Roaming\\Sublime Text 3\\Packages")' 6 | init-hook="from pylint.config import find_pylintrc; import os, sys; sys.path.append(os.path.dirname(os.path.dirname(find_pylintrc())))" 7 | 8 | [MESSAGES CONTROL] 9 | disable=all 10 | 11 | 12 | 13 | enable=E 14 | 15 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Build documentation with MkDocs 9 | mkdocs: 10 | configuration: mkdocs.yml 11 | 12 | # Optionally build your docs in additional formats such as PDF and ePub 13 | # formats: all 14 | 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | jobs: 3 | include: 4 | - name: "Windows Lint" 5 | os: windows 6 | language: sh 7 | python: "3.7" 8 | cache: pip 9 | before_install: 10 | - choco install python --version 3.7.3 11 | - export PATH="/c/Python37:/c/Python37/Scripts:$PATH" 12 | - pip install pylint 13 | script: 14 | - pylint library queries application interface python_voice_coding_plugin.py 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.1.2] 4 | 5 | ### Added 6 | 7 | - Utility to automatically upgrade scripts in the preferences menu 8 | 9 | ### Fixed 10 | 11 | - Fixed the massive subl blunder 12 | 13 | 14 | ## [0.1.1] 15 | 16 | ### Added 17 | 18 | - a bunch of preliminary versions for small regions of interest were added in the unofficial features. 19 | 20 | - recommendation has been updated to include links to the gitter chanell 21 | 22 | - the sublime menu has been edited accordingly as well! 23 | 24 | 25 | 26 | ### Fixed 27 | 28 | - fixed a nasty bug in the argument queries, which prevented above/below queries to select parts of calls inside with clauses and for loops( it did not affect counting though) 29 | 30 | - fixed a bug regarding empty definition parameter lists, where the initial "def" keyword would be selected. Now the cursor is correct placed between the empty brackets 31 | 32 | - documentation fix, the documentation for the same keyword was pointing to the unofficial small regions of interest 33 | 34 | ### Changed 35 | 36 | - the escaping problems faced with quotes and other special characters were lifted( see below for details ) 37 | 38 | - the repair module now supports correcting cases where the return keyword is followed by invalid code 39 | 40 | - changes in the code for the sublime grammar communication on the grammar side, issues with escaping characters and occasionally losing focus have been lifted via RunCommand ( custom solution 0.5.11 ) 41 | 42 | 43 | 44 | 45 | 46 | 47 | ## [0.0.5 and 0.1.0 are not really change loged properly] 48 | 49 | ### Added 50 | 51 | * upgrades in the paste back query where it can now support surrounded punctuation. 52 | 53 | * the module delete alternatives has been added. 54 | 55 | * View information now also exposes they get regions sublime API 56 | 57 | * The interface module now has a clear_actions methods to flush the already pushed actions. 58 | 59 | ### Fixed 60 | 61 | * fixed an important bug in the insertion query module. the writing positions were sorted, but on an ascending order which simply broke everything when there are multiple of them. Fix this to sort them in descending order, so the changes that are executed first do not affect the others. 62 | 63 | ### Changed 64 | 65 | * the application module has been adopted, sought after selection queries we do not only store that arraigns corresponding to the main result in the alternative but we also keep the corresponding text. 66 | 67 | * the paste back query now reads the corresponding text directly from the state instead of getting their location and obtaining from the code as it did in the past 68 | 69 | ## [0.0.4] - 2019-11-27 70 | 71 | ### Added 72 | 73 | * aenea support has been added by means of the server plug-ins, available in the bundles aenea folder. this includes both the PythonVoiceCodingPluginAeneaServer.py and the corresponding yapsy-plugin file. 74 | 75 | * in the tiebreak module function tiebreak_on_visual has been added, to enable more coherent tie-breaking 76 | 77 | * PopUpErrorAction has been added in order to inform the user in cases where to cannot parse the source code. 78 | 79 | * Sublime settings file has been added, from which you can turn on or off, showing the main result when it is not visible as well as the pop-ups with error information. 80 | 81 | ### Fixed 82 | 83 | * fixed the empty brackets bug in the repair modulebugs with ":" addressed, needs more testing and a subsequent bug 84 | 85 | * also in the repair module, we can now handle consecutive space separated name tokens( and some mixing with error tokens) like the ones that can occur after a misrecognition, for instance "x = gibberish words " is now parsable! 86 | 87 | * fixed one error in vertical direction + big_roi queries, which appeared when a region of interest spanned across multiple physical lines and was the selection origin of a query searching for a region of interest of the same kind and was causing an off by one error when going upwards. 88 | 89 | * Fixed error in big_roi module , where when trying to select something in global scope with vertical direction big_roi_queries ,not checking definition_node for Nonetype object caused error 90 | 91 | * Fixed error in the preliminary function of the big regions of interest, where if the cursor was at the last empty line of the function, selections would be given from the next function! 92 | 93 | * Fixed old name of my output panel:) 94 | 95 | * Fixed a bug in the argument module where not forwarding/backwarding selections could cause errors for the above below keywords. 96 | 97 | * fixed a bug in the above/below argument command, which occasionally caused of by one errors. 98 | 99 | * in the info module, fixed a bug in the get_body function where ast.IfExp was missing for some reason 100 | 101 | * Yet another forwarding bug in the argument module:( 102 | 103 | * fix a bug in the big region of interest module which caused off by one error in the above below command, when the original selection was in an empty line. 104 | 105 | ### Changed 106 | 107 | * The Caster bundles have been modified to be usable with aenea! both the 0.5 and 0.6 versions have been tested, with PythonVoiceCodingPlugin running on Ubuntu 16.04. 108 | 109 | * collection queries now have labels(names) and they display them on the output panel. 110 | 111 | * a global state was added the application module, enabling insertion from the results of collection queries from other files 112 | 113 | * collecting modules now also collects subparts of the import paths. For example if you importfrom x.y.z, all three [x.y.z,x.y,x] paths are collected! 114 | 115 | * In the actions module, the SelectionAction now also shows the main result if it is not visible! works both for selection queries and paste back operations! 116 | 117 | * sub indexing moved from big_roi to info module! 118 | 119 | 120 | 121 | * furthermore , you can now sub index strings, arithmetical operations and more! Regarding strings, you can now get words of the sentenceseparated by space or by full stop, but you can also pick up parts of the snake or camel case words individual letters , as well as parts of a URL( little more work is needed for the latter)! 122 | 123 | * the abstract_vertical and big_roi modules have been modified so as to offer alternatives when there are multiple logical lines in the same physical line. 124 | 125 | * argument,adjective_strategy,primitives have been mortified in order to standardize the behavior of the grammar when the target logical line response over multiple physical ones. 126 | 127 | * furthermore, the issue with alternatives common from wrong direction and not close to the main result has been resolved when used with above/ below keyword by means of tiebreak_on_visual function! 128 | 129 | * additionally, even in case of ties when tie-breaking on the lowest common ancestor, the visual proximity is now taken into account! 130 | 131 | * in the partial module, the function partially_parse has been modified in order to accept one more optional Boolean parameter which when True causes the function to raise the initial syntax error it captured instead of returning None objects. By default the parameter is set to False. 132 | 133 | * In the same spirit, the query module has been modified and has a new attribute in order to store the above exception. The application module checks if this attribute HUD stored exception and displays an error through the PopUpErrorAction! 134 | 135 | * The interface module has been modified to accept settings in its constructor. 136 | 137 | ## [0.0.3] - 2019-11-18 138 | 139 | important patch 140 | 141 | ### Fixed 142 | 143 | * The third party folder was not in the Python path, so imports from the dependencies asking for other dependencies failed! 144 | 145 | ### Added 146 | 147 | once again, thanks to thanks to @LexiconCode there are bundles for the upcoming 1.0.0 release of Caster 148 | 149 | - python_voice_coding_plugin_caster_v1-0-0 150 | 151 | ## [0.0.2] - 2019-11-15 152 | 153 | Caster 0.6.11 support many thanks to @LexiconCode 154 | 155 | ### Added 156 | 157 | In the grammar section there are now two scripts: 158 | 159 | - python_voice_coding_plugin_caster_v0-6-11 160 | - python_voice_coding_plugin_caster_v0-5-11 161 | 162 | ## [0.0.1] - 2019-11-14 163 | 164 | I think these are the most important changes , I hope I didn't forget any! 165 | 166 | ### Added 167 | 168 | * Improvements in the sub indexing of big regions of interest , among others the ability to select parts of comparisons and slicing/indexes 169 | 170 | ### Fixed 171 | 172 | Various bug fixes most importantly in the following modules: 173 | 174 | * big_roi 175 | 176 | * repair: repaired the bug about repairing ".", empty compounds and more 177 | 178 | * obtain, fixed the bug where the main result could appear in the alternatives! 179 | 180 | * higher, correct error regarding await but not sure yet need to revisit! 181 | 182 | -------------------------------------------------------------------------------- /DEPENDENCES_LICENSE.md: -------------------------------------------------------------------------------- 1 | # libraries licenses 2 | 3 | Licenses for my dependencies, I have copy pasted them from your github repositories, if you see anything wrong please contact me! 4 | 5 | ## pyparsing 6 | 7 | ``` 8 | # Copyright (c) 2003-2019 Paul T. McGuire 9 | # 10 | # Permission is hereby granted, free of charge, to any person obtaining 11 | # a copy of this software and associated documentation files (the 12 | # "Software"), to deal in the Software without restriction, including 13 | # without limitation the rights to use, copy, modify, merge, publish, 14 | # distribute, sublicense, and/or sell copies of the Software, and to 15 | # permit persons to whom the Software is furnished to do so, subject to 16 | # the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be 19 | # included in all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 25 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 26 | # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 27 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | ``` 30 | 31 | ## asttokens 32 | 33 | ``` 34 | # Copyright 2016 Grist Labs, Inc. 35 | # 36 | # Licensed under the Apache License, Version 2.0 (the "License"); 37 | # you may not use this file except in compliance with the License. 38 | # You may obtain a copy of the License at 39 | # 40 | # http://www.apache.org/licenses/LICENSE-2.0 41 | # 42 | # Unless required by applicable law or agreed to in writing, software 43 | # distributed under the License is distributed on an "AS IS" BASIS, 44 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 45 | # See the License for the specific language governing permissions and 46 | # limitations under the License. 47 | ``` 48 | 49 | ## astmonkey 50 | 51 | ``` 52 | Copyright [2013] [Konrad Hałas] 53 | 54 | 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 55 | 56 | http://www.apache.org/licenses/LICENSE-2.0 57 | 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. 58 | ``` 59 | 60 | ## six 61 | 62 | ``` 63 | Copyright (c) 2010-2019 Benjamin Peterson 64 | 65 | Permission is hereby granted, free of charge, to any person obtaining a copy of 66 | this software and associated documentation files (the "Software"), to deal in 67 | the Software without restriction, including without limitation the rights to 68 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 69 | the Software, and to permit persons to whom the Software is furnished to do so, 70 | subject to the following conditions: 71 | 72 | The above copyright notice and this permission notice shall be included in all 73 | copies or substantial portions of the Software. 74 | 75 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 76 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 77 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 78 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 79 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 80 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 81 | ``` 82 | 83 | ## segment_tree 84 | 85 | ``` 86 | MIT License 87 | 88 | Copyright (c) 2017 Evgeny Yurtaev 89 | 90 | Permission is hereby granted, free of charge, to any person obtaining a copy 91 | of this software and associated documentation files (the "Software"), to deal 92 | in the Software without restriction, including without limitation the rights 93 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 94 | copies of the Software, and to permit persons to whom the Software is 95 | furnished to do so, subject to the following conditions: 96 | 97 | The above copyright notice and this permission notice shall be included in all 98 | copies or substantial portions of the Software. 99 | 100 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 101 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 102 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 103 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 104 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 105 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 106 | SOFTWARE. 107 | ``` 108 | 109 | ## pydot 110 | 111 | ``` 112 | Copyright (c) 2014 Carlos Jenkins 113 | Copyright (c) 2014 Lance Helper 114 | Copyright (c) 2004 Ero Carrera 115 | 116 | Permission is hereby granted, free of charge, to any person obtaining a copy 117 | of this software and associated documentation files (the "Software"), to deal 118 | in the Software without restriction, including without limitation the rights 119 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 120 | copies of the Software, and to permit persons to whom the Software is 121 | furnished to do so, subject to the following conditions: 122 | 123 | The above copyright notice and this permission notice shall be included in all 124 | copies or substantial portions of the Software. 125 | 126 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 127 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 128 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 129 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 130 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 131 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 132 | SOFTWARE. 133 | ``` 134 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2019, Kitsios Panagiotis 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "preferences", 4 | "children": 5 | [ 6 | { 7 | "id": "package-settings", 8 | "children": 9 | [ 10 | { 11 | "caption": "PythonVoiceCodingPlugin", 12 | "children": 13 | [ 14 | { 15 | "caption": "Settings", 16 | "command": "edit_settings", 17 | "args": 18 | { 19 | "base_file": "${packages}/PythonVoiceCodingPlugin/python_voice_coding_plugin.sublime-settings", 20 | "default": "{\n\t$0\n}\n" 21 | } 22 | }, 23 | { 24 | "caption":"Gitter Chat Room", 25 | "command": "open_url", 26 | "args":{ 27 | "url":"https://gitter.im/PythonVoiceCodingPlugin/community" 28 | } 29 | }, 30 | { 31 | "caption": "Online Documentation", 32 | "children": 33 | [ 34 | { 35 | "caption": "Argument Queries", 36 | "command": "open_url", 37 | "args":{ 38 | "url": "https://pythonvoicecodingplugin.readthedocs.io/en/latest/SelectArgument/" 39 | } 40 | }, 41 | { 42 | "caption": "Big Roi Queries", 43 | "command": "open_url", 44 | "args":{ 45 | "url":"https://pythonvoicecodingplugin.readthedocs.io/en/latest/SelectBigROI/" 46 | } 47 | }, 48 | { 49 | "caption": "General Documentation", 50 | "command": "open_url", 51 | "args":{ 52 | "url":"https://pythonvoicecodingplugin.readthedocs.io/en/latest/" 53 | } 54 | }, 55 | { 56 | "caption": "Operations", 57 | "command": "open_url", 58 | "args":{ 59 | "url": "https://pythonvoicecodingplugin.readthedocs.io/en/latest/Operations/" 60 | } 61 | }, 62 | { 63 | "caption": "Sub Indexing", 64 | "command": "open_url", 65 | "args":{ 66 | "url": "https://pythonvoicecodingplugin.readthedocs.io/en/latest/SubIndexing/" 67 | } 68 | }, 69 | { 70 | "caption": "CollectionQueries", 71 | "command": "open_url", 72 | "args":{ 73 | "url": "https://pythonvoicecodingplugin.readthedocs.io/en/latest/CollectionQueries/" 74 | } 75 | }, 76 | { 77 | "caption": "Unofficial", 78 | "command": "open_url", 79 | "args":{ 80 | "url": "https://pythonvoicecodingplugin.readthedocs.io/en/latest/#experiment-or-unofficial-and-so-on-features-you-need-to-enable-manually" 81 | } 82 | } 83 | 84 | 85 | 86 | 87 | ] 88 | }, 89 | { 90 | "caption": "Issues", 91 | "command": "open_url", 92 | "args":{ 93 | "url": "https://github.com/mpourmpoulis/PythonVoiceCodingPlugin/issues" 94 | } 95 | }, 96 | 97 | { 98 | "caption":"Grammar for Caster 1.0.0", 99 | "command": "open_file", 100 | "args":{ 101 | "file":"${packages}/PythonVoiceCodingPlugin/bundles/Caster/python_voice_coding_plugin_caster_v1-0-0.py" 102 | } 103 | 104 | 105 | }, 106 | { 107 | "caption":"Grammar for Caster 0.5.11", 108 | "command": "open_file", 109 | "args":{ 110 | "file":"${packages}/PythonVoiceCodingPlugin/bundles/Caster/python_voice_coding_plugin_caster_v0-5-11.py" 111 | } 112 | 113 | 114 | }, 115 | { 116 | "caption":"Grammar for Caster 0.6.11", 117 | "command": "open_file", 118 | "args":{ 119 | "file":"${packages}/PythonVoiceCodingPlugin/bundles/Caster/python_voice_coding_plugin_caster_v0-6-11.py" 120 | } 121 | 122 | 123 | }, 124 | { 125 | "caption": "Grammar Installation Doc", 126 | "command": "open_url", 127 | "args":{ 128 | "url": "https://pythonvoicecodingplugin.readthedocs.io/en/latest/Installation/" 129 | } 130 | }, 131 | { 132 | "caption": "Quick 1.0.0 Installation", 133 | "command": "quick_install_python_voice_coding_plugin", 134 | "args":{} 135 | } 136 | 137 | 138 | 139 | 140 | ] 141 | } 142 | ] 143 | } 144 | ] 145 | } 146 | ] 147 | -------------------------------------------------------------------------------- /application/README.md: -------------------------------------------------------------------------------- 1 | # Application 2 | 3 | -------------------------------------------------------------------------------- /application/__init__py.py: -------------------------------------------------------------------------------- 1 | from PythonVoiceCodingPlugin.application.build_cache import BuildCache 2 | from PythonVoiceCodingPlugin.application.application import Application 3 | 4 | 5 | -------------------------------------------------------------------------------- /application/application.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | from copy import deepcopy 3 | 4 | 5 | from PythonVoiceCodingPlugin.queries import * 6 | from PythonVoiceCodingPlugin.application.build_cache import BuildCache 7 | from PythonVoiceCodingPlugin.application.state_update import clear_state,retrieve_state,retrieve_text,get_location_text,update_changes,update_origin,horizontal_to_vertical 8 | from PythonVoiceCodingPlugin.interface.common.actions import * 9 | 10 | 11 | class Application(): 12 | """docstring for Application""" 13 | active_applications = {} 14 | build_cache = BuildCache() 15 | global_state = {} 16 | global_data = {} 17 | 18 | def __init__(self,vid): 19 | self.history = [] 20 | self.state = { 21 | "result": None, 22 | "origin": None, 23 | "initial_origin":None, 24 | "alternatives": [], 25 | "change_count":-1, 26 | "mode":"single", 27 | "initial_mode":"single", 28 | "initial_count":-1, 29 | } 30 | self.ui_controller = None 31 | self.vid = vid 32 | 33 | @staticmethod 34 | def create_application_for_view(vid): 35 | if vid not in Application.active_applications: 36 | Application.active_applications[vid] = Application(vid) 37 | 38 | @staticmethod 39 | def get_application(vid): 40 | Application.create_application_for_view(vid) 41 | return Application.active_applications[vid] 42 | 43 | def update_text(self,code): 44 | retrieve_text(self.state,code) 45 | 46 | def update_locations(self,locations_text): 47 | update_changes(self.state,locations_text) 48 | 49 | 50 | def respond_to_query(self,interface,query_description,secondary=False): 51 | extra = { 52 | "state":self.state,"global_state":Application.global_state, 53 | "history":self.history,"secondary":secondary,"global_data":Application.global_data, 54 | } 55 | view_information = interface.get_view_information() 56 | ui_information = interface.get_ui_information() 57 | 58 | # extract code and change count and reuse previous build if possible 59 | code = view_information["code"] 60 | change_count = view_information["change_count"] 61 | latest_build = Application.build_cache.get_build(self.vid,change_count) 62 | # print("state\n\n",self.state,"\n\n") 63 | try: 64 | if not secondary: 65 | need_update = retrieve_state(self.state,view_information,code) 66 | 67 | except: 68 | clear_state(self.state) 69 | 70 | # get the corresponding query and execute it 71 | s = get_query(query_description)(code,latest_build) 72 | secondary_query_description = get_secondary_query(query_description) 73 | if secondary_query_description: 74 | self.backup=[deepcopy(self.state),deepcopy(self.global_state)] 75 | should_execute_secondary = True 76 | 77 | try: 78 | s(view_information,query_description,extra) 79 | except Exception as e: 80 | # check if there are exceptions with parsing 81 | if s.exceptions_raised: 82 | # traceback.print_tb(s.exceptions_raised) 83 | interface.clear_actions() 84 | interface.push_action(PopUpErrorAction(str(s.exceptions_raised))) 85 | return False 86 | 87 | interface.clear_actions() 88 | traceback.print_exc() 89 | return False 90 | 91 | 92 | 93 | 94 | 95 | # register build for later use 96 | b = s.get_the_latest_build() 97 | if b: 98 | Application.build_cache.register_build(self.vid,change_count,b) 99 | 100 | if secondary: 101 | self.state,self.global_state = self.backup 102 | 103 | Application.global_data.update(s.data_for_storage) 104 | if isinstance(s,SelectionQuery): 105 | result = s.result 106 | alternatives = s.alternatives 107 | selection = view_information["selection"] 108 | 109 | mode = isinstance(result,list) or isinstance(selection,list) 110 | if not secondary: 111 | update_origin(self.state,"origin",selection,mode) 112 | self.state["mode"] = "multiple" if mode else "single" 113 | if (self.state["initial_count"]=view_information["change_count"]: 158 | return False 159 | if state["change_count"]==-1: 160 | state["change_count"]=view_information["change_count"] 161 | return False 162 | 163 | try : 164 | 165 | convert_single_to_multiple(state,state["mode"],state["initial_mode"]) 166 | sublime_data = {x:get_regions_while_you_still_can(view_information,x) 167 | for x in ["result","origin","alternatives","initial_origin"]} 168 | # print("\nSublime date at ease\n",sublime_data,"\n") 169 | 170 | state = retrieve_primitive(state,sublime_data) 171 | convert_multiple_to_single(state,state["mode"],state["initial_mode"]) 172 | # print("\n\nAfter conversion:\n",state,"\n") 173 | except: 174 | clear_state(state) 175 | retrieve_text(state,code) 176 | raise 177 | # print("Before Retrieving Text:\n",state) 178 | retrieve_text(state,code) 179 | return True 180 | 181 | 182 | 183 | 184 | 185 | 186 | def update_changes(state,locations_text): 187 | def forward(x,m): 188 | if x is None: 189 | return x 190 | if isinstance(x,list): 191 | return [forward(y,m) for y in x] 192 | return m.forward(x) 193 | 194 | m = ModificationHandler() 195 | for location,t in locations_text: 196 | m.modify_from(0, location, t) 197 | 198 | for k in ["result","origin","initial_origin","alternatives"]: 199 | state[k] = forward(state[k],m) 200 | 201 | 202 | def update_origin(state,name,selection,force_multiple): 203 | assert name in state,"I cannot set something that is not in the state"+name 204 | if isinstance(selection,list): 205 | selection = [[x] for x in selection] 206 | elif force_multiple: 207 | selection = [[selection]] 208 | state[name] = selection 209 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /bundles/Aenea/PythonVoiceCodingPluginAeneaServer.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | 4 | from yapsy.IPlugin import IPlugin 5 | 6 | enabled = True 7 | 8 | def python_voice_coding_plugin_aenea_send_sublime(c,data): 9 | x = str(data).replace('\'','\\\"') 10 | x = x.replace("u\\","\\") 11 | y = "subl --command \"" + c + " " + x + "\"" 12 | print(y) 13 | subprocess.call(y, shell = True) 14 | subprocess.call("subl", shell = True) 15 | 16 | class PythonVoiceCodingPluginAenea(IPlugin): 17 | """docstring for PythonVoiceCodingPluginAena""" 18 | def register_rpcs(self,server): 19 | server.register_function(python_voice_coding_plugin_aenea_send_sublime) 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /bundles/Aenea/PythonVoiceCodingPluginAeneaServer.yapsy-plugin: -------------------------------------------------------------------------------- 1 | [Core] 2 | Name = PythonVoiceCodingPluginAeneaServer plugin 3 | Module = PythonVoiceCodingPluginAeneaServer 4 | 5 | 6 | [Documentation] 7 | Author = Kitsios Panagiotis 8 | Version = 0.0 9 | Description = PythonVoiceCodingPluginAeneaServer Custom RPC Plug-in . 10 | -------------------------------------------------------------------------------- /bundles/Aenea/README.md: -------------------------------------------------------------------------------- 1 | # aenea support 2 | 3 | In order to use the custom RPC you need to copy both the py script and the yapsy-plugin inside aenea plug-ins folder. 4 | 5 | This should be inside aenea/server/linux_x11/plugins if you are on a Linux machine. 6 | 7 | ```console 8 | foo@bar:~/aenea/server/linux_x11/plugins$ ls 9 | example.py example.yapsy-plugin PythonVoiceCodingPluginAeneaServer.pyc 10 | example.pyc PythonVoiceCodingPluginAeneaServer.py PythonVoiceCodingPluginAeneaServer.yapsy-plugin 11 | ``` 12 | 13 | When you boot the server, you should see something like: 14 | 15 | ```console 16 | foo@bar:~/aenea/server/linux_x11$ python server_x11.py 17 | 2019-12-01 02:55:23,914 [DEBUG ] [aenea] Loading plugin "Example plugin" 18 | 19 | 2019-12-01 02:55:23,914 [DEBUG ] [aenea] Loading plugin "PythonVoiceCodingPluginAeneaServer plugin" 20 | 21 | 2019-12-01 02:55:23,914 [DEBUG ] [aenea] using XdotoolPlatformRpcs for input emulation 22 | 2019-12-01 02:55:23,914 [DEBUG ] [aenea] starting server on 10.0.2.15:8240 23 | ``` 24 | 25 | The system has been tested on Ubuntu 16.04. If you face any problems, please let me know in the issues with the aenea label! 26 | -------------------------------------------------------------------------------- /bundles/Caster/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bundles/README.md: -------------------------------------------------------------------------------- 1 | # Grammar bundles 2 | 3 | This folder contains my grammar and other related stuff 4 | 5 | For the time being I only release bundles for Caster 0.5.11 and 0.6.11, these are in the Caster folder. 6 | 7 | To install them simply copy paste the script insise caster "apps" folder:) 8 | 9 | once again thanks to @LexiconCode there are bundles for the upcoming Caster 1.0.0 but installation is a bit different(to be updated) 10 | 11 | For use within Linux see also the Aenea folder 12 | 13 | ## Update 14 | 15 | Also you should know that Caster 1.x.x is also supported but you must enable it by saying 16 | 17 | ``` 18 | enable python voice coding plugin 19 | ``` 20 | 21 | also the datum needs to be stored in a different folder. Up until recently these used to be 22 | 23 | ``` 24 | C:\Users\%USERNAME%\.caster\rules 25 | ``` 26 | 27 | but the latest masterhas moved to this folder to 28 | 29 | ``` 30 | C:\Users\%USERNAME%\AppData\Local\caster\rules 31 | ``` 32 | 33 | https://github.com/dictation-toolbox/Caster/pull/718 34 | 35 | -------------------------------------------------------------------------------- /doc/CollectionQueries.md: -------------------------------------------------------------------------------- 1 | # Collection Queries 2 | 3 | ![](./gif/collect0.gif) 4 | 5 | 6 | ## Collecting Interesting Stuff 7 | 8 | to collect interesting stuff, the command 9 | 10 | ```python 11 | "[smart] collect " 12 | ``` 13 | 14 | is available. the `collectable` parameter can have one of the following values 15 | 16 | ```python 17 | Choice("collectable",{ 18 | "(variable|variables)":"variable", 19 | "( parameter | parameters)":"parameter", 20 | "imported value":"import value", 21 | "function (name|names)":"function name", 22 | "class name" : "class name", 23 | "decorator" : "decorator", 24 | } 25 | ) 26 | ``` 27 | 28 | ![](./gif/collect5.gif) 29 | 30 | 31 | Now there are various small things to note: 32 | 33 | * everything is collected from the entire code, so that means that the variables and parameters are collected from other functions as well 34 | 35 | * When you are collecting modules, if you import from x.y.z, all three [x.y.z,x.y,x] paths are collected! 36 | 37 | * When collecting decorators, both the entire decorator as well as the calling function is collected. 38 | 39 | ## Inserting Items 40 | 41 | okay great, so we have collected all the items that you want and they are displayed on the screen. How do you insert them? up to 0.0.4 this syntax was based around `"(smart insert|insert item) "` but with a release of 0.1.0 that `(smart insert|insert item)` has been shortened to `[smart] item` and enhancements have been made, mostly to accommodate the need of quickly inserting multiple items. 42 | 43 | 44 | To that end, the new grammar allows you to 45 | 46 | * specify a range of items 47 | 48 | * Individually describe multiple items in a row by their index 49 | 50 | the corresponding syntax is 51 | 52 | ```python 53 | "[smart] item " 54 | 55 | "[smart] (item|items) (all| until (| the end))" 56 | 57 | "[smart] (item|items) [ and ]" 58 | ``` 59 | 60 | In those multiple values are pasted with commas in between them on the current selection. 61 | To give you an example: 62 | 63 | ![](./gif/collect1.gif) 64 | 65 | please do note, two important factors. `[smart] item` : 66 | 67 | * Does not parse your source code, so it is going to work even if there are fatal errors which might prevent other commands from running 68 | 69 | * because collections currently persist between tabs, you can insert items from other source files! 70 | 71 | * Is going to use the latest collection built, even if the display bar has been hidden because of another query/pressing escape. 72 | 73 | * works with multiple cursors, inserting the same thing in all of them 74 | 75 | To illustrate all of the above: 76 | 77 | ![](./gif/collect2.gif) 78 | 79 | 80 | 81 | 82 | ## Index Collectible 83 | 84 | so far we have seen two discrete rules, one collecting items and displaying them on the bottom of the screen and pond responsible for inserting them. but for two special cases, namely variables and parameters kinda combine them :) 85 | 86 | the core idea is to have commands based on the form 87 | 88 | ```python 89 | "variable " 90 | 91 | "parameter " 92 | ``` 93 | 94 | which are going to collect variables/parameters from the current function and insert them directly. Combined in these with the ideas developed above for inserting multiple items at once, we obtain something of the form 95 | 96 | ### Variables 97 | 98 | ```python 99 | "[smart] variable [[and] [and ]]" 100 | 101 | "[smart] (variables all|variable until (| the end))" 102 | ``` 103 | 104 | ![](./gif/collect3.gif) 105 | 106 | please do pay attention to the fact that variables are extracted only from the current function this time! 107 | 108 | ### Parameters 109 | 110 | something similar applies for parameters as well 111 | 112 | ![](./gif/collect6.gif) 113 | 114 | however in this case we have a little bit more expressiveness available, as we can also insert barometers from other functions! 115 | 116 | 117 | ![](./gif/collect4.gif) 118 | 119 | ```python 120 | "[smart] [ []] parameter [ [and ]]" 121 | 122 | 123 | "[smart] [ []] (parameters all| parameter until (| the end))" 124 | ``` 125 | 126 | notice that the syntax is very similar after the one used by big regions of interest queries `" [] "` for selecting things from other functions, but function is optional, so it can also be used in the more simple and traditional `" []"` this was chosen so most makes things easier to speak into either way we are extracting from function definitions:) 127 | 128 | #### Experimental 129 | 130 | 131 | In the grammar bundles you are going to to see there are some extra commented lines 132 | 133 | ```python 134 | "[smart] [ []] key parameter [ and [and ]]": 135 | lazy_value("collect_parameter",2,experimental = "True"), 136 | 137 | "[smart] [ []] key (parameters all| parameter until (| the end))": 138 | lazy_value("collect_parameter",3,experimental = "True"), 139 | ``` 140 | 141 | 142 | 143 | this is a little bit more functionality that that the backened has been adopted to support but I am still not sure if what it offers is worth the additional grammar complexity. furthermore they are still immature and may be subject to change. As a consequence, I chose not to include them in the "official" grammar but if you want you can enable them yourself by simply commending those lines. 144 | 145 | Essentially they look just like the previous ones but in the spoken form there is a `key` word before the parameter( which of course you can change to what ever you wish) and an additional `experimental = "True"`, which is just a temporary way to inform the plug-in that we want experimental functionality. 146 | 147 | where they defer is that instead of inserting 148 | 149 | ```python 150 | parameter1,parameter2,... 151 | ``` 152 | 153 | they insert 154 | 155 | ```python 156 | parameter1=parameter1,parameter2=parameter2,... 157 | ``` 158 | 159 | 160 | ![](./gif/collect7.gif) 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /doc/Installation.md: -------------------------------------------------------------------------------- 1 | ## Installation 2 | 3 | As this is a two-part system, in order to install, you must 4 | 5 | - install the main plugin 6 | 7 | - install the corresponding [grammar](../bundles/README.md) for the version of caster you are using 8 | 9 | - put the `subl` executable which enables the communication of those two into the Windows path(from 0.1.2 and above optionally) 10 | 11 | 12 | ### Install the main plugin 13 | 14 | There are currently two installation (Package Control and git) methods for performing the first task,I highly recommend using Package Control. 15 | 16 | 17 | #### Package Control 18 | 19 | - Firstly make sure you have Package Control installed. If not, please follow the instructions [here](https://packagecontrol.io/installation) 20 | 21 | - open Command Palette(Control+Shift+P) 22 | 23 | - execute 24 | 25 | ``` 26 | Package Control:Install Package 27 | ``` 28 | 29 | And then simply 30 | 31 | ``` 32 | PythonVoiceCodingPlugin 33 | ``` 34 | 35 | 36 | 37 | ##### Note for those who installed between 0.0.4 and 0.0.5 38 | 39 | previously the installation of plug-in included running 40 | 41 | ``` 42 | Package Control:Add Repository 43 | ``` 44 | 45 | and then entering a URL to my repository 46 | 47 | ``` 48 | https://github.com/mpourmpoulis/PythonVoiceCodingPlugin 49 | ``` 50 | 51 | 52 | which enabled you to install directly from a master branch rather than my releases and you should be seing a fake version like v2020.01.05.( and so on ) instead of v0.0.4. 53 | 54 | This was only temporary solution and I recommend that you ran 55 | 56 | ``` 57 | Package Control:Remove Repository 58 | ``` 59 | 60 | so was only install/upgrade from releasees. 61 | 62 | 63 | 64 | 65 | For the time being be warned, that the plug-in has not been tested with portable versions of sublime! 66 | 67 | 68 | For any further installation questions, feel free to ask [here](https://github.com/mpourmpoulis/PythonVoiceCodingPlugin/issues/5) 69 | 70 | 71 | 72 | #### Git Install 73 | 74 | Alternatively you can download the plugin directly from github and place it in sublime package folder 75 | 76 | for windows users this should be: 77 | 78 | ``` 79 | C:\Users\Admin\AppData\Roaming\Sublime Text 3\Packages 80 | ``` 81 | 82 | and on Ubuntu it is : 83 | ``` 84 | ~/.config/sublime-text-3/Packages/ 85 | ``` 86 | 87 | Currently the Master Branch ships with its dependencies so you're good to go! 88 | 89 | Just in case something is wrong and you want to manually install dependencies,using your installation of python (this worked for me with 3.7.4 and 3.5.2) run from inside the plug-in folder (PythonVoiceCodingPlugin): 90 | 91 | ```bash 92 | python3 -m pip install --target third_party -r requirements.txt 93 | ``` 94 | 95 | 96 | ### Install Grammar 97 | 98 | Furthermore, in order to use the plug-in, you must also install the grammar! You can find additional information [here](https://github.com/mpourmpoulis/PythonVoiceCodingPlugin/tree/master/bundles) if you intend to use this on Linux via [Aenea](https://github.com/mpourmpoulis/PythonVoiceCodingPlugin/tree/master/bundles/Aenea) you will need a few extra steps but in a nutshell: 99 | 100 | - Make sure you have [Caster](https://caster.readthedocs.io/en/latest/) installed 101 | 102 | - Copy the grammar files to the appropriate user directory,depending on the version of caster these should be either `C:\Users\%USERNAME%\AppData\Local\caster\rules` or `C:\Users\%USERNAME%\.caster\rules 103 | ` 104 | 105 | - Reboot/launch Caster and if you are using 1.0 and above do not forget to enable the rule by saying `enable python voice coding plugin` 106 | 107 | in order to make this process easier, under `Preferences > Package Settings > PythonVoiceCodingPlugin 108 | ` you will find utilities 109 | 110 | - To retrieve those grammar files and then manually copy paste them 111 | 112 | ![](./gif/install1.gif) 113 | 114 | - or to automatically install them to the appropriate directory if you are using Caster 1.x.x 115 | 116 | ![](./gif/install2.gif) 117 | 118 | ### Subl Path 119 | 120 | The communication between the main plugin and the grammar happens via the sublime command line interface through the `subl` executable. Up to and including version 0.1.1, it was expected that this executable is in your Windows path but as pointed out by LexiconCode the corresponding documentation was missing! these was a big blunder on my part and may have prevented you from using the project altogether! 121 | 122 | now you can find more information about how you can add this executable to the Windows path [here](https://stackoverflow.com/questions/9440639/sublime-text-from-command-line), but in order to work around this issue without adding an additional installation step for you, release 0.1.2 implements the following scheme: 123 | 124 | * If `subl` is already in the path, it will use normally 125 | 126 | * Otherwise, it will try to fall back to `C:\Program Files\Sublime Text 3\subl` which is where it should be if you have installed sublime in the classical way! In such a case, no extra steps are needed on your part! 127 | 128 | if sublime is installed in another directory, you must unfortunately add it to the path yourself! 129 | 130 | Please note that this does not affect Linux! 131 | 132 | 133 | -------------------------------------------------------------------------------- /doc/gif/README.md: -------------------------------------------------------------------------------- 1 | This folder contains gifs and images fpr use in the documentation files 2 | -------------------------------------------------------------------------------- /doc/gif/arg0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg0.gif -------------------------------------------------------------------------------- /doc/gif/arg1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg1.gif -------------------------------------------------------------------------------- /doc/gif/arg10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg10.gif -------------------------------------------------------------------------------- /doc/gif/arg11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg11.gif -------------------------------------------------------------------------------- /doc/gif/arg12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg12.gif -------------------------------------------------------------------------------- /doc/gif/arg13.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg13.gif -------------------------------------------------------------------------------- /doc/gif/arg14.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg14.gif -------------------------------------------------------------------------------- /doc/gif/arg15.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg15.gif -------------------------------------------------------------------------------- /doc/gif/arg16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg16.gif -------------------------------------------------------------------------------- /doc/gif/arg17.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg17.gif -------------------------------------------------------------------------------- /doc/gif/arg18.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg18.gif -------------------------------------------------------------------------------- /doc/gif/arg19.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg19.gif -------------------------------------------------------------------------------- /doc/gif/arg2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg2.gif -------------------------------------------------------------------------------- /doc/gif/arg20.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg20.gif -------------------------------------------------------------------------------- /doc/gif/arg21.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg21.gif -------------------------------------------------------------------------------- /doc/gif/arg22.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg22.gif -------------------------------------------------------------------------------- /doc/gif/arg3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg3.gif -------------------------------------------------------------------------------- /doc/gif/arg4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg4.gif -------------------------------------------------------------------------------- /doc/gif/arg5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg5.gif -------------------------------------------------------------------------------- /doc/gif/arg6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg6.gif -------------------------------------------------------------------------------- /doc/gif/arg7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg7.gif -------------------------------------------------------------------------------- /doc/gif/arg8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg8.gif -------------------------------------------------------------------------------- /doc/gif/arg9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/arg9.gif -------------------------------------------------------------------------------- /doc/gif/big0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big0.gif -------------------------------------------------------------------------------- /doc/gif/big1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big1.gif -------------------------------------------------------------------------------- /doc/gif/big10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big10.gif -------------------------------------------------------------------------------- /doc/gif/big11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big11.gif -------------------------------------------------------------------------------- /doc/gif/big12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big12.gif -------------------------------------------------------------------------------- /doc/gif/big2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big2.gif -------------------------------------------------------------------------------- /doc/gif/big20.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big20.gif -------------------------------------------------------------------------------- /doc/gif/big21.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big21.gif -------------------------------------------------------------------------------- /doc/gif/big22.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big22.gif -------------------------------------------------------------------------------- /doc/gif/big23.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big23.gif -------------------------------------------------------------------------------- /doc/gif/big24.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big24.gif -------------------------------------------------------------------------------- /doc/gif/big25.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big25.gif -------------------------------------------------------------------------------- /doc/gif/big26.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big26.gif -------------------------------------------------------------------------------- /doc/gif/big27.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big27.gif -------------------------------------------------------------------------------- /doc/gif/big28.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big28.gif -------------------------------------------------------------------------------- /doc/gif/big29.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big29.gif -------------------------------------------------------------------------------- /doc/gif/big3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big3.gif -------------------------------------------------------------------------------- /doc/gif/big30.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big30.gif -------------------------------------------------------------------------------- /doc/gif/big31.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big31.gif -------------------------------------------------------------------------------- /doc/gif/big32.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big32.gif -------------------------------------------------------------------------------- /doc/gif/big33.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big33.gif -------------------------------------------------------------------------------- /doc/gif/big34.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big34.gif -------------------------------------------------------------------------------- /doc/gif/big35.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big35.gif -------------------------------------------------------------------------------- /doc/gif/big36.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big36.gif -------------------------------------------------------------------------------- /doc/gif/big37.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big37.gif -------------------------------------------------------------------------------- /doc/gif/big38.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big38.gif -------------------------------------------------------------------------------- /doc/gif/big39.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big39.gif -------------------------------------------------------------------------------- /doc/gif/big4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big4.gif -------------------------------------------------------------------------------- /doc/gif/big41.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big41.gif -------------------------------------------------------------------------------- /doc/gif/big42.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big42.gif -------------------------------------------------------------------------------- /doc/gif/big43.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big43.gif -------------------------------------------------------------------------------- /doc/gif/big44.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big44.gif -------------------------------------------------------------------------------- /doc/gif/big5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big5.gif -------------------------------------------------------------------------------- /doc/gif/big6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big6.gif -------------------------------------------------------------------------------- /doc/gif/big7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big7.gif -------------------------------------------------------------------------------- /doc/gif/big8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big8.gif -------------------------------------------------------------------------------- /doc/gif/big9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/big9.gif -------------------------------------------------------------------------------- /doc/gif/bug1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/bug1.gif -------------------------------------------------------------------------------- /doc/gif/bug2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/bug2.gif -------------------------------------------------------------------------------- /doc/gif/collect1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/collect1.gif -------------------------------------------------------------------------------- /doc/gif/collect2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/collect2.gif -------------------------------------------------------------------------------- /doc/gif/collect3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/collect3.gif -------------------------------------------------------------------------------- /doc/gif/collect4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/collect4.gif -------------------------------------------------------------------------------- /doc/gif/collect5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/collect5.gif -------------------------------------------------------------------------------- /doc/gif/collect6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/collect6.gif -------------------------------------------------------------------------------- /doc/gif/collect7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/collect7.gif -------------------------------------------------------------------------------- /doc/gif/d1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/d1.gif -------------------------------------------------------------------------------- /doc/gif/d2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/d2.gif -------------------------------------------------------------------------------- /doc/gif/d3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/d3.gif -------------------------------------------------------------------------------- /doc/gif/d4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/d4.gif -------------------------------------------------------------------------------- /doc/gif/d5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/d5.gif -------------------------------------------------------------------------------- /doc/gif/d6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/d6.gif -------------------------------------------------------------------------------- /doc/gif/del1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/del1.gif -------------------------------------------------------------------------------- /doc/gif/example_1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/example_1.gif -------------------------------------------------------------------------------- /doc/gif/example_2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/example_2.gif -------------------------------------------------------------------------------- /doc/gif/example_3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/example_3.gif -------------------------------------------------------------------------------- /doc/gif/example_4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/example_4.gif -------------------------------------------------------------------------------- /doc/gif/example_5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/example_5.gif -------------------------------------------------------------------------------- /doc/gif/example_6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/example_6.gif -------------------------------------------------------------------------------- /doc/gif/install1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/install1.gif -------------------------------------------------------------------------------- /doc/gif/install2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/install2.gif -------------------------------------------------------------------------------- /doc/gif/l2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/l2.gif -------------------------------------------------------------------------------- /doc/gif/op1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op1.gif -------------------------------------------------------------------------------- /doc/gif/op10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op10.gif -------------------------------------------------------------------------------- /doc/gif/op11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op11.gif -------------------------------------------------------------------------------- /doc/gif/op12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op12.gif -------------------------------------------------------------------------------- /doc/gif/op13.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op13.gif -------------------------------------------------------------------------------- /doc/gif/op14.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op14.gif -------------------------------------------------------------------------------- /doc/gif/op15.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op15.gif -------------------------------------------------------------------------------- /doc/gif/op16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op16.gif -------------------------------------------------------------------------------- /doc/gif/op17.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op17.gif -------------------------------------------------------------------------------- /doc/gif/op19.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op19.gif -------------------------------------------------------------------------------- /doc/gif/op2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op2.gif -------------------------------------------------------------------------------- /doc/gif/op20.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op20.gif -------------------------------------------------------------------------------- /doc/gif/op21.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op21.gif -------------------------------------------------------------------------------- /doc/gif/op22.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op22.gif -------------------------------------------------------------------------------- /doc/gif/op23.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op23.gif -------------------------------------------------------------------------------- /doc/gif/op24.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op24.gif -------------------------------------------------------------------------------- /doc/gif/op25.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op25.gif -------------------------------------------------------------------------------- /doc/gif/op26.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op26.gif -------------------------------------------------------------------------------- /doc/gif/op28.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op28.gif -------------------------------------------------------------------------------- /doc/gif/op29.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op29.gif -------------------------------------------------------------------------------- /doc/gif/op3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op3.gif -------------------------------------------------------------------------------- /doc/gif/op30.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op30.gif -------------------------------------------------------------------------------- /doc/gif/op31.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op31.gif -------------------------------------------------------------------------------- /doc/gif/op32.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op32.gif -------------------------------------------------------------------------------- /doc/gif/op33.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op33.gif -------------------------------------------------------------------------------- /doc/gif/op34.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op34.gif -------------------------------------------------------------------------------- /doc/gif/op35.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op35.gif -------------------------------------------------------------------------------- /doc/gif/op36.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op36.gif -------------------------------------------------------------------------------- /doc/gif/op37.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op37.gif -------------------------------------------------------------------------------- /doc/gif/op38.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op38.gif -------------------------------------------------------------------------------- /doc/gif/op4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op4.gif -------------------------------------------------------------------------------- /doc/gif/op5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op5.gif -------------------------------------------------------------------------------- /doc/gif/op6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op6.gif -------------------------------------------------------------------------------- /doc/gif/op7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op7.gif -------------------------------------------------------------------------------- /doc/gif/op8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op8.gif -------------------------------------------------------------------------------- /doc/gif/op9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/op9.gif -------------------------------------------------------------------------------- /doc/gif/sub10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub10.gif -------------------------------------------------------------------------------- /doc/gif/sub11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub11.gif -------------------------------------------------------------------------------- /doc/gif/sub12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub12.gif -------------------------------------------------------------------------------- /doc/gif/sub13.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub13.gif -------------------------------------------------------------------------------- /doc/gif/sub14.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub14.gif -------------------------------------------------------------------------------- /doc/gif/sub15.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub15.gif -------------------------------------------------------------------------------- /doc/gif/sub16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub16.gif -------------------------------------------------------------------------------- /doc/gif/sub17.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub17.gif -------------------------------------------------------------------------------- /doc/gif/sub18.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub18.gif -------------------------------------------------------------------------------- /doc/gif/sub19.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub19.gif -------------------------------------------------------------------------------- /doc/gif/sub2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub2.gif -------------------------------------------------------------------------------- /doc/gif/sub3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub3.gif -------------------------------------------------------------------------------- /doc/gif/sub4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub4.gif -------------------------------------------------------------------------------- /doc/gif/sub5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub5.gif -------------------------------------------------------------------------------- /doc/gif/sub6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub6.gif -------------------------------------------------------------------------------- /doc/gif/sub7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub7.gif -------------------------------------------------------------------------------- /doc/gif/sub8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub8.gif -------------------------------------------------------------------------------- /doc/gif/sub9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpourmpoulis/PythonVoiceCodingPlugin/3356ad9f609e70923dde28964bc5c2b7e7105fb7/doc/gif/sub9.gif -------------------------------------------------------------------------------- /interface/common/utility.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | from itertools import chain 3 | 4 | def make_region(r): 5 | if isinstance(r,tuple): 6 | return sublime.Region(r[0],r[1]) 7 | elif isinstance(r,list): 8 | return [make_region(x) for x in r if x] 9 | else: 10 | raise Exception("the maker region function was given an incorrect argument"+str(r)) 11 | 12 | def all_or_nothing(r,check,*arguments): 13 | return all(check(x,*arguments) for x in r) or not any(check(x,*arguments) for x in r) 14 | 15 | 16 | def make_sequence(r): 17 | if not isinstance(r ,list): 18 | return [r] 19 | elif isinstance(r,list): 20 | try : 21 | return list(chain.from_iterable(r)) 22 | except : 23 | print("Gold Inside Here") 24 | return r 25 | 26 | -------------------------------------------------------------------------------- /interface/interface.py: -------------------------------------------------------------------------------- 1 | from PythonVoiceCodingPlugin.application.application import Application 2 | from PythonVoiceCodingPlugin.interface.view_info import ViewInformation 3 | 4 | 5 | class Interface(): 6 | """docstring for Interface""" 7 | def __init__(self,view,window,edit,sublime,settings): 8 | self.view = view 9 | self.window = window 10 | self.edit = edit 11 | self.sublime = sublime 12 | self.actions = [] 13 | self.settings = settings 14 | 15 | def get_view_information(self): 16 | return ViewInformation(self.view,self.sublime) 17 | 18 | def get_ui_information(self): 19 | return None 20 | 21 | def push_action(self,item): 22 | self.actions.append(item) 23 | 24 | def respond_to_query(self,query_description): 25 | application = Application.get_application(self.view.id()) 26 | application.respond_to_query(self,query_description) 27 | parameters = { 28 | "view":self.view,"window":self.window,"edit":self.edit,"sublime":self.sublime,"settings":self.settings, 29 | } 30 | for action in self.actions: 31 | action.execute(**parameters) 32 | 33 | def respond_to_event(self,event_description): 34 | self.actions = [] 35 | application = Application.get_application(self.view.id()) 36 | application.respond_to_event(self,event_description) 37 | parameters = { 38 | "view":self.view,"window":self.window,"edit":self.edit,"sublime":self.sublime,"settings":self.settings, 39 | } 40 | for action in self.actions: 41 | action.execute(**parameters) 42 | 43 | 44 | def clear_actions(self): 45 | self.actions = [] 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /interface/view_info.py: -------------------------------------------------------------------------------- 1 | class ViewInformation(): 2 | def __init__(self, view, sublime): 3 | self.view = view 4 | self.sublime = sublime 5 | def __getitem__(self, value): 6 | if value == "selection": 7 | intermediate = self.view.sel() 8 | temporary = [(x.begin(),x.end()) for x in intermediate] 9 | return temporary if len(temporary)!=1 else temporary[0] 10 | elif value == "change_count": 11 | return self.view.change_count() 12 | elif value == "id": 13 | return self.view.id() 14 | elif value == "code": 15 | return self.view.substr(self.sublime.Region(0, self.view.size())) 16 | elif value == "rowcol": 17 | return self.view.rowcol 18 | elif value == "text_point": 19 | return self.view.text_point 20 | elif value == "get_regions": 21 | return lambda y:[(x.begin(),x.end()) for x in self.view.get_regions(y)] 22 | else: 23 | return None 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | reference.py 2 | scope_visitor.py 3 | collect.py 4 | -------------------------------------------------------------------------------- /library/BracketMatcher.py: -------------------------------------------------------------------------------- 1 | import ast 2 | import bisect 3 | import token 4 | 5 | from PythonVoiceCodingPlugin.third_party.astmonkey import transformers 6 | from PythonVoiceCodingPlugin.third_party.asttokens import asttokens 7 | 8 | from PythonVoiceCodingPlugin.library import build_tree,get_source_region,previous_token,next_token 9 | 10 | class BracketMatcher(): 11 | """docstring for BracketMatcher""" 12 | def __init__(self, atok): 13 | self.atok = atok 14 | self.matching = {} 15 | self.level = {} 16 | self.level_index = {} 17 | self._match(atok) 18 | 19 | 20 | def find_enclosing(self,origin,include_self = True): 21 | possible = bisect.bisect_right(self.level_index[0],origin.start) 22 | 23 | if possible!=0: 24 | c = self.level[0][possible-1] 25 | # print( origin ,c) 26 | # print(origin.end,c[1].end) 27 | if origin.end <= c[1].end : 28 | if origin.end==c[1].end or origin.end==c[0].end : 29 | if include_self: 30 | return c 31 | else: 32 | return None,None 33 | return c 34 | return None,None 35 | 36 | def _match(self,atok): 37 | # print("inside much mass on all bracket ") 38 | target = {"[":1, "]":-1 , "(":1,")":-1,"{":1,"}":-1} 39 | stack = [] 40 | candidates = [x for x in atok.tokens if x.string in target] 41 | for candidate in candidates: 42 | # print(candidate,stack) 43 | if target[candidate.string] == 1: 44 | stack.append(candidate) 45 | else: 46 | c = stack.pop() 47 | self.matching[c] = candidate 48 | self.matching[candidate] = c 49 | index = len(stack) 50 | if index not in self.level: 51 | self.level[index] = [] 52 | self.level_index[index] = [] 53 | self.level[index].append((c,candidate)) 54 | self.level_index[index].append(c.start) 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /library/LCA.py: -------------------------------------------------------------------------------- 1 | import ast 2 | import bisect 3 | 4 | from PythonVoiceCodingPlugin.third_party.segment_tree import SegmentTree 5 | from PythonVoiceCodingPlugin.third_party.segment_tree.operations import min_operation 6 | 7 | class LCA(): 8 | """docstring for LCA""" 9 | def __init__(self, root): 10 | self.sequence = [] 11 | self.field_history = {} 12 | self.visits = {} 13 | self.cycle = 0 14 | self.depth = 0 15 | self.visit(root) 16 | self.tree = SegmentTree(self.sequence,[min_operation]) 17 | 18 | 19 | def visit(self, node): 20 | self.depth+=1 21 | if node not in self.visits: 22 | self.visits[node] = (self.cycle,self.cycle) # can probably omitted the ifprint() 23 | self.field_history[node] = [] 24 | self.sequence.append((self.depth, node)) 25 | self.cycle+=1 26 | for child in ast.iter_child_nodes(node): 27 | if not hasattr(child,"parent"): 28 | continue 29 | self.field_history[node].append((self.cycle,child.parent_field,getattr(child,"parent_field_index",None))) 30 | self.visit(child) 31 | first, last = self.visits[node] 32 | self.visits[node] = (first,self.cycle) 33 | self.sequence.append((self.depth, node)) 34 | self.cycle+=1 35 | self.depth-=1 36 | 37 | def get_depth(self, node): 38 | return self.sequence[self.visits[node][0]][0] 39 | 40 | def __call__(self,first_node,second_node,only_depth = False,node_and_depth = True): 41 | try : 42 | x,y = self.visits[first_node] 43 | w,v = self.visits[second_node] 44 | except : 45 | print(ast.dump(first_node),"\n") 46 | print(second_node,ast.dump(second_node),"\n") 47 | raise 48 | 49 | 50 | 51 | l = min(x,w) 52 | r = max(y,v) 53 | 54 | ancestor = self.tree.query(l,r,"min") 55 | if node_and_depth: 56 | return ancestor 57 | elif only_depth: 58 | return ancestor[0] 59 | else: 60 | return ancestor[1] 61 | 62 | def get_field_with_respect_to(self,node,parent_node): 63 | index = bisect.bisect_left(self.field_history[parent_node],(self.visits[node][0],)) 64 | index = index if index < len(self.field_history[parent_node]) and \ 65 | self.field_history[parent_node][index][0] == self.visits[node][0] else index-1 66 | y = self.field_history[parent_node][index] 67 | return (y[1],y[2]) 68 | 69 | def visit_time(self, node): 70 | return self.visits[node] 71 | 72 | def is_child(self,child, parent): 73 | x = self.visits[child] 74 | y = self.visits[parent] 75 | return x[0] > y[0] 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /library/__init__.py: -------------------------------------------------------------------------------- 1 | import ast 2 | from itertools import chain 3 | 4 | from PythonVoiceCodingPlugin.third_party.astmonkey import transformers 5 | from PythonVoiceCodingPlugin.third_party.asttokens import asttokens 6 | 7 | def make_flat(x): 8 | return list(chain.from_iterable(x)) 9 | 10 | 11 | def build_tree(code : str): 12 | atok = asttokens.ASTTokens(parse=True, source_text= code ) 13 | root = transformers.ParentChildNodeTransformer().visit(atok.tree) 14 | return root,atok 15 | 16 | def get_source_region(atok, element): 17 | if element is None: 18 | return None 19 | if isinstance(element,tuple): 20 | elemental = list(element) 21 | if isinstance(element,ast.AST): 22 | return atok.get_text_range(element) 23 | else: 24 | # regions = [atok.get_text_range(node) for node in element] 25 | regions = [get_source_region(atok,node) for node in element] 26 | start = min( regions,key = lambda s: s[0])[0] 27 | end = max( regions,key = lambda s: s[1])[1] 28 | return ( start , end) 29 | 30 | def sorted_by_source_region(atok, container): 31 | return sorted(container,key = lambda x: get_source_region(atok,x)) 32 | 33 | 34 | 35 | 36 | def previous_token(atok, origin,extra = False): 37 | """returns the preview stoking 38 | 39 | Args: 40 | atok (TYPE): Description 41 | origin (TYPE): Description 42 | extra (bool, optional): Description 43 | 44 | Returns: 45 | TYPE: Description 46 | """ 47 | if not origin: 48 | return None 49 | result = atok.prev_token(origin,extra) 50 | return result if result.index < origin.index else None 51 | 52 | def next_token(atok, origin,extra = False): 53 | if not origin: 54 | return None 55 | try: 56 | result = atok.next_token(origin,extra) 57 | except: 58 | result = None 59 | return result 60 | 61 | -------------------------------------------------------------------------------- /library/higher.py: -------------------------------------------------------------------------------- 1 | import ast 2 | import token 3 | 4 | from PythonVoiceCodingPlugin.third_party.asttokens import asttokens 5 | 6 | from PythonVoiceCodingPlugin.library import previous_token,next_token 7 | from PythonVoiceCodingPlugin.library.modification import ModificationHandler 8 | 9 | 10 | 11 | 12 | 13 | def filter_asynchronous(atok,m = None, timestamp = 0): 14 | m = m if m else ModificationHandler(atok.text) 15 | candidates = [x for x in atok.tokens if x.string=="async"] 16 | for c in candidates: 17 | y = next_token(atok,c) 18 | # async_stmt: 'async' (funcdef | with_stmt | for_stmt) 19 | if y and y.string in ["def","for","with"]: 20 | m.modify_from(timestamp,(c.startpos,y.startpos),"","async_"+y.string) 21 | return m 22 | 23 | 24 | def filter_await(atok,m = None, timestamp = 0): 25 | m = m if m else ModificationHandler(atok.text) 26 | candidates = [x for x in atok.tokens if x.string=="await"] 27 | for c in candidates: 28 | y = previous_token(atok,c) 29 | z = next_token(atok,c) 30 | if y and not y.string.isspace(): 31 | m.modify_from(timestamp,(c.startpos,c.endpos),"","await") 32 | else: 33 | if z: 34 | m.modify_from(timestamp,(c.startpos,z.startpos),"yield from ","await") 35 | else: 36 | m.modify_from(timestamp,(c.startpos,c.endpos),"","await") 37 | return m 38 | 39 | def filter_fstrings(atok,m = None, timestamp = 0): 40 | m = m if m else ModificationHandler(atok.text) 41 | candidates = [x for x in atok.tokens if x.string=="f"] 42 | for c in candidates: 43 | y = next_token(atok,c) 44 | if y and y.type==token.STRING: 45 | m.modify_from(timestamp,(c.startpos,y.endpos),y.string,"fstring") 46 | return m 47 | 48 | def filter_everything(atok, m = None, timestamp = 0): 49 | m = m if m else ModificationHandler(atok.text) 50 | m = filter_asynchronous(atok,m, timestamp) 51 | m = filter_fstrings(atok,m, timestamp) 52 | m = filter_await(atok,m, timestamp) 53 | return m 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /library/level_info.py: -------------------------------------------------------------------------------- 1 | import ast 2 | 3 | from PythonVoiceCodingPlugin.library import sorted_by_source_region 4 | 5 | PARENT = 1 6 | PARENT_FIELD = 2 7 | PARENT_FIELD_INDEX = 3 8 | 9 | class LevelVisitor(): 10 | """docstring for LevelVisitor 11 | 12 | Attributes: 13 | atok (TYPE): Description 14 | data (dict[int,dict[tuple,list]]): Description 15 | local_data (dict[ast.AST, tuple[ast.AST,str,int]]): Description 16 | parent (TYPE): Description 17 | root (TYPE): Description 18 | special (TYPE): Description 19 | level_defining(set[ast.AST]): nodes that define the level 20 | stack (TYPE): Description 21 | """ 22 | def __init__(self, root,level_defining,atok = None,special_nodes = []): 23 | self.atok = atok 24 | self.root = root 25 | self.level_defining = set(level_defining) 26 | self.special = set(special_nodes) 27 | self.flag = self.special.issubset(self.level_defining) 28 | 29 | self.data = {1:{},2:{},3:{}} 30 | self.local_data = {} 31 | 32 | # stock and parent initialization before recursion 33 | self.stack = [(root,None,None)] 34 | self.parent = (root,None,None) 35 | self.visit(root) 36 | 37 | 38 | def _insert_primitive(self,h,k,v): 39 | if k not in h: 40 | h[k] = [] 41 | h[k].append(v) 42 | 43 | def insert(self,k,v): 44 | self.local_data[v] = k 45 | self._insert_primitive(self.data[1],(k[0],),v) 46 | self._insert_primitive(self.data[2],(k[0],k[1]),v) 47 | self._insert_primitive(self.data[3],(k[0],k[1],k[2]),v) 48 | 49 | def visit(self,node): 50 | self.insert(self.parent,node) 51 | success = node in self.level_defining 52 | for child in ast.iter_child_nodes(node): 53 | if success: 54 | self.stack.append(self.parent) 55 | self.parent = (node,child.parent_field,getattr(child,"parent_field_index",None)) 56 | self.visit(child) 57 | if success: 58 | self.parent =self.stack.pop() 59 | 60 | def __getitem__(self,key): 61 | return self.local_data[key] 62 | 63 | def __call__(self, node, level_desc, index = None, only_special = False): 64 | # we determine how strict our level hierarchy will be 65 | guide = tuple(list(self.local_data[node])[:level_desc]) 66 | 67 | # and we retrieve all spatial nodes in the same hierarchy as "node" 68 | # we may optionally return only nodes that are special 69 | result = [ 70 | x for x in self.data[level_desc][guide] 71 | if ((x in self.level_defining and self.flag) or x in self.special) and 72 | (not only_special or not self.special or x in self.special) 73 | ] 74 | 75 | # we optionally sort the list positionally +and pick the specified index 76 | if self.atok : 77 | result = sorted_by_source_region(self.atok, result) 78 | if index is not None: 79 | if len(result)>index and len(result) >= -1*index: 80 | result = result[index] 81 | else: 82 | result = None 83 | return result 84 | 85 | 86 | 87 | def everything(self, level_desc, index = None, only_special = False): 88 | result = self.data[level_desc].values() # type: List[List[ast.AST]] 89 | 90 | 91 | # Allow only level defining or special nodes 92 | result = [ 93 | [ 94 | y for y in x 95 | if ((y in self.level_defining and self.flag) or y in self.special) and 96 | (not only_special or not self.special or y in self.special) 97 | ] 98 | for x in result 99 | ] 100 | # print("\nresume\n",result,"\n\n") 101 | # optionally pick specific element from each list 102 | if self.atok: 103 | result = [sorted_by_source_region(self.atok,x) for x in result] 104 | if index is not None: 105 | result = [x[index] for x in result if len(x)>index and len(x) >= -1*index] 106 | return result 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /library/lexical.py: -------------------------------------------------------------------------------- 1 | import ast 2 | import token 3 | 4 | from PythonVoiceCodingPlugin.third_party.astmonkey import transformers 5 | from PythonVoiceCodingPlugin.third_party.asttokens import asttokens 6 | 7 | from PythonVoiceCodingPlugin.library import build_tree,get_source_region,previous_token,next_token 8 | from PythonVoiceCodingPlugin.library.BracketMatcher import BracketMatcher 9 | 10 | ''' 11 | attention: when this module was written I was unaware of the fact that the tokenize module contains the NL 12 | token even in version 3.3. By contrast, the token module only introduced it in version 3.7 13 | this could most likely significantly redo use the amount and for complexity of this module 14 | 15 | 16 | 17 | 18 | ''' 19 | 20 | 21 | 22 | 23 | 24 | def extract_all_function_names(code): 25 | atok = asttokens.ASTTokens(parse=False, source_text=code) 26 | return [(atok.next_token(x).string,x.type) for x in atok.tokens if x.type == 1 and x.string =="def"] 27 | 28 | 29 | def extract_all_class_names(code): 30 | atok = asttokens.ASTTokens(parse=False, source_text=code) 31 | return [(atok.next_token(x).string,x.type) for x in atok.tokens if x.type == 1 and x.string =="class"] 32 | 33 | 34 | def line_continues(line): 35 | x = line.rfind("\\") 36 | if x==-1: 37 | return False 38 | return line[x+1:].isspace() or line[x+1:] == "" 39 | 40 | def leftmost(x,t): 41 | return x if x.start=t.start 80 | choice = max if go_left else min 81 | candidates = [(x.startpos,x) for x in self.breakpoint[t.start[0]] if right_direction(x)] 82 | return choice(candidates)[1] if candidates else None 83 | 84 | def get_first(self,t): 85 | # print("get_first in",t,t.start) 86 | bp = self.find_breakpoint(t,True) 87 | # print("breakpoint {} ",bp) 88 | if bp: 89 | return next_token(self.atok,bp),False 90 | x = t.start[0] 91 | #print("why not x-ray",x) 92 | # print(self.first) 93 | y = self.first[x] 94 | 95 | 96 | return self.first[x],self.continuation[x-2] or y.start[0] 5:return None 133 | left = l.get_last_up(left) if move_left else left 134 | # print("entering right loop we ",right) 135 | while move_right: 136 | new_right = right 137 | while new_right: 138 | right,move_right = l.get_last(new_right) 139 | # print( right,move_right,[new_right],right.type) 140 | _,new_right = b.find_enclosing(right,False) 141 | # there was a bug where we would get in a fit loopif the last token was a closing bracket or parentheses 142 | i=i+1 143 | if i>5:return None,None 144 | right = l.get_first_down(right) if move_right else right 145 | return left, right 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /library/partial.py: -------------------------------------------------------------------------------- 1 | """ 2 | this module is responsible for partially parsing user code. 3 | In particular, while editing code, it is often the case 4 | there are syntactical errors, such as missing variables 5 | (x = [value to be completed now]) or features introduced in later versions of Python. 6 | such errors will cause the ast parser to abort with the syntax error preventing us from 7 | analyze 8 | additionally, these module enables us to parse ( and correct ) is single 9 | logical line. 10 | 11 | """ 12 | import ast 13 | import tokenize 14 | 15 | from PythonVoiceCodingPlugin.third_party.asttokens import asttokens 16 | 17 | from PythonVoiceCodingPlugin.library import build_tree,get_source_region 18 | from PythonVoiceCodingPlugin.library.lexical import expand_to_line_or_statement 19 | from PythonVoiceCodingPlugin.library.higher import filter_everything 20 | from PythonVoiceCodingPlugin.library.modification import ModificationHandler 21 | from PythonVoiceCodingPlugin.library.repair import RepairMissing 22 | 23 | 24 | ''' 25 | these module is responsible for partially parsing the user code 26 | For instance, it enables to ignore various syntactic errors and to compile 27 | either fulltext or only single logical lines 28 | ''' 29 | 30 | ################################################################################################ 31 | ################################################################################################ 32 | 33 | def partially_parse(code, m = None, atok = None,rethrow_exception = False): 34 | m = m if m is not None else ModificationHandler(code) 35 | #print(code) 36 | timestamp = m.get_timestamp() 37 | try: 38 | root,atok = build_tree(code) 39 | r = RepairMissing(atok,m,timestamp) 40 | return root,atok,m,r 41 | except Exception as e_first: 42 | atok = atok if atok else asttokens.ASTTokens(parse=False, source_text= code) 43 | # print(m) 44 | m = filter_everything(atok,m, timestamp) 45 | m.update() 46 | #print("after filtering",m.history) 47 | atok = asttokens.ASTTokens(parse=False, source_text= m.current_code) 48 | r = RepairMissing(atok,m,m.get_timestamp()) 49 | r.work() 50 | m.update() 51 | #print("she's after repair",m.history) 52 | try: 53 | root,atok = build_tree(m.current_code) 54 | return root,atok,m,r 55 | except Exception as e: 56 | print(" go to the field\n",m.current_code) 57 | print(" error was\n",str(e),"\n",e) 58 | if rethrow_exception : 59 | raise e 60 | return None,None,None,None 61 | 62 | ############################### 63 | 64 | 65 | def line_partial(code,offset): 66 | atok = asttokens.ASTTokens(parse=False, source_text=code) 67 | origin = atok.get_token_from_offset(offset) 68 | left, right = expand_to_line_or_statement(atok,origin) 69 | m = ModificationHandler(code) 70 | m.modify_from(0,(0, left.startpos),"") 71 | if right.string == ":": 72 | m.modify_from(0,(right.endpos,len(code)+1),"pass") 73 | else: 74 | m.modify_from(0,(right.endpos,len(code)+1),"") 75 | m.update() 76 | return partially_parse(m.current_code,m) 77 | 78 | ################################################################################################ 79 | ################################################################################################ 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | ################################################################################################ 91 | ################################################################################################ 92 | # 93 | # 94 | # the following functions are deprecated and will be removed in the near future 95 | # 96 | # 97 | ################################################################################################ 98 | ################################################################################################ 99 | def parse_single_correct_line(line): 100 | try: 101 | return build_tree(line) 102 | except Exception as e: 103 | return None 104 | 105 | def build_without_higher(code,mode = True): 106 | atok = asttokens.ASTTokens(parse=False, source_text=code) 107 | m = ModificationHandler(code) 108 | m = filter_everything(m,atok) 109 | m.update() 110 | root,atok = build_tree(m.current_code) 111 | return root,atok,m 112 | 113 | 114 | def parse_line_from_offset(code, offset): 115 | print("\n\n hello world here\n\n") 116 | atok = asttokens.ASTTokens(parse=False, source_text= code ) 117 | origin = atok.get_token_from_offset(offset) 118 | print("off their origin ") 119 | left, right = expand_to_line_or_statement(atok,origin) 120 | print("often expands the underlying ", left, right) 121 | area = code[left.startpos:right.endpos] 122 | 123 | #print("area is ",area) 124 | print(asttokens.ASTTokens(parse=False, source_text=area).tokens) 125 | return build_tree(area) 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /library/selection_node.py: -------------------------------------------------------------------------------- 1 | import ast 2 | 3 | from PythonVoiceCodingPlugin.third_party.asttokens import asttokens 4 | 5 | 6 | from PythonVoiceCodingPlugin.library import get_source_region,previous_token,next_token 7 | from PythonVoiceCodingPlugin.library.info import generic_fix,get_sub_index 8 | from PythonVoiceCodingPlugin.library.traverse import match_node 9 | 10 | def nearest_node_from_offset(root,atok,offset,special=False): 11 | converter = atok._line_numbers 12 | original_token = atok.get_token_from_offset(offset) 13 | token = original_token 14 | while token and (not token.string or token.string.isspace()): 15 | token = previous_token(atok,token) 16 | if not token or converter.offset_to_line(offset)[0] != converter.offset_to_line(token.startpos)[0]: 17 | following = next_token(atok,original_token) 18 | while following and following.string.isspace(): 19 | token = following 20 | following = next_token(atok,token) 21 | if following: 22 | token = following 23 | s = token.startpos 24 | r = node_from_range(root,atok,(s,s),special= special,lenient = True) 25 | return r 26 | 27 | 28 | 29 | def node_from_range_new(root,atok,r,special = False,lenient = False): 30 | # notes like ast.Store result in (0,0) with atok.get_text_range() 31 | # which causes problems if the cursor is right at the beginning of the file 32 | inside = lambda x,y: (y[0]<=x[0] Package Settings > PythonVoiceCodingPlugin 11 | 12 | It supports all version of Caster 0.5, 0.6, 1.x but please upgrade as support for older versions will sooner or later be dropped! as a note if you're using any version above 1.0.0 except for copy pasting the grammar in the appropriate folder you must also enable it by saying 13 | 14 | enable python voice coding plugin 15 | 16 | if you have any problem or questions regarding installation , whether of the plug-in itself or the grammar necessary to use it please let me know at my issues! 17 | 18 | NOTE FOR MAC Installers 19 | 20 | Honestly you called me a little bit unprepared,i didn't expect anyone to download on Mac:P 21 | 22 | Firstly the core plug-in has not been tested on Mac, though it is pure Python so probably should work? 23 | 24 | Secondly currently the grammar is written to be used with Caster which does not support Mac. Nonetheless you could adapt it to standalone dragonfly or what ever suits your system. 25 | 26 | 27 | If you are using Talon , an alternative you might want to check out is 28 | 29 | https://github.com/dwiel/talon_community/blob/master/apps/jetbrains_psi.py 30 | 31 | though I have not tested it. -------------------------------------------------------------------------------- /messages/0.1.1.txt: -------------------------------------------------------------------------------- 1 | Thanks for upgrading to the latest 0.1.1 version of PythonVoiceCodingPlugin! This patch brings with it for things to note 2 | 3 | - The project now has a gitter channel https://gitter.im/PythonVoiceCodingPlugin/community to provide installation troubleshooting support which you can also find under Preferences > Package Settings > PythonVoiceCodingPlugin 4 | 5 | - Improvements on the grammar side regarding communication with the main plug-in lifting the constraints regarding special characters in your custom paste back formatting options and some occasional focus issues. These were devised while working on a proof of concept https://github.com/mpourmpoulis/CasterSublimeSnippetInterfaceExample which enables us to create snippets purely on the grammar side without any plug-in code or sublime-snippet files. 6 | 7 | - Various back fixes in the plug-in backend, such as incorrectly handling empty definition parameter lists and a issue that might sometimes prevent you from selecting an argument from a function call inside the header of an for or with statement 8 | 9 | - A whole bunch of new unofficial small regions of interest such as picking up the individual lower upper step of the subscript or the left/right/middle side of comparison! 10 | -------------------------------------------------------------------------------- /messages/0.1.2.txt: -------------------------------------------------------------------------------- 1 | ===================== 2 | CRITICAL UPDATE 3 | ===================== 4 | 5 | My sincerest apologies but up to release 0.1.1 a subtle yet critical installation step was not documented, which may have prevented you from using the plug-in altogether! 6 | 7 | You can find more information at https://github.com/mpourmpoulis/PythonVoiceCodingPlugin/issues/15 but release 0.1.2 should make that installation step redundant for most users, so SIMPLY UPGRADING and replacing the grammar files should be enough without any further action on your part! 8 | 9 | In order to rapidly upgrade your grammars, if you are using Caster 1.x.x under 10 | 11 | Preferences > Package Settings > PythonVoiceCodingPlugin 12 | 13 | You will find 14 | 15 | Quick 1.0.0 Install 16 | 17 | More information https://github.com/mpourmpoulis/PythonVoiceCodingPlugin/issues/14 18 | 19 | Many thanks to LexiconCode for pointing this massive blunder out and once again I am deeply sorry! 20 | -------------------------------------------------------------------------------- /messages/0.1.3.txt: -------------------------------------------------------------------------------- 1 | Thanks for upgrading to the latest version v0.1.3! 2 | 3 | This is a small patch 4 | 5 | - refactoring some old code from the age of the dinosaurs 6 | 7 | - Introduces a variety of bug fixes, especially certain edge cases with the cursor position at the beginning or the end of the file and stabilizing the behavior of argument queries using the "inside" keyword 8 | 9 | - improves code coverage most notably by allowing "partial parsing", so that ArgumentQueries and dedicated sub indexing queries (eg,"delete part 2") can now run within the current logical line even if there are unrecoverable syntax errors in other parts of the code, so long as tokenization is still possible, a requirement I hope to remove in the future 10 | 11 | - ports the documentation to readthedocs 12 | 13 | If all things go according to plan, the next release will be 0.2.0 and will go public around mid August 14 | 15 | =============================================================== 16 | CRITICAL UPDATE FOR THOSE UPGRADING FROM 0.1.1 17 | ================================================================ 18 | 19 | My sincerest apologies but up to release 0.1.1 a subtle yet critical installation step was not documented, which may have prevented you from using the plug-in altogether! 20 | 21 | You can find more information at https://github.com/mpourmpoulis/PythonVoiceCodingPlugin/issues/15 but release 0.1.2 should make that installation step redundant for most users, so SIMPLY UPGRADING and replacing the grammar files should be enough without any further action on your part! 22 | 23 | -------------------------------------------------------------------------------- /messages/install.txt: -------------------------------------------------------------------------------- 1 | Thanks for downloading the latest 0.1.3 version of PythonVoiceCodingPlugin! 2 | 3 | Should you face any problems or have any questions regarding the installation process, feel free to contact me in the dedicated gitter channel 4 | 5 | https://gitter.im/PythonVoiceCodingPlugin/community 6 | 7 | This link along with links to the online documentation containing around 100 gifs with examples you can find under 8 | 9 | Preferences > Package Settings > PythonVoiceCodingPlugin 10 | 11 | From there you can also retrieve the Caster grammars that are necessary for using the plug-in along with instructions on how to install them as well as a 12 | 13 | Quick 1.0.0 Install 14 | 15 | utility. It supports all version of Caster 0.5, 0.6, 1.x but please upgrade as support for older versions will soon be dropped, most probably with release 0.2.0 when it comes out hopefully around mid August! As a note if you're using any version above 1.0.0 you must also enable it by saying 16 | 17 | enable python voice coding plugin 18 | 19 | 20 | Finally you should be aware that there are some experimental/unofficial features you can manually enable! 21 | 22 | 23 | ################################# 24 | NOTE FOR MAC Installers 25 | ################################# 26 | 27 | Honestly you caught me a little bit unprepared,I am releasing these for Windows and Linux so i didn't expect anyone to download on Mac and lacking Mac hardware, the core plug-in has not been tested on Mac. Nonetheless it is pure python I believe it should generally work and with Caster now supporting Mac it is probably worth your while to give it a try! 28 | 29 | Finally if you are using Talon and Jetbrains, an alternative you might want to check out is 30 | https://github.com/dwiel/talon_community/blob/master/apps/jetbrains_psi.py 31 | 32 | -------------------------------------------------------------------------------- /mkdocs.yaml: -------------------------------------------------------------------------------- 1 | extra_css: 2 | - https://assets.readthedocs.org/static/css/badge_only.css 3 | - https://assets.readthedocs.org/static/css/readthedocs-doc-embed.css 4 | extra_javascript: 5 | - readthedocs-data.js 6 | - https://assets.readthedocs.org/static/core/js/readthedocs-doc-embed.js 7 | - https://assets.readthedocs.org/static/javascript/readthedocs-analytics.js 8 | google_analytics: null 9 | site_name: PythonVoiceCodingPlugin 10 | site_author: mpourmpoulis 11 | site_url: https://pythonvoicecodingplugin.readthedocs.io 12 | docs_dir: doc 13 | repo_url: https://github.com/mpourmpoulis/PythonVoiceCodingPlugin 14 | edit_uri: tree/master/doc 15 | 16 | theme: 17 | name: readthedocs 18 | 19 | nav: 20 | - Home: README.md 21 | - Argument queries: SelectArgument.md 22 | - Big ROI queries: SelectBigROI.md 23 | - SubIndexing: SubIndexing.md 24 | - Operations: Operations.md 25 | - Collections: CollectionQueries.md 26 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | extra_css: 2 | - https://assets.readthedocs.org/static/css/badge_only.css 3 | - https://assets.readthedocs.org/static/css/readthedocs-doc-embed.css 4 | extra_javascript: 5 | - readthedocs-data.js 6 | - https://assets.readthedocs.org/static/core/js/readthedocs-doc-embed.js 7 | - https://assets.readthedocs.org/static/javascript/readthedocs-analytics.js 8 | google_analytics: null 9 | site_name: PythonVoiceCodingPlugin 10 | site_author: mpourmpoulis 11 | site_url: https://pythonvoicecodingplugin.readthedocs.io 12 | docs_dir: doc 13 | repo_url: https://github.com/mpourmpoulis/PythonVoiceCodingPlugin 14 | edit_uri: tree/master/doc 15 | 16 | theme: 17 | name: readthedocs 18 | 19 | nav: 20 | - User Guide: README.md 21 | - Argument queries: SelectArgument.md 22 | - Big ROI queries: SelectBigROI.md 23 | - SubIndexing: SubIndexing.md 24 | - Operations: Operations.md 25 | - Collections: CollectionQueries.md 26 | - Installation: Installation.md 27 | -------------------------------------------------------------------------------- /python_voice_coding_plugin.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | import sublime 5 | import sublime_plugin 6 | 7 | 8 | # making sure our dependencies are in the path 9 | sys.path.insert(0,os.path.join(os.path.dirname(__file__), 'third_party')) 10 | 11 | from PythonVoiceCodingPlugin.interface.interface import Interface 12 | 13 | 14 | PLUGIN_VERSION = (0,1,3) 15 | 16 | settings = {} 17 | already_message = False 18 | 19 | def plugin_loaded(): 20 | global settings 21 | settings = sublime.load_settings("python_voice_coding_plugin.sublime-settings") 22 | try : 23 | from package_control import events 24 | except : 25 | pass 26 | 27 | 28 | 29 | class PythonVoiceCodingPluginCommand(sublime_plugin.TextCommand): 30 | def run(self, edit,arg): 31 | global already_message 32 | if "grammar_version" not in arg and not already_message: 33 | sublime.error_message("You are using main plug-in version >=0.1.0 with a grammar <= 0.0.5." + 34 | "They are not compatible." + 35 | "You can find the new newest version of the grammar along with instructions to install it\n" + 36 | " Under Preferences > Package Settings > PythonVoiceCodingPlugin" 37 | 38 | ) 39 | already_message = True 40 | self.action_one(edit,arg) 41 | 42 | def action_one(self, edit,arg): 43 | global settings 44 | interface = Interface( 45 | sublime = sublime, 46 | view = self.view, 47 | window = sublime.active_window(), 48 | edit = edit, 49 | settings = settings 50 | ) 51 | interface.respond_to_query(arg) 52 | interface.respond_to_event({"event":"update_change_count","change_count":self.view.change_count()}) 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /python_voice_coding_plugin.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "show_invisible":true, 3 | "show_error":true, 4 | } -------------------------------------------------------------------------------- /queries/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /queries/__init__.py: -------------------------------------------------------------------------------- 1 | from PythonVoiceCodingPlugin.queries.abstract import * 2 | from PythonVoiceCodingPlugin.queries.argument import SelectArgument 3 | from PythonVoiceCodingPlugin.queries.alternatives import SelectAlternative 4 | from PythonVoiceCodingPlugin.queries.big_roi import SelectBigRoi 5 | from PythonVoiceCodingPlugin.queries.paste_back import PasteBack 6 | from PythonVoiceCodingPlugin.queries.collect_variable import CollectVariable 7 | from PythonVoiceCodingPlugin.queries.collect_parameter import CollectParameter 8 | from PythonVoiceCodingPlugin.queries.collect_module import CollectModule 9 | from PythonVoiceCodingPlugin.queries.collect_function_name import CollectFunctionName 10 | from PythonVoiceCodingPlugin.queries.collect_imported_value import CollectImportedValue 11 | from PythonVoiceCodingPlugin.queries.collect_decorator import CollectDecorator 12 | from PythonVoiceCodingPlugin.queries.collect_class_name import CollectClassName 13 | from PythonVoiceCodingPlugin.queries.insert_item import InsertItem 14 | from PythonVoiceCodingPlugin.queries.delete_alternatives import DeleteAlternatives 15 | from PythonVoiceCodingPlugin.queries.swap_back import SwapBack 16 | from PythonVoiceCodingPlugin.queries.select_part import SelectPart 17 | from PythonVoiceCodingPlugin.queries.select_back import SelectBack 18 | from PythonVoiceCodingPlugin.queries.remember_here import RememberHere 19 | 20 | 21 | 22 | 23 | def get_query(query_description): 24 | index = query_description["command"] 25 | if index in ["collect_indexable"]: 26 | index = { 27 | "variable":"collect_variable", 28 | "parameter":"collect_parameter", 29 | "module":"collect_module", 30 | "import value":"collect_imported_value", 31 | "function name":"collect_function_name", 32 | "class name":"collect_class_name", 33 | "decorator":"collect_decorator", 34 | }[query_description["collectable"]] 35 | h = { 36 | "argument": SelectArgument, 37 | "alternative": SelectAlternative, 38 | "big_roi": SelectBigRoi, 39 | "paste_back": PasteBack, 40 | 41 | "collect_variable": CollectVariable, 42 | "collect_parameter":CollectParameter, 43 | "collect_module":CollectModule, 44 | "collect_imported_value": CollectImportedValue, 45 | "collect_function_name": CollectFunctionName, 46 | "collect_decorator":CollectDecorator, 47 | "collect_class_name":CollectClassName, 48 | 49 | 50 | "insert_item": InsertItem, 51 | "delete_alternatives":DeleteAlternatives, 52 | "swap_back": SwapBack, 53 | "select_part": SelectPart, 54 | "select_back": SelectBack, 55 | "remember_here": RememberHere, 56 | } 57 | return h[index] 58 | 59 | 60 | def get_secondary_query(query_description): 61 | if "operation" not in query_description: 62 | return {} 63 | else: 64 | h={ 65 | "paste":{ 66 | "command":"paste_back", 67 | "format":1, 68 | }, 69 | "delete":{ 70 | "command":"delete_alternatives", 71 | "format":1, 72 | "color":0, 73 | }, 74 | "swap":{ 75 | "command":"swap_back", 76 | "format":1, 77 | }, 78 | "edit":{ 79 | "command":"alternative", 80 | "format":3, 81 | "color":0, 82 | }, 83 | } 84 | return h[query_description["operation"]] 85 | 86 | 87 | -------------------------------------------------------------------------------- /queries/abstract/__init__.py: -------------------------------------------------------------------------------- 1 | from PythonVoiceCodingPlugin.queries.abstract.query import * 2 | from PythonVoiceCodingPlugin.queries.abstract.selection_query import * 3 | from PythonVoiceCodingPlugin.queries.abstract.insertion_query import * 4 | from PythonVoiceCodingPlugin.queries.abstract.collection_query import * 5 | 6 | 7 | -------------------------------------------------------------------------------- /queries/abstract/collection_query.py: -------------------------------------------------------------------------------- 1 | import abc 2 | from copy import deepcopy 3 | from PythonVoiceCodingPlugin.library import get_source_region 4 | from PythonVoiceCodingPlugin.library.selection_node import nearest_node_from_offset,node_from_range 5 | from PythonVoiceCodingPlugin.library.modification import ModificationHandler 6 | from PythonVoiceCodingPlugin.queries.abstract.query import Query 7 | 8 | 9 | class CollectionQuery(Query): 10 | """docstring for CollectionQuery""" 11 | 12 | multiple_in = False 13 | indexable = False 14 | select_insertion = True 15 | label = "Collection" 16 | 17 | @abc.abstractmethod 18 | def handle_single(self,view_information,query_description,extra = {}): 19 | pass 20 | 21 | @abc.abstractmethod 22 | def handle_multiple(self,view_information,query_description,extra = {}): 23 | pass 24 | 25 | ################################################################ 26 | ################################################################ 27 | 28 | def __init__(self, code,latest_build = None): 29 | super(CollectionQuery, self).__init__(code,latest_build) 30 | self.result = None 31 | self.writing_positions = [] 32 | self.items = [] 33 | self.optional_selection = [] 34 | 35 | 36 | def __call__(self,view_information,query_description,extra = {}): 37 | selection = self._get_selection(view_information,extra) 38 | self.writing_positions = selection if isinstance(selection,list) else [selection] 39 | self.writing_positions = sorted(self.writing_positions) 40 | if self.indexable: 41 | self.result,self.items = self.handle_single(view_information,query_description,extra) 42 | if self.result and self.select_insertion: 43 | m = ModificationHandler() 44 | for location in self.writing_positions: 45 | m.modify_from(0, location, self.result) 46 | self.optional_selection = [m.forward(x) for x in self.writing_positions] 47 | else: 48 | self.items = self.handle_single(view_information,query_description,extra) 49 | 50 | return self.result,self.items,self.writing_positions ,self.optional_selection 51 | 52 | def _preliminary(self,view_information,query_description, extra = {}): 53 | selection = self._get_selection(view_information,extra) 54 | build = self.general_build 55 | if not build or not build[0] : 56 | return None,None,None 57 | root,atok,m,r = build 58 | selection = m.forward(selection) 59 | origin = nearest_node_from_offset(root,atok, selection[0]) if selection[0]==selection[1] else node_from_range(root,atok, selection) 60 | return build, selection, origin 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /queries/abstract/insertion_query.py: -------------------------------------------------------------------------------- 1 | import abc 2 | from copy import deepcopy 3 | 4 | from PythonVoiceCodingPlugin.library import get_source_region 5 | from PythonVoiceCodingPlugin.library.modification import ModificationHandler 6 | from PythonVoiceCodingPlugin.queries.abstract.query import Query 7 | 8 | 9 | 10 | class InsertionQuery(Query): 11 | ################################################################ 12 | # attributes and methods the user can override\change 13 | ################################################################ 14 | multiple_in = False 15 | select_insertion = True 16 | 17 | @abc.abstractmethod 18 | def handle_single(self,view_information,query_description,extra = {}): 19 | pass 20 | 21 | @abc.abstractmethod 22 | def handle_multiple(self,view_information,query_description,extra = {}): 23 | pass 24 | 25 | ################################################################ 26 | # standard code for default functionality 27 | ################################################################ 28 | def __init__(self, code,latest_build = None): 29 | super(InsertionQuery, self).__init__(code, latest_build) 30 | self.writing_locations_text = [] 31 | self.optional_selection = [] 32 | 33 | handle_single._original = True 34 | handle_multiple._original = True 35 | 36 | 37 | def __call__(self,view_information,query_description,extra = {}): 38 | self.view_information = view_information 39 | self.query_description = query_description 40 | selection = self._get_selection(view_information,extra) 41 | if isinstance(selection,list): 42 | if hasattr(self.handle_multiple,"_original"): 43 | if hasattr(self.handle_single,"_original") or not self.multiple_in: 44 | return [],[] 45 | self.writing_locations_text = [] 46 | for s in selection: 47 | temporary_extra = deepcopy(extra) 48 | temporary_extra["selection"] = s 49 | w = self.handle_single(view_information,query_description,temporary_extra) 50 | self.writing_locations_text.extend(w) 51 | else: 52 | self.writing_locations_text = self.handle_multiple(view_information,query_description, extra) 53 | else: 54 | if hasattr(self.handle_single,"_original"): 55 | return [],[] 56 | self.writing_locations_text = self.handle_single(view_information,query_description, extra) 57 | self.writing_locations_text = sorted(self.writing_locations_text, key = lambda x:x[0],reverse=True) 58 | if self.select_insertion: 59 | m = ModificationHandler() 60 | for location,t in self.writing_locations_text: 61 | # print(" inside the loop ", location,t,"\n") 62 | m.modify_from(0, location, t) 63 | self.optional_selection = [m.forward(x[0]) for x in self.writing_locations_text] 64 | return self.writing_locations_text,self.optional_selection 65 | 66 | -------------------------------------------------------------------------------- /queries/abstract/query.py: -------------------------------------------------------------------------------- 1 | from PythonVoiceCodingPlugin.library.partial import partially_parse 2 | 3 | class Query(): 4 | """docstring for Query""" 5 | def __init__(self, code,latest_build = None): 6 | self.code = code 7 | self.general_build = latest_build 8 | self.exceptions_raised = None 9 | self.data_for_storage = {} 10 | self.attempt_build() 11 | 12 | 13 | 14 | def __call__(self,view_information,query_description,extra = {}): 15 | pass 16 | 17 | def get_the_latest_build(self): 18 | return self.general_build 19 | 20 | def attempt_build(self): 21 | if self.general_build is None: 22 | try: 23 | self.general_build = partially_parse(self.code,rethrow_exception = True) 24 | except Exception as e: 25 | self.exceptions_raised = e 26 | 27 | def _get_selection(self,view_information,extra = {}): 28 | return extra["selection"] if "selection" in extra else view_information["selection"] 29 | 30 | def _register_for_storage(self,**kwargs): 31 | self.data_for_storage.update(kwargs) 32 | 33 | def no_build_attempt(cls): 34 | cls.attempt_build = lambda x: None 35 | return cls 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /queries/abstract/selection_query.py: -------------------------------------------------------------------------------- 1 | import abc 2 | from copy import deepcopy 3 | 4 | from PythonVoiceCodingPlugin.library import get_source_region 5 | from PythonVoiceCodingPlugin.queries.abstract.query import Query 6 | 7 | class SelectionQuery(Query): 8 | ################################################################ 9 | # attributes and methods the user can override\change 10 | ################################################################ 11 | multiple_in = False 12 | initial_origin_force_update = False 13 | 14 | @abc.abstractmethod 15 | def handle_single(self,view_information,query_description,extra = {}): 16 | pass 17 | 18 | 19 | @abc.abstractmethod 20 | def handle_multiple(self,view_information,query_description,extra = {}): 21 | pass 22 | 23 | ################################################################ 24 | # standard code for default functionality 25 | ################################################################ 26 | def __init__(self, code,latest_build = None): 27 | super(SelectionQuery, self).__init__(code,latest_build) 28 | self.result = None 29 | self.alternatives = None 30 | 31 | handle_single._original = True 32 | handle_multiple._original = True 33 | 34 | def get_result(self): 35 | return self.result 36 | 37 | def get_alternatives(self): 38 | return self.alternatives 39 | 40 | def get_the_latest_build(self): 41 | return self.general_build 42 | 43 | def _backward_result(self,result,alternatives,build,individually = False): 44 | if build and build[0]: 45 | m = build[2] 46 | atok = build[1] 47 | if individually: 48 | result = [m.backward(get_source_region(atok, x)) if x else None for x in result] 49 | else: 50 | result = m.backward(get_source_region(atok, result)) if result else None 51 | if alternatives: 52 | alternatives = [m.backward(get_source_region(atok,x)) for x in alternatives] 53 | else: 54 | alternatives = [] 55 | return result, alternatives 56 | else: 57 | return None,None 58 | 59 | 60 | def __call__(self,view_information,query_description,extra = {}): 61 | self.view_information = view_information 62 | self.query_description = query_description 63 | selection = self._get_selection(view_information,extra) 64 | if isinstance(selection,list): 65 | if hasattr(self.handle_multiple,"_original"): 66 | if hasattr(self.handle_single,"_original") or not self.multiple_in: 67 | return None,None 68 | self.result = [] 69 | self.alternatives = [] 70 | for s in selection: 71 | temporary_extra = deepcopy(extra) 72 | temporary_extra["selection"] = s 73 | r,a = self.handle_single(view_information,query_description,temporary_extra) 74 | if not isinstance(r,list): 75 | r =[r] 76 | self.result.append(r) 77 | self.alternatives.append(a) 78 | else: 79 | self.result ,self.alternatives = self.handle_multiple(view_information,query_description, extra) 80 | else: 81 | if hasattr(self.handle_single,"_original"): 82 | return None,None 83 | self.result ,self.alternatives = self.handle_single(view_information,query_description, extra) 84 | if isinstance(self.result,list): 85 | self.result = [self.result] 86 | self.alternatives = [self.alternatives] 87 | return self.result,self.alternatives 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /queries/alternatives.py: -------------------------------------------------------------------------------- 1 | from PythonVoiceCodingPlugin.library import make_flat 2 | from PythonVoiceCodingPlugin.queries.abstract import SelectionQuery, no_build_attempt 3 | from PythonVoiceCodingPlugin.queries.strategies import decode_item_selection,result_alternatives_sequence 4 | 5 | 6 | @no_build_attempt 7 | class SelectAlternative(SelectionQuery): 8 | """docstring for SelectAlternative""" 9 | 10 | def handle_multiple(self,view_information,query_description,extra = {}): 11 | return self.handle_single(view_information,query_description,extra) 12 | 13 | def handle_single(self,view_information,query_description,extra = {}): 14 | state = extra["state"] 15 | # print("state:\n",state) 16 | candidates = result_alternatives_sequence(state,location=True) 17 | # print("candidates:\n",candidates) 18 | if "alternative_index" in query_description: 19 | name="alternative_index" 20 | elif "color" in query_description: 21 | name = "color" 22 | else: 23 | return None,None 24 | if state["mode"]=="single": 25 | result = decode_item_selection(candidates,query_description,"individual",name,decrement=False) 26 | if len(result)==1: 27 | result = result[0] 28 | else: 29 | result = [decode_item_selection(x,query_description,"individual",name,decrement=False) for x in candidates] 30 | selection =self._get_selection(view_information,extra) 31 | if not isinstance(selection,list) or len(selection)==1: 32 | try : 33 | result = make_flat(result) 34 | except : 35 | pass 36 | # print("result is ",result) 37 | return result, [] 38 | 39 | 40 | -------------------------------------------------------------------------------- /queries/collect_class_name.py: -------------------------------------------------------------------------------- 1 | import ast 2 | from collections import OrderedDict 3 | 4 | from PythonVoiceCodingPlugin.library import sorted_by_source_region,get_source_region,make_flat 5 | from PythonVoiceCodingPlugin.library.info import * 6 | from PythonVoiceCodingPlugin.library.LCA import LCA 7 | from PythonVoiceCodingPlugin.library.level_info import LevelVisitor 8 | from PythonVoiceCodingPlugin.library.partial import partially_parse, line_partial 9 | from PythonVoiceCodingPlugin.library.traverse import search_upwards,search_upwards_log, find_matching,match_node, find_all_nodes,search_upwards_for_parent 10 | 11 | from PythonVoiceCodingPlugin.queries.abstract import CollectionQuery 12 | from PythonVoiceCodingPlugin.queries.tiebreak import tiebreak_on_lca 13 | from PythonVoiceCodingPlugin.queries.strategies import adjective_strategy,decode_abstract_vertical,translate_adjective,obtain_result 14 | from PythonVoiceCodingPlugin.queries.strategies import decode_item_selection 15 | 16 | 17 | class CollectClassName(CollectionQuery): 18 | label = 'ClassName' 19 | def handle_single(self,view_information,query_description,extra = {}): 20 | build, selection, origin = self._preliminary(view_information,query_description,extra) 21 | if not build: 22 | return None,None 23 | root,atok,m,r = build 24 | definition_node = search_upwards(origin,ast.ClassDef) if query_description["format"]!=1 else root 25 | name_nodes = [(x.name,0) for x in find_all_nodes(definition_node,ast.ClassDef)] 26 | name_nodes = name_nodes + [(atok.get_text(x),0) for x in find_matching(definition_node,is_base)] 27 | names = list(OrderedDict(name_nodes).keys()) 28 | return names 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /queries/collect_decorator.py: -------------------------------------------------------------------------------- 1 | import ast 2 | from collections import OrderedDict 3 | 4 | from PythonVoiceCodingPlugin.library import sorted_by_source_region,get_source_region,make_flat 5 | from PythonVoiceCodingPlugin.library.info import * 6 | from PythonVoiceCodingPlugin.library.LCA import LCA 7 | from PythonVoiceCodingPlugin.library.level_info import LevelVisitor 8 | from PythonVoiceCodingPlugin.library.partial import partially_parse, line_partial 9 | from PythonVoiceCodingPlugin.library.traverse import search_upwards,search_upwards_log, find_matching,match_node, find_all_nodes,search_upwards_for_parent 10 | 11 | from PythonVoiceCodingPlugin.queries.abstract import CollectionQuery 12 | from PythonVoiceCodingPlugin.queries.tiebreak import tiebreak_on_lca 13 | from PythonVoiceCodingPlugin.queries.strategies import adjective_strategy,decode_abstract_vertical,translate_adjective,obtain_result 14 | from PythonVoiceCodingPlugin.queries.strategies import decode_item_selection 15 | 16 | 17 | class CollectDecorator(CollectionQuery): 18 | label = 'ClassName' 19 | def handle_single(self,view_information,query_description,extra = {}): 20 | build, selection, origin = self._preliminary(view_information,query_description,extra) 21 | if not build: 22 | return None,None 23 | root,atok,m,r = build 24 | definition_node = search_upwards(origin,ast.ClassDef) if query_description["format"]!=1 else root 25 | temporary = find_matching(definition_node,is_decorator) 26 | name_nodes = [get_decorator_text(x,atok,False) for x in temporary] + [get_decorator_text(x,atok,True) for x in temporary] 27 | name_nodes = [(x,0) for x in name_nodes if x] 28 | names = list(OrderedDict(name_nodes).keys()) 29 | return names 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /queries/collect_function_name.py: -------------------------------------------------------------------------------- 1 | import ast 2 | from collections import OrderedDict 3 | 4 | from PythonVoiceCodingPlugin.library import sorted_by_source_region,get_source_region,make_flat 5 | from PythonVoiceCodingPlugin.library.info import * 6 | from PythonVoiceCodingPlugin.library.traverse import search_upwards,search_upwards_log, find_matching,match_node, find_all_nodes,search_upwards_for_parent 7 | 8 | from PythonVoiceCodingPlugin.queries.abstract import CollectionQuery 9 | 10 | 11 | 12 | 13 | 14 | class CollectFunctionName(CollectionQuery): 15 | indexable = False 16 | label = 'Function Names' 17 | def handle_single(self,view_information,query_description,extra = {}): 18 | build, selection, origin = self._preliminary(view_information,query_description,extra) 19 | if not build: 20 | return None,None 21 | root,atok,m,r = build 22 | definition_nodes = find_all_nodes(root,(ast.FunctionDef)) 23 | name_nodes = [x.name for x in definition_nodes] 24 | names = list(OrderedDict([(x,0) for x in name_nodes]).keys()) 25 | result = None 26 | return names 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /queries/collect_imported_value.py: -------------------------------------------------------------------------------- 1 | import ast 2 | from collections import OrderedDict 3 | 4 | from PythonVoiceCodingPlugin.library import sorted_by_source_region,get_source_region,make_flat 5 | from PythonVoiceCodingPlugin.library.info import * 6 | from PythonVoiceCodingPlugin.library.traverse import search_upwards,search_upwards_log, find_matching,match_node, find_all_nodes,search_upwards_for_parent 7 | 8 | from PythonVoiceCodingPlugin.queries.abstract import CollectionQuery 9 | 10 | 11 | 12 | 13 | 14 | class CollectImportedValue(CollectionQuery): 15 | indexable = True 16 | label = "Imported Values" 17 | def handle_single(self,view_information,query_description,extra = {}): 18 | build, selection, origin = self._preliminary(view_information,query_description,extra) 19 | if not build: 20 | return None,None 21 | root,atok,m,r = build 22 | definition_nodes = find_all_nodes(root,(ast.Import,ast.ImportFrom)) 23 | name_nodes = make_flat([get_imported_value_names(x) for x in definition_nodes]) 24 | names = list(OrderedDict([(x,0) for x in name_nodes]).keys()) 25 | result = names[query_description["collect_index"] - 1] if query_description["format"]==2 else None 26 | return result, names 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /queries/collect_module.py: -------------------------------------------------------------------------------- 1 | import ast 2 | from collections import OrderedDict 3 | 4 | from PythonVoiceCodingPlugin.library import sorted_by_source_region,get_source_region,make_flat 5 | from PythonVoiceCodingPlugin.library.info import * 6 | from PythonVoiceCodingPlugin.library.traverse import search_upwards,search_upwards_log, find_matching,match_node, find_all_nodes,search_upwards_for_parent 7 | 8 | from PythonVoiceCodingPlugin.queries.abstract import CollectionQuery 9 | 10 | 11 | 12 | 13 | 14 | class CollectModule(CollectionQuery): 15 | indexable = False 16 | label = "Modules" 17 | def handle_single(self,view_information,query_description,extra = {}): 18 | build, origin, selection = self._preliminary(view_information,query_description,extra) 19 | if not build: 20 | return None,None 21 | root,atok,m,r = build 22 | definition_nodes = find_all_nodes(root,(ast.Import,ast.ImportFrom)) 23 | name_nodes = make_flat([get_module_names(x) for x in definition_nodes]) 24 | for name in name_nodes: 25 | smaller = name.split(".") 26 | if len( smaller)>1: 27 | name_nodes.append(".".join(smaller[:-1])) 28 | names = list(OrderedDict([(x,0) for x in name_nodes]).keys()) 29 | result = None 30 | return names 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /queries/collect_parameter.py: -------------------------------------------------------------------------------- 1 | import ast 2 | from collections import OrderedDict 3 | 4 | from PythonVoiceCodingPlugin.library import sorted_by_source_region,get_source_region,make_flat 5 | from PythonVoiceCodingPlugin.library.info import * 6 | from PythonVoiceCodingPlugin.library.traverse import search_upwards,search_upwards_log, find_matching,match_node, find_all_nodes,search_upwards_for_parent 7 | 8 | from PythonVoiceCodingPlugin.queries.abstract import CollectionQuery 9 | from PythonVoiceCodingPlugin.queries.strategies import decode_item_selection 10 | from PythonVoiceCodingPlugin.queries.strategies import decode_abstract_vertical 11 | 12 | 13 | 14 | class CollectParameter(CollectionQuery): 15 | indexable = True 16 | label = 'Parameters' 17 | def handle_single(self,view_information,query_description,extra = {}): 18 | build, selection, origin = self._preliminary(view_information = view_information,query_description = query_description,extra = extra) 19 | if not build: 20 | return None,None 21 | root,atok,m,r = build 22 | definition_nodes = [search_upwards(origin,ast.FunctionDef)] if query_description["format"]>=2 else find_all_nodes(root,ast.FunctionDef) 23 | if query_description["format"]>=2: 24 | if "vertical_direction" in query_description: 25 | definition_node = definition_nodes[0] 26 | temporary_information = lambda x: match_node(x,ast.FunctionDef) 27 | direction = query_description["vertical_direction"] 28 | ndir = query_description["ndir"] 29 | row = view_information["rowcol"](m.backward(selection)[0])[0] + 1 if definition_node is None else definition_node.first_token.start[0] 30 | bonus = 1 if definition_node.first_token.startpos > selection[1] else 0 31 | t = decode_abstract_vertical(root,atok,(),row, ndir + bonus,direction,True,temporary_information) 32 | definition_nodes = [t] 33 | 34 | name_nodes = make_flat([get_argument_from_definition(x) for x in definition_nodes]) 35 | names = list(OrderedDict([(x,0) for x in name_nodes]).keys()) 36 | if "experimental" in query_description: 37 | names = [x + "=" + x for x in names] 38 | if query_description["format"]==1: 39 | result = None 40 | else: 41 | mode = { 42 | 2:"individual", 43 | 3:"range", 44 | }[query_description["format"]] 45 | result = ",".join(decode_item_selection(names,query_description,mode,"item_index")) 46 | return result, names 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /queries/collect_variable.py: -------------------------------------------------------------------------------- 1 | import ast 2 | from collections import OrderedDict 3 | 4 | from PythonVoiceCodingPlugin.library import sorted_by_source_region,get_source_region,make_flat 5 | from PythonVoiceCodingPlugin.library.info import * 6 | from PythonVoiceCodingPlugin.library.LCA import LCA 7 | from PythonVoiceCodingPlugin.library.level_info import LevelVisitor 8 | from PythonVoiceCodingPlugin.library.partial import partially_parse, line_partial 9 | from PythonVoiceCodingPlugin.library.traverse import search_upwards,search_upwards_log, find_matching,match_node, find_all_nodes,search_upwards_for_parent 10 | 11 | from PythonVoiceCodingPlugin.queries.abstract import CollectionQuery 12 | from PythonVoiceCodingPlugin.queries.tiebreak import tiebreak_on_lca 13 | from PythonVoiceCodingPlugin.queries.strategies import adjective_strategy,decode_abstract_vertical,translate_adjective,obtain_result 14 | from PythonVoiceCodingPlugin.queries.strategies import decode_item_selection 15 | 16 | 17 | class CollectVariable(CollectionQuery): 18 | indexable = True 19 | label = 'Variables' 20 | def handle_single(self,view_information,query_description,extra = {}): 21 | build, selection, origin = self._preliminary(view_information,query_description,extra) 22 | if not build: 23 | return None,None 24 | root,atok,m,r = build 25 | definition_node = search_upwards(origin,ast.FunctionDef) if query_description["format"]!=1 else root 26 | name_nodes = [(get_id(x),0) for x in find_all_nodes(definition_node,ast.Name) if is_store(x)] 27 | names = list(OrderedDict(name_nodes).keys()) 28 | if query_description["format"]==1: 29 | result = None 30 | else: 31 | mode = { 32 | 2:"individual", 33 | 3:"range", 34 | }[query_description["format"]] 35 | result = ",".join(decode_item_selection(names,query_description,mode,"item_index")) 36 | return result, names 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /queries/delete_alternatives.py: -------------------------------------------------------------------------------- 1 | from PythonVoiceCodingPlugin.library import make_flat 2 | from PythonVoiceCodingPlugin.queries.abstract import InsertionQuery,no_build_attempt 3 | from PythonVoiceCodingPlugin.queries.strategies import result_alternatives_sequence 4 | 5 | 6 | @no_build_attempt 7 | class DeleteAlternatives(InsertionQuery): 8 | select_insertion = True 9 | multiple_in = True 10 | # def handle_single(self,view_information,query_description,extra = {}): 11 | # candidates = result_alternatives_sequence(extra["state"],location= True) 12 | # if query_description["format"] == 1: 13 | # selection = {candidates[query_description["color"+i]] 14 | # for i in ["","2","3","4"] if "color"+i in query_description} 15 | # return [(x,"") for x in selection] 16 | # 17 | 18 | def filter_overlapping(self,selection): 19 | 20 | if selection: 21 | selection = sorted(selection) 22 | result = [selection[0]] 23 | print(type(result)) 24 | for s in selection: 25 | print(type(s)) 26 | if s[1]=1 and history[index-1][1] == view_information["change_count"]: 14 | index -=1 15 | if index==len(history) or history[index][1] != view_information["change_count"]: 16 | return [] 17 | selection = history[index][2] 18 | selection = selection if isinstance(selection,list) else [selection] 19 | f = query_description["format"] 20 | if f==1: 21 | i = query_description["paste_back_index"] 22 | elif f==2: 23 | i = query_description["color"] 24 | else: 25 | return [] 26 | result = state["result"] 27 | alternatives = state["alternatives"] 28 | location = alternatives[i-1] if i != 0 else result 29 | location = location if isinstance(location,list) else [location] 30 | return [(x,code[l[0]:l[1]]) for x,l in zip(selection, location)] 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /queries/insert_item.py: -------------------------------------------------------------------------------- 1 | from PythonVoiceCodingPlugin.queries.abstract import InsertionQuery,no_build_attempt 2 | from PythonVoiceCodingPlugin.queries.strategies import decode_item_selection 3 | 4 | @no_build_attempt 5 | class InsertItem(InsertionQuery): 6 | select_insertion = True 7 | multiple_in = True 8 | 9 | def handle_single(self,view_information,query_description,extra = {}): 10 | collection = extra["global_state"]["collection"] 11 | mode = { 12 | 1:"individual", 13 | 3:"individual", 14 | 2:"range", 15 | }[query_description["format"]] 16 | items = ",".join(decode_item_selection(collection,query_description,mode,"item_index")) 17 | selection = self._get_selection(view_information,extra) 18 | selection = selection if isinstance(selection,list) else [selection] 19 | return [(x,items) for x in selection] 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /queries/paste_back.py: -------------------------------------------------------------------------------- 1 | from PythonVoiceCodingPlugin.library import make_flat 2 | from PythonVoiceCodingPlugin.queries.abstract import InsertionQuery,no_build_attempt 3 | from PythonVoiceCodingPlugin.queries.strategies import result_alternatives_sequence 4 | 5 | def surround(surrounding,text): 6 | assert isinstance(surrounding,(str,tuple,list)), "Surrounding must be either a string, tuple or list not a " + str(type(surrounding)) 7 | if isinstance(surrounding,(tuple,list)): 8 | surrounding = ( 9 | surrounding[0].replace("quotes",'"'), 10 | surrounding[1].replace("quotes",'"'), 11 | ) 12 | 13 | return surrounding[0] + text + surrounding[1] 14 | if isinstance(surrounding,str): 15 | surrounding = surrounding.replace("quotes",'"') 16 | surrounding = surrounding.replace("$$",text) 17 | return surrounding 18 | 19 | 20 | 21 | 22 | 23 | 24 | @no_build_attempt 25 | class PasteBack(InsertionQuery): 26 | select_insertion = True 27 | def handle_multiple(self,view_information,query_description,extra = {}): 28 | return self.handle_single(view_information,query_description,extra) 29 | 30 | def handle_single(self,view_information,query_description,extra = {}): 31 | state = extra["state"] 32 | print("\ninside query ",state,"\n\n") 33 | history = extra["history"] 34 | candidates = result_alternatives_sequence(state,text = True) 35 | candidates_location = result_alternatives_sequence(state,location = True) 36 | surrounding = query_description.get("surrounding_punctuation",("","")) 37 | # surrounding = surrounding if surrounding != "quotes" else ('"','"') 38 | if query_description["format"]==1: 39 | selection = state["initial_origin"] 40 | if state["initial_mode"]=="multiple": 41 | selection = make_flat(selection) 42 | 43 | if state["mode"]=="single": 44 | output = candidates[query_description.get("color",0)] 45 | selection = selection if isinstance(selection,list) else [selection] 46 | return [(x,surround(surrounding,output)) for x in selection] 47 | 48 | elif state["mode"]=="multiple": 49 | try : 50 | output = [x[query_description.get("color",0)] for x in candidates] 51 | except IndexError as e: 52 | raise Exception("tried to obtain an alternative color that is not common!") 53 | 54 | if state["initial_mode"]=="single": 55 | print("Output:\n",output) 56 | try : 57 | output = make_flat(output) 58 | except : 59 | pass 60 | output = ",".join([surround(surrounding,x) for x in output]) 61 | return [(state["initial_origin"],output)] 62 | # raise Exception("can't paste multiple values the same origin!") 63 | 64 | elif state["initial_mode"]=="multiple": 65 | if len(state["initial_origin"]) != len(state["origin"]): 66 | print("before doing anything Palenque's ",output) 67 | if len(output)==1 and isinstance(output[0],list): 68 | output = make_flat(output) 69 | if len(state["origin"])==1 and len(output)==len(state["initial_origin"]): 70 | return [(x,surround(surrounding,y)) for y,x in zip(output,selection)] 71 | print("their respective lengths are",len(output),len(state["initial_origin"]),output, "\n") 72 | raise Exception("mismatch of things to paste and locations to place") 73 | 74 | if any(isinstance(x,list) for x in output): 75 | raise Exception("one of the results spanned over multiple selections, this is not supported!") 76 | return [(x,surround(surrounding,y)) for y,x in zip(output,selection)] 77 | 78 | if query_description["format"]==2: 79 | if state["mode"]=="multiple": 80 | raise Exception("pasting between alternatives is possible only in single mode") 81 | selection = {candidates_location[query_description["color"+i]] 82 | for i in ["2","3","4"] if "color"+i in query_description} 83 | output = candidates[query_description.get("color",0)] 84 | return [(x,surround(surrounding,output)) for x in selection] 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /queries/remember_here.py: -------------------------------------------------------------------------------- 1 | from PythonVoiceCodingPlugin.library import make_flat 2 | from PythonVoiceCodingPlugin.queries.abstract import SelectionQuery, no_build_attempt 3 | 4 | 5 | 6 | @no_build_attempt 7 | class RememberHere(SelectionQuery): 8 | """docstring for SelectAlternative""" 9 | initial_origin_force_update = True 10 | 11 | def handle_multiple(self,view_information,query_description,extra = {}): 12 | return self.handle_single(view_information,query_description,extra) 13 | 14 | def handle_single(self,view_information,query_description,extra = {}): 15 | selection = self._get_selection(view_information,extra) 16 | return selection,[] 17 | 18 | 19 | -------------------------------------------------------------------------------- /queries/select_back.py: -------------------------------------------------------------------------------- 1 | from PythonVoiceCodingPlugin.library import make_flat 2 | from PythonVoiceCodingPlugin.queries.abstract import SelectionQuery, no_build_attempt 3 | from PythonVoiceCodingPlugin.queries.strategies import decode_item_selection,result_alternatives_sequence 4 | 5 | 6 | @no_build_attempt 7 | class SelectBack(SelectionQuery): 8 | """docstring for SelectAlternative""" 9 | 10 | def handle_multiple(self,view_information,query_description,extra = {}): 11 | return self.handle_single(view_information,query_description,extra) 12 | 13 | def handle_single(self,view_information,query_description,extra = {}): 14 | state = extra["state"] 15 | if query_description["format"]==1: 16 | return state["initial_origin"],[] 17 | elif query_description["format"]==2: 18 | return state["origin"],[] 19 | 20 | -------------------------------------------------------------------------------- /queries/select_part.py: -------------------------------------------------------------------------------- 1 | import ast 2 | 3 | from PythonVoiceCodingPlugin.library import sorted_by_source_region,get_source_region,make_flat 4 | from PythonVoiceCodingPlugin.library.selection_node import nearest_node_from_offset,node_from_range 5 | from PythonVoiceCodingPlugin.library.info import * 6 | from PythonVoiceCodingPlugin.library.partial import partially_parse, line_partial 7 | from PythonVoiceCodingPlugin.library.traverse import search_upwards,search_upwards_log, find_matching,match_node, find_all_nodes,search_upwards_for_parent 8 | 9 | from PythonVoiceCodingPlugin.queries.abstract import SelectionQuery 10 | from PythonVoiceCodingPlugin.queries.tiebreak import tiebreak_on_lca 11 | from PythonVoiceCodingPlugin.queries.strategies import translate_adjective,obtain_result 12 | 13 | 14 | 15 | 16 | class SelectPart(SelectionQuery): 17 | multiple_in = True 18 | 19 | 20 | 21 | def handle_single(self,view_information,query_description,extra = {}): 22 | # print(" inside here selection where he parked ") 23 | selection = self._get_selection(view_information,extra) 24 | build = self.general_build if self.general_build else line_partial(self.code,selection[0]) 25 | if not build or not build[0] : 26 | return None,None 27 | root,atok,m,r = build 28 | selection = m.forward(selection) 29 | origin = nearest_node_from_offset(root,atok, selection[0],special = True) if selection[0]==selection[1] else node_from_range(root,atok, selection,special = True) 30 | if selection[0]==selection[1]: 31 | # return None,None 32 | pass 33 | second_origin = origin 34 | if "nth" in query_description: 35 | # print(" hello world ") 36 | # print(translate_adjective[query_description["nth"]]) 37 | second_origin = get_sub_index(origin,translate_adjective[query_description["nth"]]-1) 38 | 39 | if query_description["format"]==1: 40 | if "nth2" in query_description: 41 | second_origin = get_sub_index(second_origin,translate_adjective[query_description["nth2"]]-1) 42 | result = get_sub_index(second_origin,query_description["sub_index"]-1) 43 | alternatives = [] 44 | elif query_description["format"]==2: 45 | if "nth2" in query_description: 46 | second_origin = get_sub_index(second_origin,translate_adjective[query_description["nth2"]]-1) 47 | result = [ 48 | get_sub_index(second_origin,query_description["sub_index"]-1), 49 | get_sub_index(second_origin,query_description.get("sub_index2",0)-1) 50 | ] 51 | alternatives=[] 52 | elif query_description["format"]==3 or query_description["format"]==4: 53 | intermediate = get_sub_index(second_origin,None) 54 | if "nth2" in query_description: 55 | intermediate = [get_sub_index(x,translate_adjective[query_description["nth2"]]-1) for x in intermediate] 56 | intermediate = [x for x in intermediate if x] 57 | if "sub_index" in query_description: 58 | candidates = [get_sub_index(x,query_description["sub_index"]-1) for x in intermediate] 59 | candidates = [x for x in candidates if x] 60 | else: 61 | candidates = intermediate 62 | if query_description["format"]==3: 63 | result,alternatives = obtain_result(None, candidates) 64 | elif query_description["format"]==4: 65 | result = candidates if candidates else None 66 | alternatives=[] 67 | return self._backward_result(result, alternatives,build,individually=query_description["format"]==4) 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /queries/strategies/__init__.py: -------------------------------------------------------------------------------- 1 | from PythonVoiceCodingPlugin.queries.strategies.primitives import * 2 | from PythonVoiceCodingPlugin.queries.strategies.adjective_strategy import * 3 | from PythonVoiceCodingPlugin.queries.strategies.abstract_vertical import * 4 | from PythonVoiceCodingPlugin.queries.strategies.obtain import * 5 | from PythonVoiceCodingPlugin.queries.strategies.state_extraction import * 6 | from PythonVoiceCodingPlugin.queries.strategies.item_selection import * 7 | 8 | 9 | -------------------------------------------------------------------------------- /queries/strategies/abstract_vertical.py: -------------------------------------------------------------------------------- 1 | import ast 2 | from bisect import bisect_right,bisect_left 3 | 4 | from PythonVoiceCodingPlugin.library.traverse import search_upwards,search_upwards_log, find_matching,match_node, find_all_nodes 5 | from PythonVoiceCodingPlugin.queries.strategies.obtain import obtain_result 6 | 7 | def decode_abstract_vertical(root,atok, target,current_line, index,direction, 8 | want_node = False, selector = None, want_alternatives = False): 9 | nodes = find_matching(root, selector) if selector else find_all_nodes(root,target) 10 | line_information = set() 11 | for n in nodes: 12 | line_information.add(n.first_token.start[0]) 13 | line_information = sorted(list(line_information)) 14 | ll=len(line_information) 15 | if direction=="downwards": 16 | i = bisect_right(line_information,current_line) 17 | i = min(ll-1,i+index-1) 18 | elif direction=="upwards": 19 | i = bisect_left(line_information,current_line) 20 | i = max(0,i-index) 21 | else: 22 | return None 23 | if want_node: 24 | if want_alternatives: 25 | candidates = [x for x in nodes if x.first_token.start[0] == line_information[i]] 26 | return obtain_result(None,candidates) 27 | for n in nodes: 28 | if n.first_token.start[0] == line_information[i]: 29 | return n 30 | else: 31 | return None 32 | else: 33 | return line_information[i] 34 | 35 | 36 | 37 | def decode_vertical_groups(atok,current_line,index,direction): 38 | groups = [] 39 | written = [] 40 | data = [not x.isspace() for x in atok.text.splitlines()] 41 | if not data: 42 | return None , None 43 | l = data[0] 44 | for i,d in enumerate(data): 45 | if d != l: 46 | groups.append(i) 47 | written.append(d) 48 | location = bisect_right(groups,current_line) - 1 49 | offset = -1 if direction in ["above","up"] else 1 50 | if written[location]: 51 | potential_location = location + 2*index*offset 52 | else: 53 | potential_location = location + 2*index*offset - offset 54 | x = groups 55 | 56 | advance = lambda x: x - 1 if direction in ["above","up"] else x+1 57 | pointer=current_line 58 | while data[pointer] and 0n and len(l) >= -1*n else d 3 | 4 | 5 | def root_level_order(accumulator,root,level,index,only_information,priority,penalty): 6 | first_option = level(root,1, index,False) 7 | second_option = level(root,1, index,True) 8 | if first_option in level.special and only_information==False: 9 | accumulator.push(first_option,priority) 10 | else: 11 | first_option = None 12 | if not only_information or True: 13 | accumulator.push(second_option,priority,penalty = 0 if not first_option else penalty) 14 | 15 | def root_lexical_order(accumulator,root,level_nodes,information_nodes,index, 16 | only_information,priority,penalty,lca = None,constrained_space = None): 17 | # print(" I entered a roach lexical order") 18 | if lca: 19 | level_nodes = [x for x in level_nodes if lca.is_child(x,root)] 20 | information_nodes = [x for x in information_nodes if lca.is_child(x,root)] 21 | # print("inside Drew's lexical order",level_nodes,information_nodes) 22 | if constrained_space: 23 | level_nodes = [x for x in level_nodes if constrained_space[0]=1 and history[index-1][1] == view_information["change_count"]: 21 | # index -=1 22 | # if index==len(history) or history[index][1] != view_information["change_count"]: 23 | # return [] 24 | candidates = result_alternatives_sequence(state,location = True,text = True) 25 | if query_description["format"]==1: 26 | if extra["secondary"]: 27 | for location,t in candidates: 28 | if not overlap_regions(location,state["origin"]): 29 | decision = (location,t) 30 | break 31 | else: 32 | raise Exception("Swamp cannot swap regions of overlap!!!") 33 | else: 34 | decision = candidates[query_description.get("color",0)] 35 | location_text = [(state["origin"],state["origin_text"]),decision] 36 | if query_description["format"]==2: 37 | location_text = [candidates[query_description["color"+i]] 38 | for i in ["","2","3","4"] if "color"+i in query_description] 39 | output = [] 40 | for j in range(0,len(location_text)): 41 | x = location_text[j] 42 | y = location_text[j-1] 43 | assert not overlap_regions(x[0],y[0]),"Locations Are " + x + " " + y 44 | output.append((x[0],y[1])) 45 | 46 | return output 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /queries/tiebreak.py: -------------------------------------------------------------------------------- 1 | import ast 2 | 3 | from PythonVoiceCodingPlugin.library.LCA import LCA 4 | from PythonVoiceCodingPlugin.library.level_info import LevelVisitor 5 | from PythonVoiceCodingPlugin.library.traverse import match_node 6 | 7 | 8 | 9 | def tiebreak_on_lca(root,origin,candidates,lca = None): 10 | """ranks nodes based on the depth of their lowest_common_ancestor 11 | With origin (the deeper the better). In case of ties the note 12 | Closer to the LCA is preferred. 13 | 14 | Args: 15 | root (TYPE): Description 16 | origin (TYPE): Description 17 | candidates (TYPE): Description 18 | 19 | Returns: 20 | TYPE: Description 21 | """ 22 | lca = LCA(root) if lca is None else lca 23 | def tiebreaker(x): 24 | depth,node = lca(x, origin,node_and_depth = True) 25 | v = 3 26 | if match_node(node,ast.Dict): 27 | if node is not x and node is not origin: 28 | field,field_index = lca.get_field_with_respect_to(x,node) 29 | ofield,ofield_index = lca.get_field_with_respect_to(origin,node) 30 | v = abs(field_index - ofield_index) 31 | v = v if v<3 else 3 32 | return (-1 * depth,v,lca.get_depth(x),abs(x.first_token.start[0] - origin.first_token.start[0])) 33 | 34 | return sorted(candidates, key = tiebreaker) 35 | 36 | 37 | 38 | def tiebreak_on_visual(original_line,result,alternatives): 39 | if result: 40 | if original_line: 41 | k = lambda x: ( 42 | abs(x.first_token.start[0] - result.first_token.start[0]) + 43 | ( 44 | 10 if ( 45 | x.first_token.start[0]<=original_line<=result.first_token.start[0] or 46 | x.first_token.start[0]>=original_line>=result.first_token.start[0] 47 | ) else 0 48 | ) 49 | ) 50 | else: 51 | k = lambda x: abs(x.first_token.start[0] - result.first_token.start[0]) 52 | if alternatives: 53 | return sorted(alternatives, key = k) 54 | return alternatives 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /queries/utility.py: -------------------------------------------------------------------------------- 1 | def reestablish_priority(initial,adjusted): 2 | output={} 3 | to_be_removed = {k for k,v in adjusted.items() if v<0} 4 | initial_order = sorted(initial.items(),key=lambda x:x[1]) 5 | adjusted_order = sorted(adjusted.items(),key=lambda x:x[1]) 6 | already_assigned_values = set(adjusted.values()) 7 | for k,v in adjusted_order: 8 | output[k] = v 9 | for k,v in initial_order: 10 | if k not in output: 11 | while v in already_assigned_values: 12 | v = v + 1 13 | output[k] = v 14 | already_assigned_values.add(v) 15 | 16 | if len(set(adjusted.keys())-to_be_removed)!=len(set(adjusted.values()))-(1 if to_be_removed else 0): 17 | raise Exception("you cannot assign the same priority for two strategies",adjusted) 18 | 19 | return output 20 | 21 | 22 | 23 | 24 | class ResultAccumulator(): 25 | """docstring for ResultAccumulator""" 26 | def __init__(self,penalized=[], penalty=0): 27 | self.accumulator = {} 28 | self.penalized = set(penalized) 29 | self.penalty = penalty 30 | self.history = [] 31 | 32 | def push(self,node,priority,penalty = 0): 33 | self.history.append((node,priority)) 34 | if not node: 35 | return None 36 | if node in self.penalized: 37 | priority = self.penalize(priority,self.penalty) 38 | priority = self.penalize(priority,penalty) 39 | if priority < 0: 40 | return 41 | elif priority not in self.accumulator: 42 | self.accumulator[priority] = [node] 43 | else: 44 | self.accumulator[priority].append(node) 45 | 46 | def penalize(self,priority,penalty): 47 | if priority<0: 48 | return priority 49 | else: 50 | return priority+penalty 51 | 52 | def get_result(self): 53 | visited = set() 54 | finalists = [] 55 | sorted_keys = sorted(self.accumulator.keys()) 56 | for x in sorted_keys: 57 | for node in self.accumulator[x]: 58 | if node not in visited: 59 | visited.add(node) 60 | finalists.append(node) 61 | if len(finalists)>=1: 62 | return finalists[0],finalists[1:] 63 | else: 64 | return None,None 65 | 66 | 67 | -------------------------------------------------------------------------------- /quick_install_python_voice_coding_plugin.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | import sublime 5 | import sublime_plugin 6 | 7 | greeting = ''' 8 | Thanks for trying out PythonVoiceCodingPlugin! 9 | 10 | To complete your installation, you need to copy the bundled grammar for your version of Caster into your appropriate Caster user directory. Afterwards reboot Caster and if needed enable the grammar by saying 11 | 12 | enable python voice coding plugin 13 | 14 | You can retrieve those grammars under 15 | 16 | Preferences > Package Settings > PythonVoiceCodingPlugin 17 | 18 | where you will also find links to documentation with lots of examples and my gitter chatroom for questions and troubleshooting. 19 | 20 | To make your life easier with the copy pasting, if you're on windows and using Caster 1.x.x, there is also utility to handle this process automatically for you! Do you want to run it? 21 | ''' 22 | 23 | 24 | def plugin_loaded(): 25 | window = sublime.active_window() 26 | try : 27 | from package_control import events 28 | if events.install("PythonVoiceCodingPlugin"): 29 | if sublime.yes_no_cancel_dialog(greeting)!=sublime.DIALOG_YES: 30 | return 31 | window.run_command("quick_install_python_voice_coding_plugin",{}) 32 | except : 33 | pass 34 | 35 | 36 | 37 | class QuickInstallPythonVoiceCodingPluginCommand(sublime_plugin.WindowCommand): 38 | def run(self): 39 | if sublime.platform()!="windows": 40 | sublime.error_message("Quick install has only meaning in windows") 41 | return 42 | candidates = [] 43 | for user in os.listdir("C:\\Users"): 44 | for x in [".caster\\rules","AppData\\Local\\caster\\rules"]: 45 | if os.path.isdir(os.path.join("C:\\Users",user,x)): 46 | candidates.append(os.path.join("C:\\Users",user,x)) 47 | if not candidates: 48 | sublime.error_message("No Caster 1.x.x user directory was found! Are you sure you have it installedand you are not using an older version?") 49 | def on_done(index): 50 | if index==-1: 51 | return 52 | c = candidates[index] 53 | name = "python_voice_coding_plugin_caster_v1-0-0.py" 54 | if os.path.exists(os.path.join(c,name)): 55 | if sublime.yes_no_cancel_dialog("The grammar file already exists, surely you want to replace it")!=sublime.DIALOG_YES: 56 | return 57 | 58 | with open(os.path.join(sublime.packages_path(),"PythonVoiceCodingPlugin\\bundles\\Caster",name),"r") as f: 59 | s = f.read() 60 | with open(os.path.join(c,name),"w") as f: 61 | f.write(s) 62 | sublime.error_message("Grammar successfully copied!") 63 | self.window.show_quick_panel(candidates,on_done) 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asttokens==1.1.13 # Apache-2.0 , should work with higher versions but not tested yet 2 | astmonkey==0.3.6 3 | segment_tree==0.2.3 4 | -------------------------------------------------------------------------------- /third_party/.gitignore: -------------------------------------------------------------------------------- 1 | *.dist-info 2 | __pycache__ 3 | 4 | -------------------------------------------------------------------------------- /third_party/README.md: -------------------------------------------------------------------------------- 1 | # Directory For Dependencies 2 | -------------------------------------------------------------------------------- /third_party/astmonkey/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.3.6' 2 | -------------------------------------------------------------------------------- /third_party/astmonkey/transformers.py: -------------------------------------------------------------------------------- 1 | import ast 2 | 3 | 4 | class ParentChildNodeTransformer(object): 5 | 6 | def visit(self, node): 7 | self._prepare_node(node) 8 | for field, value in ast.iter_fields(node): 9 | self._process_field(node, field, value) 10 | return node 11 | 12 | @staticmethod 13 | def _prepare_node(node): 14 | if not hasattr(node, 'parent'): 15 | node.parent = None 16 | if not hasattr(node, 'parents'): 17 | node.parents = [] 18 | if not hasattr(node, 'children'): 19 | node.children = [] 20 | 21 | def _process_field(self, node, field, value): 22 | if isinstance(value, list): 23 | for index, item in enumerate(value): 24 | if isinstance(item, ast.AST): 25 | self._process_child(item, node, field, index) 26 | elif isinstance(value, ast.AST): 27 | self._process_child(value, node, field) 28 | 29 | def _process_child(self, child, parent, field_name, index=None): 30 | self.visit(child) 31 | child.parent = parent 32 | child.parents.append(parent) 33 | child.parent_field = field_name 34 | child.parent_field_index = index 35 | child.parent.children.append(child) 36 | -------------------------------------------------------------------------------- /third_party/astmonkey/utils.py: -------------------------------------------------------------------------------- 1 | import ast 2 | import sys 3 | 4 | 5 | def is_docstring(node): 6 | if node.parent is None or node.parent.parent is None: 7 | return False 8 | def_node = node.parent.parent 9 | return ( 10 | isinstance(def_node, (ast.FunctionDef, ast.ClassDef, ast.Module)) and def_node.body and 11 | isinstance(def_node.body[0], ast.Expr) and isinstance(def_node.body[0].value, ast.Str) and 12 | def_node.body[0].value == node 13 | ) 14 | 15 | 16 | def get_by_python_version(classes, python_version=sys.version_info): 17 | result = None 18 | for cls in classes: 19 | if cls.__python_version__ <= python_version: 20 | if not result or cls.__python_version__ > result.__python_version__: 21 | result = cls 22 | if not result: 23 | raise NotImplementedError('astmonkey does not support Python %s.' % sys.version) 24 | return result 25 | 26 | 27 | class CommaWriter: 28 | 29 | def __init__(self, write_func, add_space_at_beginning=False): 30 | self.write_func = write_func 31 | self.add_space_at_beginning = add_space_at_beginning 32 | self.not_called_yet = True 33 | 34 | def __call__(self, *args, **kwargs): 35 | if self.not_called_yet: 36 | self.not_called_yet = False 37 | if self.add_space_at_beginning: 38 | self.write_func(' ') 39 | else: 40 | self.write_func(', ') 41 | 42 | def check_version(from_inclusive=None, to_exclusive=None): 43 | if (not from_inclusive or sys.version_info >= from_inclusive) \ 44 | and (not to_exclusive or sys.version_info < to_exclusive): 45 | return True 46 | return False 47 | -------------------------------------------------------------------------------- /third_party/asttokens/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Grist Labs, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """ 16 | This module enhances the Python AST tree with token and source code information, sufficent to 17 | detect the source text of each AST node. This is helpful for tools that make source code 18 | transformations. 19 | """ 20 | 21 | from .line_numbers import LineNumbers 22 | from .asttokens import ASTTokens 23 | -------------------------------------------------------------------------------- /third_party/asttokens/line_numbers.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 Grist Labs, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import bisect 16 | import re 17 | 18 | _line_start_re = re.compile(r'^', re.M) 19 | 20 | class LineNumbers(object): 21 | """ 22 | Class to convert between character offsets in a text string, and pairs (line, column) of 1-based 23 | line and 0-based column numbers, as used by tokens and AST nodes. 24 | 25 | This class expects unicode for input and stores positions in unicode. But it supports 26 | translating to and from utf8 offsets, which are used by ast parsing. 27 | """ 28 | def __init__(self, text): 29 | # A list of character offsets of each line's first character. 30 | self._line_offsets = [m.start(0) for m in _line_start_re.finditer(text)] 31 | self._text = text 32 | self._text_len = len(text) 33 | self._utf8_offset_cache = {} # maps line num to list of char offset for each byte in line 34 | 35 | def from_utf8_col(self, line, utf8_column): 36 | """ 37 | Given a 1-based line number and 0-based utf8 column, returns a 0-based unicode column. 38 | """ 39 | offsets = self._utf8_offset_cache.get(line) 40 | if offsets is None: 41 | end_offset = self._line_offsets[line] if line < len(self._line_offsets) else self._text_len 42 | line_text = self._text[self._line_offsets[line - 1] : end_offset] 43 | 44 | offsets = [i for i,c in enumerate(line_text) for byte in c.encode('utf8')] 45 | offsets.append(len(line_text)) 46 | self._utf8_offset_cache[line] = offsets 47 | 48 | return offsets[max(0, min(len(offsets)-1, utf8_column))] 49 | 50 | def line_to_offset(self, line, column): 51 | """ 52 | Converts 1-based line number and 0-based column to 0-based character offset into text. 53 | """ 54 | line -= 1 55 | if line >= len(self._line_offsets): 56 | return self._text_len 57 | elif line < 0: 58 | return 0 59 | else: 60 | return min(self._line_offsets[line] + max(0, column), self._text_len) 61 | 62 | def offset_to_line(self, offset): 63 | """ 64 | Converts 0-based character offset to pair (line, col) of 1-based line and 0-based column 65 | numbers. 66 | """ 67 | offset = max(0, min(self._text_len, offset)) 68 | line_index = bisect.bisect_right(self._line_offsets, offset) - 1 69 | return (line_index + 1, offset - self._line_offsets[line_index]) 70 | 71 | 72 | -------------------------------------------------------------------------------- /third_party/segment_tree/__init__.py: -------------------------------------------------------------------------------- 1 | from .segment_tree import * 2 | -------------------------------------------------------------------------------- /third_party/segment_tree/operations.py: -------------------------------------------------------------------------------- 1 | class Operation: 2 | def __init__(self, name, function, function_on_equal, neutral_value=0): 3 | self.name = name 4 | self.f = function 5 | self.f_on_equal = function_on_equal 6 | 7 | 8 | def add_multiple(x, count): 9 | return x * count 10 | 11 | 12 | def min_multiple(x, count): 13 | return x 14 | 15 | 16 | def max_multiple(x, count): 17 | return x 18 | 19 | 20 | sum_operation = Operation("sum", sum, add_multiple, 0) 21 | min_operation = Operation("min", min, min_multiple, 1e9) 22 | max_operation = Operation("max", max, max_multiple, -1e9) 23 | -------------------------------------------------------------------------------- /third_party/segment_tree/segment_tree.py: -------------------------------------------------------------------------------- 1 | from segment_tree.operations import * 2 | 3 | 4 | class SegmentTree: 5 | """ 6 | SegmentTree class. Handles an underlying array as well as available 7 | operations and pointer to the root of a tree. 8 | """ 9 | 10 | def __init__(self, 11 | array, 12 | operations=[sum_operation, min_operation, max_operation]): 13 | """ 14 | Builds a segment tree based on the provided `array`. Supports operations 15 | of class Operation provided in the operations array. 16 | """ 17 | self.array = array 18 | if type(operations) != list: 19 | raise TypeError("operations must be a list") 20 | self.operations = {} 21 | for op in operations: 22 | self.operations[op.name] = op 23 | self.root = SegmentTreeNode(0, len(array) - 1, self) 24 | 25 | def query(self, start, end, operation_name): 26 | """ 27 | Returns the result of the operation execution with `operation_name` 28 | on the range from [start, end] 29 | """ 30 | if self.operations.get(operation_name) == None: 31 | raise Exception("This operation is not available") 32 | return self.root._query(start, end, self.operations[operation_name]) 33 | 34 | def summary(self): 35 | """ 36 | Prints the summary for the whole array (values in the root node). 37 | """ 38 | return self.root.values 39 | 40 | def update(self, position, value): 41 | """ 42 | Updates an old value at `position` to a new `value`. 43 | """ 44 | self.root._update(position, value) 45 | 46 | def update_range(self, start, end, value): 47 | """ 48 | Updates old values old in the range [start, end], inclusively, to a new value. 49 | """ 50 | self.root._update_range(start, end, value) 51 | 52 | def __repr__(self): 53 | return self.root.__repr__() 54 | 55 | 56 | class SegmentTreeNode: 57 | """ 58 | Internal SegmentTreeNode class represents a node of a segment tree. Each node 59 | stores the reference to the left and the right bound of a segment this 60 | node is responsible for. 61 | """ 62 | 63 | def __init__(self, start, end, segment_tree): 64 | self.range = (start, end) 65 | self.parent_tree = segment_tree 66 | self.range_value = None 67 | self.values = {} 68 | self.left = None 69 | self.right = None 70 | if start == end: 71 | self._sync() 72 | return 73 | self.left = SegmentTreeNode(start, start + (end - start) // 2, 74 | segment_tree) 75 | self.right = SegmentTreeNode(start + (end - start) // 2 + 1, end, 76 | segment_tree) 77 | self._sync() 78 | 79 | def _query(self, start, end, operation): 80 | if end < self.range[0] or start > self.range[1]: 81 | return None 82 | if start <= self.range[0] and self.range[1] <= end: 83 | return self.values[operation.name] 84 | self._push() 85 | left_res = self.left._query(start, end, 86 | operation) if self.left else None 87 | right_res = self.right._query(start, end, 88 | operation) if self.right else None 89 | if left_res is None: 90 | return right_res 91 | if right_res is None: 92 | return left_res 93 | return operation.f([left_res, right_res]) 94 | 95 | def _update(self, position, value): 96 | if position < self.range[0] or position > self.range[1]: 97 | return 98 | if position == self.range[0] and self.range[1] == position: 99 | self.parent_tree.array[position] = value 100 | self._sync() 101 | return 102 | self._push() 103 | self.left._update(position, value) 104 | self.right._update(position, value) 105 | self._sync() 106 | 107 | def _update_range(self, start, end, value): 108 | if end < self.range[0] or start > self.range[1]: 109 | return 110 | if start <= self.range[0] and self.range[1] <= end: 111 | self.range_value = value 112 | self._sync() 113 | return 114 | self._push() 115 | self.left._update_range(start, end, value) 116 | self.right._update_range(start, end, value) 117 | self._sync() 118 | 119 | def _sync(self): 120 | if self.range[0] == self.range[1]: 121 | for op in self.parent_tree.operations.values(): 122 | current_value = self.parent_tree.array[self.range[0]] 123 | if self.range_value is not None: 124 | current_value = self.range_value 125 | self.values[op.name] = op.f([current_value]) 126 | else: 127 | for op in self.parent_tree.operations.values(): 128 | result = op.f( 129 | [self.left.values[op.name], self.right.values[op.name]]) 130 | if self.range_value is not None: 131 | bound_length = self.range[1] - self.range[0] + 1 132 | result = op.f_on_equal(self.range_value, bound_length) 133 | self.values[op.name] = result 134 | 135 | def _push(self): 136 | if self.range_value is None: 137 | return 138 | if self.left: 139 | self.left.range_value = self.range_value 140 | self.right.range_value = self.range_value 141 | self.left._sync() 142 | self.right._sync() 143 | self.range_value = None 144 | 145 | def __repr__(self): 146 | ans = "({}, {}): {}\n".format(self.range[0], self.range[1], 147 | self.values) 148 | if self.left: 149 | ans += self.left.__repr__() 150 | if self.right: 151 | ans += self.right.__repr__() 152 | return ans 153 | --------------------------------------------------------------------------------