diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 333f6a17d..000000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text=auto \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 6a59e91bf..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: Bug -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior (be sure to include the exact command phrase you are using): -1. Go to '...' -2. Say '...' -3. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**System:** - - OS: [e.g. iOS] - - Program: [e.g. chrome, eclipse, atom] - - Version: [e.g. 22] diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index bbcbbe7d6..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index eb5722e66..000000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: Ask a question -about: The issue tracker is not for questions. If you have a question, please feel - free to ask it on our community chat, at https://gitter.im/dictation-toolbox/Caster. -title: '' -labels: '' -assignees: '' - ---- - -The issue tracker is not for questions. If you have a question, please feel free to ask it on our community chat, at https://gitter.im/dictation-toolbox/Caster. diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 74b2757e3..000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,17 +0,0 @@ -version: 2 -updates: -- package-ecosystem: pip - directory: "/" - schedule: - interval: daily - time: "00:00" - timezone: America/Chicago - open-pull-requests-limit: 10 - labels: - - 'dependencies' - commit-message: - prefix: 'deps' - ignore: - - dependency-name: "pyvda*" - - dependency-name: "wxpython*" - - dependency-name: "regex*" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 325d2989b..000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,61 +0,0 @@ -# Title - - - -## Description - - - -## Related Issue - - - -## Motivation and Context - - - -## How Has This Been Tested - - - - - -## Types of changes - - - - -- [ ] Docs change / refactoring / dependency upgrade -- [ ] Bug fix (non-breaking change which fixes an issue or bug) -- [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to change) -- [ ] Renamed existing command phrases (we discourage this without a strong rationale). - -## Checklist - - - - - - - - - -- [ ] I have read the CONTRIBUTING document. -- [ ] My code follows the code style of this project. -- [ ] I have checked that my code does not duplicate functionality elsewhere in Caster. -- [ ] I have checked for and utilized existing command phrases from within Caster (delete if not applicable). -- [ ] My code implements all the features I wish to merge in this pull request. -- [ ] My change requires a change to the documentation. -- [ ] I have updated the documentation accordingly. -- [ ] I have added tests to cover my changes. -- [ ] All new and existing tests pass. - -## Maintainer/Reviewer Checklist - - - - -- [ ] Basic functionality has been tested and works as claimed. -- [ ] New documentation is clear and complete. -- [ ] Code is clear and readable. diff --git a/.github/workflows/testrunner.yml b/.github/workflows/testrunner.yml deleted file mode 100644 index 9dc002a91..000000000 --- a/.github/workflows/testrunner.yml +++ /dev/null @@ -1,85 +0,0 @@ -name: Caster Lint/Unit Tests - -on: [push, pull_request] - -jobs: - python-windows-3-10-x: - name: python 3 windows - runs-on: windows-latest - strategy: - matrix: - python-version: [3.10.x] - steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install --upgrade setuptools - pip install wheel - pip install -U -r requirements-dev.txt - - name: Lint with pylint - run: | - pylint -E _caster.py - pylint -E castervoice - - name: Unit Tests Via Testrunner - run: | - python tests/testrunner.py - - python-linux-3-10-x: - name: python 3 linux - runs-on: ubuntu-latest - strategy: - matrix: - python-version: [3.10.x] - steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install libgtk-3-dev - sudo apt-get install python3-tk - python -m pip install --upgrade pip - pip install --upgrade setuptools - pip install wheel - pip install -U -r requirements-mac-linux.txt - - name: Lint with pylint - run: | - pylint -E _caster.py - pylint -E castervoice - - name: Unit Tests Via Testrunner - run: | - python tests/testrunner.py - - python-macos-3-10-x: - name: python 3 MacOs - runs-on: macos-latest - strategy: - matrix: - python-version: [3.10.x] - steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install --upgrade setuptools - pip install wheel - pip install -U -r requirements-mac-linux.txt - - name: Lint with pylint - run: | - pylint -E _caster.py - pylint -E castervoice - - name: Unit Tests Via Testrunner - run: | - python tests/testrunner.py diff --git a/.github_changelog_generator b/.github_changelog_generator deleted file mode 100644 index 41dd979c6..000000000 --- a/.github_changelog_generator +++ /dev/null @@ -1,6 +0,0 @@ -date-format="%Y-%m-%d" -output=CHANGELOG.md -future-release=0.6.14 -unreleased=true -exclude-labels=Duplicate,Question,Invalid,Will Not Fix or Implement,release,Known Limitation,Changes Requested,Community Feedback,[WIP] Code Blocked,[WIP],Suggestion -enhancement_labels=>Enhancement, Feature \ No newline at end of file diff --git a/.gitignore b/.gitignore deleted file mode 100644 index edbe43f85..000000000 --- a/.gitignore +++ /dev/null @@ -1,55 +0,0 @@ -# Ignore junk -.idea/ -*.pyc -*.toml -*.wav -*.class -test.py -log.txt -complexity_report* -*.log -*.*\# -*.*~ -*.aux -*.synctex.gz -_test/ -test_user_dir - -# Ignore Rope -.ropeproject/ - -# Ignoring Visual Studio (Code) -.vs/ -.vscode/ - -# Ignore Natlink -/core/ - -# Ignore SonarQube -.sonar -sonar-project.properties - -# Ignore Eclipse/Pydev Files -.project -.pydevproject -.settings - -# Ignore dist files -dist -build/ -castervoice.egg-info -/.stignore - -# Ignore Notepad++ backup files -**/nppBackup -*.bak - -# Speech recognition models -kaldi_model* - -# Ignore virtual -venv* - -# Dragonfly module loaders -kaldi_module_loader_plus.py -kaldi_module_loader.py diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index bcda3d499..000000000 --- a/.pylintrc +++ /dev/null @@ -1,10 +0,0 @@ -[TYPECHECK] -generated-members=pythoncom.*,wx.* -ignored-modules=natlink,natlinkstatus - -[MASTER] -extension-pkg-whitelist=pythoncom,wx,pydevd,win32gui,PySide2 - -[MESSAGES CONTROL] -disable=all -enable=E \ No newline at end of file diff --git a/.style.yapf b/.style.yapf deleted file mode 100644 index 025bd206d..000000000 --- a/.style.yapf +++ /dev/null @@ -1,6 +0,0 @@ -[style] -based_on_style=pep8 -column_limit=90 -indent_dictionary_value=True -split_complex_comprehension=True -no_spaces_around_selected_binary_operators=*,/ diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index d4572f0f0..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,458 +0,0 @@ -# Changelog - -## [0.6.14](https://github.com/dictation-toolbox/Caster/tree/0.6.14) ("2019-12-01") - -[Full Changelog](https://github.com/dictation-toolbox/Caster/compare/0.5.11...0.6.14) - -**Fixed bugs:** - -- Syntax error still breaks everything \(actually breaks more stuff than before\) [\#684](https://github.com/dictation-toolbox/Caster/issues/684) -- Store and Retrieve - OpenClipboard: Access denied [\#657](https://github.com/dictation-toolbox/Caster/issues/657) -- Basic mouse commands don't work with Aenea support [\#634](https://github.com/dictation-toolbox/Caster/issues/634) -- dll files stay loaded when not in use. [\#627](https://github.com/dictation-toolbox/Caster/issues/627) -- file to bring me as name not working [\#575](https://github.com/dictation-toolbox/Caster/issues/575) -- Caster Crashes On Load When Engine Is Not Defined In Settings.toml [\#569](https://github.com/dictation-toolbox/Caster/issues/569) -- Record from history doesn't work with non-ascii characters [\#546](https://github.com/dictation-toolbox/Caster/issues/546) -- HTML elements not written properly in Jetbrains IDE [\#541](https://github.com/dictation-toolbox/Caster/issues/541) -- Voice dev commands "commander" function buggy in Notepad++ [\#531](https://github.com/dictation-toolbox/Caster/issues/531) -- "website/folder to bring me as \" doesn't seem to be working [\#528](https://github.com/dictation-toolbox/Caster/issues/528) -- File Explorer doesn't always appear in foreground [\#527](https://github.com/dictation-toolbox/Caster/issues/527) -- macro "times" command to repeat macros doesn't work [\#526](https://github.com/dictation-toolbox/Caster/issues/526) -- Caster fails on startup: KeyError: 'PROCESSOR\_ARCHITEW6432' [\#516](https://github.com/dictation-toolbox/Caster/issues/516) -- Userspace rules don't work after changing profile [\#508](https://github.com/dictation-toolbox/Caster/issues/508) -- Douglas grid and curse \ not working on Win 7 virtualbox [\#507](https://github.com/dictation-toolbox/Caster/issues/507) -- Legion not working correctly on second monitor [\#502](https://github.com/dictation-toolbox/Caster/issues/502) -- Legion not coming up in the foreground [\#500](https://github.com/dictation-toolbox/Caster/issues/500) -- WXPYTHON\_PATH and PYTHONW aren't set correctly [\#486](https://github.com/dictation-toolbox/Caster/issues/486) -- Sikuli's control commands aren't recognized [\#468](https://github.com/dictation-toolbox/Caster/issues/468) -- Rule Filters Simplified don't work for MappingRules [\#466](https://github.com/dictation-toolbox/Caster/issues/466) -- Outlook: Invalid key name: 'esc' [\#457](https://github.com/dictation-toolbox/Caster/issues/457) -- Complexity test: Filter function 'spec\_override\_from\_config' failed. [\#442](https://github.com/dictation-toolbox/Caster/issues/442) -- Unittest: Failed TestMergeRule TypeError [\#439](https://github.com/dictation-toolbox/Caster/issues/439) -- ReadTheDocs is broken [\#431](https://github.com/dictation-toolbox/Caster/issues/431) -- Post install script handle \_caster incorrectly in some cases. [\#414](https://github.com/dictation-toolbox/Caster/issues/414) -- bringme.toml is blank on new installations of caster [\#400](https://github.com/dictation-toolbox/Caster/issues/400) -- Userspace rules are not merged. [\#399](https://github.com/dictation-toolbox/Caster/issues/399) -- CasterVoice PIP package fails to install: \[Errno 2\] No such file [\#381](https://github.com/dictation-toolbox/Caster/issues/381) -- Invalid links due to directory name change [\#379](https://github.com/dictation-toolbox/Caster/issues/379) -- Bugs in handling non-ASCII characters in clipboard over restarts [\#357](https://github.com/dictation-toolbox/Caster/issues/357) -- AppContext drops off when in save/open dialog boxes in RStudio [\#349](https://github.com/dictation-toolbox/Caster/issues/349) -- Caster GUI settings window does not launch [\#327](https://github.com/dictation-toolbox/Caster/issues/327) -- Caster fails to load with windows speech recognition engine [\#305](https://github.com/dictation-toolbox/Caster/issues/305) -- Removed duplicate dependency in .bat file [\#295](https://github.com/dictation-toolbox/Caster/issues/295) -- The 'chain alias' command is nonfunctional [\#279](https://github.com/dictation-toolbox/Caster/issues/279) -- The 'record from history' command does not execute. [\#272](https://github.com/dictation-toolbox/Caster/issues/272) -- Correctly merge contexted MergeRules [\#163](https://github.com/dictation-toolbox/Caster/issues/163) -- Workspace fix for 1903 + kaldi compatibility [\#683](https://github.com/dictation-toolbox/Caster/pull/683) ([mrob95](https://github.com/mrob95)) -- Implements tomlkit in place of toml dependency [\#676](https://github.com/dictation-toolbox/Caster/pull/676) ([LexiconCode](https://github.com/LexiconCode)) -- Find pip cross platform without environment variable [\#674](https://github.com/dictation-toolbox/Caster/pull/674) ([LexiconCode](https://github.com/LexiconCode)) -- Sets user directory with Permissions check with fallback location [\#673](https://github.com/dictation-toolbox/Caster/pull/673) ([LexiconCode](https://github.com/LexiconCode)) -- Allow Unicode characters in history [\#671](https://github.com/dictation-toolbox/Caster/pull/671) ([comodoro](https://github.com/comodoro)) -- Added Clipboard read\write retry attempts on failure [\#665](https://github.com/dictation-toolbox/Caster/pull/665) ([LexiconCode](https://github.com/LexiconCode)) -- add back sauce/dunce wally [\#662](https://github.com/dictation-toolbox/Caster/pull/662) ([alexboche](https://github.com/alexboche)) -- Add refresh method to mock ChainAlias and use test discovery on Travis [\#661](https://github.com/dictation-toolbox/Caster/pull/661) ([comodoro](https://github.com/comodoro)) -- Import from lib.imports in browser grammars [\#654](https://github.com/dictation-toolbox/Caster/pull/654) ([brxck](https://github.com/brxck)) -- Changed output of Retrieve\(\) from Text to dragonfly Paste action [\#652](https://github.com/dictation-toolbox/Caster/pull/652) ([LexiconCode](https://github.com/LexiconCode)) -- Simplify Caster mouse functions and use the Mouse action instead [\#635](https://github.com/dictation-toolbox/Caster/pull/635) ([Danesprite](https://github.com/Danesprite)) -- Removed the shadowed dragon format command and added updated dra… [\#622](https://github.com/dictation-toolbox/Caster/pull/622) ([LexiconCode](https://github.com/LexiconCode)) -- Fixed installtype function [\#611](https://github.com/dictation-toolbox/Caster/pull/611) ([LexiconCode](https://github.com/LexiconCode)) -- Fixed Selfmodrule filter bug [\#608](https://github.com/dictation-toolbox/Caster/pull/608) ([mrob95](https://github.com/mrob95)) -- Fixes the record from history "\[times \\]" command repeat macros [\#607](https://github.com/dictation-toolbox/Caster/pull/607) ([LexiconCode](https://github.com/LexiconCode)) -- Major app rules clean up [\#604](https://github.com/dictation-toolbox/Caster/pull/604) ([mrob95](https://github.com/mrob95)) -- fix Windows Explorer file dialogue navigation commands [\#475](https://github.com/dictation-toolbox/Caster/pull/475) ([alexboche](https://github.com/alexboche)) - -**Deprecated:** - -- Remove Click-By-Voice chrome helper functions in chrome.py [\#495](https://github.com/dictation-toolbox/Caster/issues/495) - -**Closed issues:** - -- Attempt transformers safely [\#695](https://github.com/dictation-toolbox/Caster/issues/695) -- Caster License needs to be updated references for Non-Original Code. [\#690](https://github.com/dictation-toolbox/Caster/issues/690) -- Discussion on managing Global State in Caster. [\#646](https://github.com/dictation-toolbox/Caster/issues/646) -- Remove current gh-pages and build GitHub Pages from /docs folder [\#632](https://github.com/dictation-toolbox/Caster/issues/632) -- Disable Wiki on Caster repository. [\#631](https://github.com/dictation-toolbox/Caster/issues/631) -- Utilize github release model and remove development branch. [\#617](https://github.com/dictation-toolbox/Caster/issues/617) -- Add Code of Conduct [\#603](https://github.com/dictation-toolbox/Caster/issues/603) -- Accepting donations to fund bounty [\#591](https://github.com/dictation-toolbox/Caster/issues/591) -- Add code to check for required dragonfly version [\#568](https://github.com/dictation-toolbox/Caster/issues/568) -- Move all long extras lists to tomls [\#566](https://github.com/dictation-toolbox/Caster/issues/566) -- Edit on github on RTD lands in the wrong place [\#565](https://github.com/dictation-toolbox/Caster/issues/565) -- Update some engine-specific code [\#554](https://github.com/dictation-toolbox/Caster/issues/554) -- windows speech recognition stop listening command does not work [\#549](https://github.com/dictation-toolbox/Caster/issues/549) -- \>= and \<= sometimes don't work [\#547](https://github.com/dictation-toolbox/Caster/issues/547) -- Caster fails on startup with SystemError: Your platform is not currently supported by Caster [\#536](https://github.com/dictation-toolbox/Caster/issues/536) -- Consider using ShortIntegerRef in caster [\#535](https://github.com/dictation-toolbox/Caster/issues/535) -- Grammar documentation template [\#532](https://github.com/dictation-toolbox/Caster/issues/532) -- Add terminal folders to bring me [\#529](https://github.com/dictation-toolbox/Caster/issues/529) -- future should be in the dependencies for caster [\#517](https://github.com/dictation-toolbox/Caster/issues/517) -- Inconsistent behaviour with carrot [\#512](https://github.com/dictation-toolbox/Caster/issues/512) -- Make bow/bowel optional [\#510](https://github.com/dictation-toolbox/Caster/issues/510) -- Refresh caster without rebooting Dragon [\#509](https://github.com/dictation-toolbox/Caster/issues/509) -- words.txt doesn't work for alphabet [\#506](https://github.com/dictation-toolbox/Caster/issues/506) -- "duple" working inconsistently [\#505](https://github.com/dictation-toolbox/Caster/issues/505) -- GitBash grammar: @ and { not working in mingw64 terminal [\#504](https://github.com/dictation-toolbox/Caster/issues/504) -- Helper function to checkout a branch on github from a web browser [\#494](https://github.com/dictation-toolbox/Caster/issues/494) -- jump and butt with quotes: " and ' [\#488](https://github.com/dictation-toolbox/Caster/issues/488) -- Repeats with jump and butt commands [\#487](https://github.com/dictation-toolbox/Caster/issues/487) -- Where is the xmlrpc server started? [\#471](https://github.com/dictation-toolbox/Caster/issues/471) -- Sikuli doesn't work after switching between profiles [\#463](https://github.com/dictation-toolbox/Caster/issues/463) -- Image file missing in documentation [\#460](https://github.com/dictation-toolbox/Caster/issues/460) -- odd error trying to get Sikuli to work on a new computer [\#455](https://github.com/dictation-toolbox/Caster/issues/455) -- Using "kick" after sikuli click follows the [\#446](https://github.com/dictation-toolbox/Caster/issues/446) -- python 3 [\#390](https://github.com/dictation-toolbox/Caster/issues/390) -- Post install script for setup.py to install \_caster.py [\#388](https://github.com/dictation-toolbox/Caster/issues/388) -- User folder disappeared [\#383](https://github.com/dictation-toolbox/Caster/issues/383) -- Caster as a Package: Master Thread [\#382](https://github.com/dictation-toolbox/Caster/issues/382) -- Move configdebug.txt file to user space [\#378](https://github.com/dictation-toolbox/Caster/issues/378) -- Utilize underscores instead of white spaces for .md for filenames. [\#376](https://github.com/dictation-toolbox/Caster/issues/376) -- Not includ version number in CasterQuickReference0.5.8.pdf file name. [\#375](https://github.com/dictation-toolbox/Caster/issues/375) -- Enhancements to chain alias and alias command [\#358](https://github.com/dictation-toolbox/Caster/issues/358) -- Concise interface to modify "Choice" lists [\#355](https://github.com/dictation-toolbox/Caster/issues/355) -- Universal file dialog interface? [\#348](https://github.com/dictation-toolbox/Caster/issues/348) -- Change imports to support Aenea [\#345](https://github.com/dictation-toolbox/Caster/issues/345) -- Is it possible to replace phrases using words.txt? [\#341](https://github.com/dictation-toolbox/Caster/issues/341) -- BringMe path ends in .toml.defaults instead of .toml [\#338](https://github.com/dictation-toolbox/Caster/issues/338) -- Update rdescript in CCR Caster commands with an identifier [\#331](https://github.com/dictation-toolbox/Caster/issues/331) -- Consider making the commands in gitbash.py safer? [\#330](https://github.com/dictation-toolbox/Caster/issues/330) -- Implement Sort keys when saving Toml files. [\#323](https://github.com/dictation-toolbox/Caster/issues/323) -- Migrating Caster project into an Organization [\#321](https://github.com/dictation-toolbox/Caster/issues/321) -- Partial Aenea + Caster support [\#312](https://github.com/dictation-toolbox/Caster/issues/312) -- Handling Caster dependencies updates. [\#309](https://github.com/dictation-toolbox/Caster/issues/309) -- Convert extensions from .MD to .md documentation markdown files. [\#307](https://github.com/dictation-toolbox/Caster/issues/307) -- Alternative approaches managing settings for 'alias'/'chain alias' and 'record from history' spec [\#302](https://github.com/dictation-toolbox/Caster/issues/302) -- Mirror Casters github repository for redundancy [\#300](https://github.com/dictation-toolbox/Caster/issues/300) -- Update Caster's Github Pages [\#294](https://github.com/dictation-toolbox/Caster/issues/294) -- Replace .docx with LaTeX for Caster\_quick\_reference [\#288](https://github.com/dictation-toolbox/Caster/issues/288) -- Filter Rules replacing a spec [\#280](https://github.com/dictation-toolbox/Caster/issues/280) -- Update Voice Index [\#275](https://github.com/dictation-toolbox/Caster/issues/275) -- Apply Formatting Commands to text in system clipboard buffer. [\#267](https://github.com/dictation-toolbox/Caster/issues/267) -- Add secondary format and default format to language rules [\#255](https://github.com/dictation-toolbox/Caster/issues/255) -- Utilizing new format instead of json for Caster settings file. [\#247](https://github.com/dictation-toolbox/Caster/issues/247) -- Redesign of Registered Actions with additional properties [\#235](https://github.com/dictation-toolbox/Caster/issues/235) -- Simplify installing Caster. [\#217](https://github.com/dictation-toolbox/Caster/issues/217) -- Consolidating command phrases from applications into core CCR and Application Core [\#211](https://github.com/dictation-toolbox/Caster/issues/211) -- Update Caster Sikuli integration to the latest version of Sikuli [\#203](https://github.com/dictation-toolbox/Caster/issues/203) -- Feature suggestion: allow for different phrasing of numbers [\#174](https://github.com/dictation-toolbox/Caster/issues/174) -- Feature suggestion: bringme [\#173](https://github.com/dictation-toolbox/Caster/issues/173) -- Additional Line Ops [\#133](https://github.com/dictation-toolbox/Caster/issues/133) -- update docs [\#131](https://github.com/dictation-toolbox/Caster/issues/131) -- Improve application context detection [\#106](https://github.com/dictation-toolbox/Caster/issues/106) -- Reduce or eliminate delays associated with AsynchronousAction [\#105](https://github.com/dictation-toolbox/Caster/issues/105) -- Rainbow command to select a grid on the screen [\#80](https://github.com/dictation-toolbox/Caster/issues/80) -- A generic method to reboot voice recognition backend. [\#77](https://github.com/dictation-toolbox/Caster/issues/77) - -**Merged pull requests:** - -- remove unneeded itertools import \(trivial\) [\#682](https://github.com/dictation-toolbox/Caster/pull/682) ([alexboche](https://github.com/alexboche)) -- Remove settings as a hard dependency for Dependency.py [\#681](https://github.com/dictation-toolbox/Caster/pull/681) ([LexiconCode](https://github.com/LexiconCode)) -- \# Switch mouse commands to use standard cancel phrase [\#675](https://github.com/dictation-toolbox/Caster/pull/675) ([kendonB](https://github.com/kendonB)) -- add longhand punctuation names [\#668](https://github.com/dictation-toolbox/Caster/pull/668) ([alexboche](https://github.com/alexboche)) -- Lexicon Optimizations [\#664](https://github.com/dictation-toolbox/Caster/pull/664) ([LexiconCode](https://github.com/LexiconCode)) -- Use testrunner for Travis [\#663](https://github.com/dictation-toolbox/Caster/pull/663) ([comodoro](https://github.com/comodoro)) -- Update selfmodrule.py [\#660](https://github.com/dictation-toolbox/Caster/pull/660) ([comodoro](https://github.com/comodoro)) -- fird -\> firch [\#659](https://github.com/dictation-toolbox/Caster/pull/659) ([alexboche](https://github.com/alexboche)) -- MarkDown CCR: Added store and retrieve [\#656](https://github.com/dictation-toolbox/Caster/pull/656) ([LexiconCode](https://github.com/LexiconCode)) -- Added Python CCR store and retrieve features [\#655](https://github.com/dictation-toolbox/Caster/pull/655) ([LexiconCode](https://github.com/LexiconCode)) -- Added store and retrieve to gitter [\#651](https://github.com/dictation-toolbox/Caster/pull/651) ([LexiconCode](https://github.com/LexiconCode)) -- Add back command descriptions and add pause time for "train word" command [\#648](https://github.com/dictation-toolbox/Caster/pull/648) ([alexboche](https://github.com/alexboche)) -- add grammar documentation template [\#645](https://github.com/dictation-toolbox/Caster/pull/645) ([kendonB](https://github.com/kendonB)) -- Bring me docs [\#644](https://github.com/dictation-toolbox/Caster/pull/644) ([kendonB](https://github.com/kendonB)) -- Remove unnecessary WSR-specific code [\#643](https://github.com/dictation-toolbox/Caster/pull/643) ([Danesprite](https://github.com/Danesprite)) -- Make tests discoverable and not check for updates [\#642](https://github.com/dictation-toolbox/Caster/pull/642) ([comodoro](https://github.com/comodoro)) -- fix voice\_dev\_commands [\#641](https://github.com/dictation-toolbox/Caster/pull/641) ([kendonB](https://github.com/kendonB)) -- fixed punctuation [\#640](https://github.com/dictation-toolbox/Caster/pull/640) ([kendonB](https://github.com/kendonB)) -- Bring me for files and folders [\#637](https://github.com/dictation-toolbox/Caster/pull/637) ([comodoro](https://github.com/comodoro)) -- Add integers 1-3 to kick [\#636](https://github.com/dictation-toolbox/Caster/pull/636) ([kendonB](https://github.com/kendonB)) -- add pr template [\#633](https://github.com/dictation-toolbox/Caster/pull/633) ([kendonB](https://github.com/kendonB)) -- add a getting started page [\#628](https://github.com/dictation-toolbox/Caster/pull/628) ([kendonB](https://github.com/kendonB)) -- Load word.txt from .caster\filters and documentation update [\#626](https://github.com/dictation-toolbox/Caster/pull/626) ([LexiconCode](https://github.com/LexiconCode)) -- Create issue templates [\#621](https://github.com/dictation-toolbox/Caster/pull/621) ([kendonB](https://github.com/kendonB)) -- Create CODE\_OF\_CONDUCT.md [\#620](https://github.com/dictation-toolbox/Caster/pull/620) ([kendonB](https://github.com/kendonB)) -- Added example rules and filters to user directory [\#619](https://github.com/dictation-toolbox/Caster/pull/619) ([LexiconCode](https://github.com/LexiconCode)) -- Add automatic installation script for classic install [\#618](https://github.com/dictation-toolbox/Caster/pull/618) ([mrob95](https://github.com/mrob95)) -- Bring me updates [\#614](https://github.com/dictation-toolbox/Caster/pull/614) ([mrob95](https://github.com/mrob95)) -- App settings removed in settings.py [\#613](https://github.com/dictation-toolbox/Caster/pull/613) ([LexiconCode](https://github.com/LexiconCode)) -- Classic install: Enhancements to check dependencies for required versions and missing dependencies. [\#610](https://github.com/dictation-toolbox/Caster/pull/610) ([LexiconCode](https://github.com/LexiconCode)) -- Improve rule naming in rdescripts [\#606](https://github.com/dictation-toolbox/Caster/pull/606) ([mrob95](https://github.com/mrob95)) -- Further tidying of rule loading [\#605](https://github.com/dictation-toolbox/Caster/pull/605) ([mrob95](https://github.com/mrob95)) -- new legion dll [\#602](https://github.com/dictation-toolbox/Caster/pull/602) ([kendonB](https://github.com/kendonB)) -- add sequences of characters for the move commands only [\#601](https://github.com/dictation-toolbox/Caster/pull/601) ([alexboche](https://github.com/alexboche)) -- Documentation for new rule loading functions [\#600](https://github.com/dictation-toolbox/Caster/pull/600) ([mrob95](https://github.com/mrob95)) -- Minimum version checking for dragonfly. [\#599](https://github.com/dictation-toolbox/Caster/pull/599) ([LexiconCode](https://github.com/LexiconCode)) -- Rule loading functions in control.py [\#596](https://github.com/dictation-toolbox/Caster/pull/596) ([mrob95](https://github.com/mrob95)) -- Revert "add CCR rule to Chrome " [\#595](https://github.com/dictation-toolbox/Caster/pull/595) ([mrob95](https://github.com/mrob95)) -- Add tell commands for all punctuation [\#593](https://github.com/dictation-toolbox/Caster/pull/593) ([alexboche](https://github.com/alexboche)) -- Add imports.py to reduce boilerplate [\#590](https://github.com/dictation-toolbox/Caster/pull/590) ([mrob95](https://github.com/mrob95)) -- add support for the 10 digits for text manipulation [\#588](https://github.com/dictation-toolbox/Caster/pull/588) ([alexboche](https://github.com/alexboche)) -- Modifier keys [\#585](https://github.com/dictation-toolbox/Caster/pull/585) ([alexboche](https://github.com/alexboche)) -- fix file name [\#583](https://github.com/dictation-toolbox/Caster/pull/583) ([kendonB](https://github.com/kendonB)) -- Revert clipboard to use json [\#582](https://github.com/dictation-toolbox/Caster/pull/582) ([comodoro](https://github.com/comodoro)) -- mention Emacs is not supported2 [\#581](https://github.com/dictation-toolbox/Caster/pull/581) ([alexboche](https://github.com/alexboche)) -- Use Dragonfly's new timers and update Sikuli code [\#577](https://github.com/dictation-toolbox/Caster/pull/577) ([comodoro](https://github.com/comodoro)) -- add CCR rule to Chrome [\#571](https://github.com/dictation-toolbox/Caster/pull/571) ([alexboche](https://github.com/alexboche)) -- add new commands to dragon.py [\#559](https://github.com/dictation-toolbox/Caster/pull/559) ([alexboche](https://github.com/alexboche)) -- Select text using douglas, rainbow, and legion [\#501](https://github.com/dictation-toolbox/Caster/pull/501) ([seekM](https://github.com/seekM)) -- tweak a couple commands in VS code [\#477](https://github.com/dictation-toolbox/Caster/pull/477) ([alexboche](https://github.com/alexboche)) - -## [0.5.11](https://github.com/dictation-toolbox/Caster/tree/0.5.11) ("2018-10-15") - -[Full Changelog](https://github.com/dictation-toolbox/Caster/compare/0.5.10...0.5.11) - -**Fixed bugs:** - -- \_find\_natspeak\(\) function fails with AttributeError: winmgmts:.Win32\_Product on some machines. [\#248](https://github.com/dictation-toolbox/Caster/issues/248) -- Alias Commands are nonfunctional [\#244](https://github.com/dictation-toolbox/Caster/issues/244) -- UnicodeDecodeError when utilizing filter rules. [\#236](https://github.com/dictation-toolbox/Caster/issues/236) -- Import Tolerance - Failure importing natlink module in dragonflys timer.py [\#224](https://github.com/dictation-toolbox/Caster/issues/224) -- For people having issues with the grid system \(Legion, Douglas, Rainbow\) [\#194](https://github.com/dictation-toolbox/Caster/issues/194) -- Legion grid is sometimes inaccurate [\#172](https://github.com/dictation-toolbox/Caster/issues/172) -- Alias fix [\#245](https://github.com/dictation-toolbox/Caster/pull/245) ([BazookaMusic](https://github.com/BazookaMusic)) -- Legion DPI fix [\#223](https://github.com/dictation-toolbox/Caster/pull/223) ([BazookaMusic](https://github.com/BazookaMusic)) -- LoadLibrary path fix [\#222](https://github.com/dictation-toolbox/Caster/pull/222) ([Versatilus](https://github.com/Versatilus)) - -**Closed issues:** - -- Comments in rule filter files [\#265](https://github.com/dictation-toolbox/Caster/issues/265) -- Enhance settings.py to account for alternate DNS install locations and DNS versions. [\#242](https://github.com/dictation-toolbox/Caster/issues/242) -- Error when attempting to run [\#238](https://github.com/dictation-toolbox/Caster/issues/238) -- Python code pauses execution while waiting for Natlink [\#228](https://github.com/dictation-toolbox/Caster/issues/228) -- Natlink Installation [\#226](https://github.com/dictation-toolbox/Caster/issues/226) -- Free Dictation intermittently not recognized within applications? [\#221](https://github.com/dictation-toolbox/Caster/issues/221) -- Caster Rest API Framework [\#198](https://github.com/dictation-toolbox/Caster/issues/198) -- Proposal: Maintain coding style through yapf. [\#197](https://github.com/dictation-toolbox/Caster/issues/197) -- Sikuli setup error [\#185](https://github.com/dictation-toolbox/Caster/issues/185) -- Legion breakdown [\#126](https://github.com/dictation-toolbox/Caster/issues/126) - -**Merged pull requests:** - -- Added a LaTeX ccr module [\#277](https://github.com/dictation-toolbox/Caster/pull/277) ([mrob95](https://github.com/mrob95)) -- Reworked CodeBase to reflect simplified alias command. [\#270](https://github.com/dictation-toolbox/Caster/pull/270) ([LexiconCode](https://github.com/LexiconCode)) -- Documented python comments are supported in rule filter files \#265. [\#268](https://github.com/dictation-toolbox/Caster/pull/268) ([LexiconCode](https://github.com/LexiconCode)) -- Add Total Commander rule [\#266](https://github.com/dictation-toolbox/Caster/pull/266) ([comodoro](https://github.com/comodoro)) -- Caster clipboard commands preserve system clipboard [\#261](https://github.com/dictation-toolbox/Caster/pull/261) ([mrob95](https://github.com/mrob95)) -- Applications quick reference [\#259](https://github.com/dictation-toolbox/Caster/pull/259) ([mrob95](https://github.com/mrob95)) -- Add RStudio support [\#258](https://github.com/dictation-toolbox/Caster/pull/258) ([mrob95](https://github.com/mrob95)) -- Enhancements to Java, Javascript, Python, Dart CCR language files and Jetbrains. [\#257](https://github.com/dictation-toolbox/Caster/pull/257) ([comodoro](https://github.com/comodoro)) -- Add a quick reference guide for the language-specific commands [\#254](https://github.com/dictation-toolbox/Caster/pull/254) ([mrob95](https://github.com/mrob95)) -- Make the SQL module output in caps. [\#253](https://github.com/dictation-toolbox/Caster/pull/253) ([mrob95](https://github.com/mrob95)) -- Reimplementation methods to find DNS path via the registry [\#252](https://github.com/dictation-toolbox/Caster/pull/252) ([LexiconCode](https://github.com/LexiconCode)) -- Slight quick reference update update [\#251](https://github.com/dictation-toolbox/Caster/pull/251) ([mrob95](https://github.com/mrob95)) -- Add \[\] to the hug function [\#250](https://github.com/dictation-toolbox/Caster/pull/250) ([mrob95](https://github.com/mrob95)) -- Update R functionality [\#249](https://github.com/dictation-toolbox/Caster/pull/249) ([mrob95](https://github.com/mrob95)) -- Detect alternate drive DNS install locations and versions \#242 [\#243](https://github.com/dictation-toolbox/Caster/pull/243) ([LexiconCode](https://github.com/LexiconCode)) -- add navigation to explorer [\#231](https://github.com/dictation-toolbox/Caster/pull/231) ([kendonB](https://github.com/kendonB)) -- Add more text spacing formats e.g. hello.world, hello/world & hello\world [\#230](https://github.com/dictation-toolbox/Caster/pull/230) ([codingApprentice](https://github.com/codingApprentice)) -- Enclose text into quotes,parens,etc. [\#229](https://github.com/dictation-toolbox/Caster/pull/229) ([BazookaMusic](https://github.com/BazookaMusic)) -- Add an initial draft of R, Matlab CCR grammars [\#227](https://github.com/dictation-toolbox/Caster/pull/227) ([shippy](https://github.com/shippy)) -- Legion Enhancement, Cheat sheet update, and more [\#220](https://github.com/dictation-toolbox/Caster/pull/220) ([LazoCoder](https://github.com/LazoCoder)) -- Add Import Tolerance [\#216](https://github.com/dictation-toolbox/Caster/pull/216) ([BazookaMusic](https://github.com/BazookaMusic)) - -## [0.5.10](https://github.com/dictation-toolbox/Caster/tree/0.5.10) ("2018-03-29") - -[Full Changelog](https://github.com/dictation-toolbox/Caster/compare/0.5.7...0.5.10) - -**Fixed bugs:** - -- "At sign" doesn't link with other commands [\#176](https://github.com/dictation-toolbox/Caster/issues/176) -- Legion grid doesn't always seem to focus [\#171](https://github.com/dictation-toolbox/Caster/issues/171) -- Programming core commands not working in Eclipse [\#156](https://github.com/dictation-toolbox/Caster/issues/156) -- fixes \#176 [\#210](https://github.com/dictation-toolbox/Caster/pull/210) ([kendonB](https://github.com/kendonB)) -- History fixes [\#178](https://github.com/dictation-toolbox/Caster/pull/178) ([carywalk](https://github.com/carywalk)) -- Fix "no handlers could be found for logger" error messages [\#160](https://github.com/dictation-toolbox/Caster/pull/160) ([chilimangoes](https://github.com/chilimangoes)) - -**Deprecated:** - -- cut deprecated features [\#154](https://github.com/dictation-toolbox/Caster/issues/154) -- Remove unused rule data [\#193](https://github.com/dictation-toolbox/Caster/pull/193) ([betaorbust](https://github.com/betaorbust)) - -**Closed issues:** - -- Improvement for different Words with identical pronunciation [\#200](https://github.com/dictation-toolbox/Caster/issues/200) -- What does a TokenSet \(and auto\) do? [\#192](https://github.com/dictation-toolbox/Caster/issues/192) -- Running with only WSR? [\#182](https://github.com/dictation-toolbox/Caster/issues/182) -- how does one put arbitrary text into a command? [\#169](https://github.com/dictation-toolbox/Caster/issues/169) -- Git bash commands not working [\#168](https://github.com/dictation-toolbox/Caster/issues/168) -- Text formatting is not working [\#166](https://github.com/dictation-toolbox/Caster/issues/166) -- can import dragonfly but not dragonfly.grammer [\#165](https://github.com/dictation-toolbox/Caster/issues/165) -- Remove implicit "set format" from text formatting commands [\#158](https://github.com/dictation-toolbox/Caster/issues/158) -- Rainbow Grid [\#157](https://github.com/dictation-toolbox/Caster/issues/157) -- Error during initialisation of Dragon NaturallySpeaking [\#155](https://github.com/dictation-toolbox/Caster/issues/155) -- The termination word "cancel" is already taken by Dragon [\#153](https://github.com/dictation-toolbox/Caster/issues/153) -- Where to put non-english commands? [\#149](https://github.com/dictation-toolbox/Caster/issues/149) -- Integer Remap causes crash for non-English DNS users [\#148](https://github.com/dictation-toolbox/Caster/issues/148) -- Rainbow, Douglas, etc only work on primary monitor [\#146](https://github.com/dictation-toolbox/Caster/issues/146) -- Issues with Windows 10 + DNS 14 [\#145](https://github.com/dictation-toolbox/Caster/issues/145) -- quick reference – typo [\#144](https://github.com/dictation-toolbox/Caster/issues/144) -- RDP Mode [\#143](https://github.com/dictation-toolbox/Caster/issues/143) -- Unable to load DLL for legion [\#142](https://github.com/dictation-toolbox/Caster/issues/142) -- Improvements to "tie match" and "ex match" [\#125](https://github.com/dictation-toolbox/Caster/issues/125) -- Caster settings GUI upon editing a setting but not exiting produces Errno 10061 over a period of time. [\#82](https://github.com/dictation-toolbox/Caster/issues/82) -- make fuzzy symbol searching smarter [\#49](https://github.com/dictation-toolbox/Caster/issues/49) - -**Merged pull requests:** - -- Develop [\#219](https://github.com/dictation-toolbox/Caster/pull/219) ([Versatilus](https://github.com/Versatilus)) -- Preparation for update to `master` [\#218](https://github.com/dictation-toolbox/Caster/pull/218) ([Versatilus](https://github.com/Versatilus)) -- Support for Gitter App [\#213](https://github.com/dictation-toolbox/Caster/pull/213) ([LexiconCode](https://github.com/LexiconCode)) -- Updated Atom Commands [\#212](https://github.com/dictation-toolbox/Caster/pull/212) ([LexiconCode](https://github.com/LexiconCode)) -- Unicode fixes [\#208](https://github.com/dictation-toolbox/Caster/pull/208) ([Versatilus](https://github.com/Versatilus)) -- Prolog and vhdl rules [\#207](https://github.com/dictation-toolbox/Caster/pull/207) ([BazookaMusic](https://github.com/BazookaMusic)) -- Prolog and vhdl rules [\#204](https://github.com/dictation-toolbox/Caster/pull/204) ([BazookaMusic](https://github.com/BazookaMusic)) -- Partial format [\#201](https://github.com/dictation-toolbox/Caster/pull/201) ([BazookaMusic](https://github.com/BazookaMusic)) -- Added default path for Naturally Speaking 15 [\#196](https://github.com/dictation-toolbox/Caster/pull/196) ([LexiconCode](https://github.com/LexiconCode)) -- VS Code and JavaScript CCR fixes [\#195](https://github.com/dictation-toolbox/Caster/pull/195) ([Versatilus](https://github.com/Versatilus)) -- Rework and clean up setting.py [\#191](https://github.com/dictation-toolbox/Caster/pull/191) ([betaorbust](https://github.com/betaorbust)) -- Change get\_name to get\_pronunciation to clarify what's being used. [\#190](https://github.com/dictation-toolbox/Caster/pull/190) ([betaorbust](https://github.com/betaorbust)) -- Add .gitattributes file and fix CRLF files. [\#189](https://github.com/dictation-toolbox/Caster/pull/189) ([betaorbust](https://github.com/betaorbust)) -- Remove try/except around startup. [\#188](https://github.com/dictation-toolbox/Caster/pull/188) ([betaorbust](https://github.com/betaorbust)) -- add build and test commands to Visual Studio [\#187](https://github.com/dictation-toolbox/Caster/pull/187) ([LoganGirard](https://github.com/LoganGirard)) -- fixing lambda in c sharp [\#186](https://github.com/dictation-toolbox/Caster/pull/186) ([LoganGirard](https://github.com/LoganGirard)) -- updates to Chrome keybinds [\#164](https://github.com/dictation-toolbox/Caster/pull/164) ([Versatilus](https://github.com/Versatilus)) -- context fixes [\#162](https://github.com/dictation-toolbox/Caster/pull/162) ([Versatilus](https://github.com/Versatilus)) -- Updated Atom Command Phrases [\#161](https://github.com/dictation-toolbox/Caster/pull/161) ([ghost](https://github.com/ghost)) -- Text formatting usability improvements [\#159](https://github.com/dictation-toolbox/Caster/pull/159) ([chilimangoes](https://github.com/chilimangoes)) -- Fix mouse documentation \(GitHub Flavored Markdown\) [\#150](https://github.com/dictation-toolbox/Caster/pull/150) ([seekM](https://github.com/seekM)) -- Update mouse documentation [\#147](https://github.com/dictation-toolbox/Caster/pull/147) ([seekM](https://github.com/seekM)) -- Adding support for gitbash on Windows and added more commands [\#141](https://github.com/dictation-toolbox/Caster/pull/141) ([mostlyjason](https://github.com/mostlyjason)) -- Automatically detecting the version of Dragon when writing the settin… [\#140](https://github.com/dictation-toolbox/Caster/pull/140) ([mostlyjason](https://github.com/mostlyjason)) - -## [0.5.7](https://github.com/dictation-toolbox/Caster/tree/0.5.7) ("2016-04-02") - -[Full Changelog](https://github.com/dictation-toolbox/Caster/compare/0.5.0...0.5.7) - -**Fixed bugs:** - -- AsynchronousAction is consuming, anything except "cancel" [\#134](https://github.com/dictation-toolbox/Caster/issues/134) -- symbol match command selection choice broken [\#121](https://github.com/dictation-toolbox/Caster/issues/121) -- BoxAction and FuzzyMatchAction broken [\#117](https://github.com/dictation-toolbox/Caster/issues/117) -- Legion grid uses incorrect screen capture on secondary monitors [\#116](https://github.com/dictation-toolbox/Caster/issues/116) -- ergonomic alarm crashes Caster on startup [\#113](https://github.com/dictation-toolbox/Caster/issues/113) -- "snake" case broken after new CCR [\#112](https://github.com/dictation-toolbox/Caster/issues/112) -- NodeRule resets after second node, instead of after last [\#101](https://github.com/dictation-toolbox/Caster/issues/101) -- Intermittent "Access Denied" error in actions2.py [\#100](https://github.com/dictation-toolbox/Caster/issues/100) -- Status Window Freezes [\#75](https://github.com/dictation-toolbox/Caster/issues/75) -- Clipboard Errors Cause Command Failure [\#74](https://github.com/dictation-toolbox/Caster/issues/74) -- Repeat Command Sometimes Doesn't Work [\#73](https://github.com/dictation-toolbox/Caster/issues/73) -- Updates and fixes to visualstudio.py [\#120](https://github.com/dictation-toolbox/Caster/pull/120) ([chilimangoes](https://github.com/chilimangoes)) -- Fixed sublime.py to work with any version rather than just Sublime Text 2 [\#119](https://github.com/dictation-toolbox/Caster/pull/119) ([chilimangoes](https://github.com/chilimangoes)) - -**Closed issues:** - -- Rainbow for large monitors [\#135](https://github.com/dictation-toolbox/Caster/issues/135) -- get rid of squeue.py [\#118](https://github.com/dictation-toolbox/Caster/issues/118) -- "through" command [\#110](https://github.com/dictation-toolbox/Caster/issues/110) -- Customizer UI [\#99](https://github.com/dictation-toolbox/Caster/issues/99) -- Multi-monitor support for grids [\#93](https://github.com/dictation-toolbox/Caster/issues/93) -- Announcements [\#91](https://github.com/dictation-toolbox/Caster/issues/91) -- Do Full/Lazy Compatibility Check At Startup [\#90](https://github.com/dictation-toolbox/Caster/issues/90) -- Change dragon modes based on active focused window. [\#89](https://github.com/dictation-toolbox/Caster/issues/89) -- \[WSR\] dragonfly exception occurred [\#88](https://github.com/dictation-toolbox/Caster/issues/88) -- find a way to consistently focus windows [\#85](https://github.com/dictation-toolbox/Caster/issues/85) -- Synchronizer Script + Persistent Customizer UI [\#72](https://github.com/dictation-toolbox/Caster/issues/72) -- "Display Available Commands" command [\#71](https://github.com/dictation-toolbox/Caster/issues/71) -- unit tests [\#66](https://github.com/dictation-toolbox/Caster/issues/66) -- Reimplement Missing WSR Functionality [\#63](https://github.com/dictation-toolbox/Caster/issues/63) -- CCR command sets for other languages [\#36](https://github.com/dictation-toolbox/Caster/issues/36) - -**Merged pull requests:** - -- Adding a setting for how long to wait for Atom palette to load [\#139](https://github.com/dictation-toolbox/Caster/pull/139) ([mostlyjason](https://github.com/mostlyjason)) -- Adding additional documentation on the mouse modes [\#136](https://github.com/dictation-toolbox/Caster/pull/136) ([mostlyjason](https://github.com/mostlyjason)) -- Fixes \#116 - Multimonitor support for Legion grid [\#132](https://github.com/dictation-toolbox/Caster/pull/132) ([chilimangoes](https://github.com/chilimangoes)) -- Mouse improvements, app grammar updates, next/prior window [\#130](https://github.com/dictation-toolbox/Caster/pull/130) ([chilimangoes](https://github.com/chilimangoes)) -- Ported a similarity calculation algorithm [\#128](https://github.com/dictation-toolbox/Caster/pull/128) ([chilimangoes](https://github.com/chilimangoes)) -- Grammars for Foxit Reader, SSMS, and misc additions [\#124](https://github.com/dictation-toolbox/Caster/pull/124) ([chilimangoes](https://github.com/chilimangoes)) -- Fix "cannot concatenate 'str' and 'int' objects" error in settings.py [\#123](https://github.com/dictation-toolbox/Caster/pull/123) ([chilimangoes](https://github.com/chilimangoes)) -- FuzzyMatchAction match logging [\#122](https://github.com/dictation-toolbox/Caster/pull/122) ([chilimangoes](https://github.com/chilimangoes)) -- Allow "pipe \(sim | symbol\)" for a more phonetically distinct option [\#109](https://github.com/dictation-toolbox/Caster/pull/109) ([chilimangoes](https://github.com/chilimangoes)) -- App grammars for Visual Studio and KDiff3. [\#108](https://github.com/dictation-toolbox/Caster/pull/108) ([chilimangoes](https://github.com/chilimangoes)) -- CCR refactoring [\#107](https://github.com/dictation-toolbox/Caster/pull/107) ([chilimangoes](https://github.com/chilimangoes)) -- Docs: Added pull request workflow guide [\#104](https://github.com/dictation-toolbox/Caster/pull/104) ([chilimangoes](https://github.com/chilimangoes)) -- Multi-monitor support for grid commands [\#103](https://github.com/dictation-toolbox/Caster/pull/103) ([chilimangoes](https://github.com/chilimangoes)) -- added C\# CCR File [\#102](https://github.com/dictation-toolbox/Caster/pull/102) ([falfaddaghi](https://github.com/falfaddaghi)) -- Javascript CCR: Add "anon funk" command [\#97](https://github.com/dictation-toolbox/Caster/pull/97) ([chilimangoes](https://github.com/chilimangoes)) -- Javascript CCR: more consistent code block formatting. [\#96](https://github.com/dictation-toolbox/Caster/pull/96) ([chilimangoes](https://github.com/chilimangoes)) -- Add a Gitter chat badge to README.md [\#92](https://github.com/dictation-toolbox/Caster/pull/92) ([gitter-badger](https://github.com/gitter-badger)) -- Add "set format" command. [\#87](https://github.com/dictation-toolbox/Caster/pull/87) ([chilimangoes](https://github.com/chilimangoes)) - -## [0.5.0](https://github.com/dictation-toolbox/Caster/tree/0.5.0) ("2015-08-02") - -[Full Changelog](https://github.com/dictation-toolbox/Caster/compare/4dab12796e8c4cdd1a7522371daa6fef9f6ff040...0.5.0) - -**Fixed bugs:** - -- \[WSR\] Legion feature not available without PIL [\#69](https://github.com/dictation-toolbox/Caster/issues/69) -- \[WRS\] Caster v 0.4.9 does not initialize [\#68](https://github.com/dictation-toolbox/Caster/issues/68) -- RegisteredAction with anything beyond R\(Key\("X"\) can keep macros from triggering. [\#67](https://github.com/dictation-toolbox/Caster/issues/67) -- fix SonarQube analysis problems [\#65](https://github.com/dictation-toolbox/Caster/issues/65) -- Grids broken [\#64](https://github.com/dictation-toolbox/Caster/issues/64) -- Initialization fails if the settings file already exists [\#61](https://github.com/dictation-toolbox/Caster/issues/61) -- Caster does not initialize properly with windows speech recognition. [\#59](https://github.com/dictation-toolbox/Caster/issues/59) -- Sikuli scripts does not exist in default Path defined in settings.json [\#54](https://github.com/dictation-toolbox/Caster/issues/54) -- caster.bat returns Device or resource busy The directory is not empty. [\#51](https://github.com/dictation-toolbox/Caster/issues/51) -- Alternate mouse modes don't work in some circumstances [\#47](https://github.com/dictation-toolbox/Caster/issues/47) -- Handle settings file misread more gracefully [\#34](https://github.com/dictation-toolbox/Caster/issues/34) -- Fuzzy string matching works badly [\#30](https://github.com/dictation-toolbox/Caster/issues/30) -- fix the Aptana/Eclipse problem [\#24](https://github.com/dictation-toolbox/Caster/issues/24) -- the flip command [\#16](https://github.com/dictation-toolbox/Caster/issues/16) -- fill is broken [\#14](https://github.com/dictation-toolbox/Caster/issues/14) -- the loop command is broken [\#6](https://github.com/dictation-toolbox/Caster/issues/6) -- monitor change instability [\#3](https://github.com/dictation-toolbox/Caster/issues/3) -- broken command: copy [\#2](https://github.com/dictation-toolbox/Caster/issues/2) - -**Closed issues:** - -- make AsynchronousAction and ContextSeeker more standard [\#84](https://github.com/dictation-toolbox/Caster/issues/84) -- \[Wiki\] List of undocumented features. [\#83](https://github.com/dictation-toolbox/Caster/issues/83) -- Extend AsynchronousAction to include general action objects. [\#81](https://github.com/dictation-toolbox/Caster/issues/81) -- Extend NodeRule to any Dragonfly action [\#79](https://github.com/dictation-toolbox/Caster/issues/79) -- Confirm Command Popup Window [\#78](https://github.com/dictation-toolbox/Caster/issues/78) -- Caster with backend WRS requires x version of dragonfly [\#60](https://github.com/dictation-toolbox/Caster/issues/60) -- Contextually aware commands within CCR command sets [\#58](https://github.com/dictation-toolbox/Caster/issues/58) -- Text Input Not Working [\#55](https://github.com/dictation-toolbox/Caster/issues/55) -- NodeRule [\#53](https://github.com/dictation-toolbox/Caster/issues/53) -- Which Dragon version do you recommend? [\#52](https://github.com/dictation-toolbox/Caster/issues/52) -- Continuous Commands [\#50](https://github.com/dictation-toolbox/Caster/issues/50) -- Alias Chain [\#48](https://github.com/dictation-toolbox/Caster/issues/48) -- Mapping rules associated with languages [\#46](https://github.com/dictation-toolbox/Caster/issues/46) -- Text formatting defaults [\#44](https://github.com/dictation-toolbox/Caster/issues/44) -- Status Window [\#43](https://github.com/dictation-toolbox/Caster/issues/43) -- Settings window [\#42](https://github.com/dictation-toolbox/Caster/issues/42) -- Automatic CCR language change [\#41](https://github.com/dictation-toolbox/Caster/issues/41) -- Common shortcuts for common IDEs [\#40](https://github.com/dictation-toolbox/Caster/issues/40) -- YouTube video demos [\#39](https://github.com/dictation-toolbox/Caster/issues/39) -- Enhancements for "pita" command [\#38](https://github.com/dictation-toolbox/Caster/issues/38) -- Make recorded rules repeatable [\#37](https://github.com/dictation-toolbox/Caster/issues/37) -- Always-on window polling for command mode [\#33](https://github.com/dictation-toolbox/Caster/issues/33) -- Browser plug-ins which communicate with Dragon [\#32](https://github.com/dictation-toolbox/Caster/issues/32) -- Sticky list [\#31](https://github.com/dictation-toolbox/Caster/issues/31) -- Element Columns, Docking [\#29](https://github.com/dictation-toolbox/Caster/issues/29) -- Cleanup config file [\#28](https://github.com/dictation-toolbox/Caster/issues/28) -- Update installation instructions [\#27](https://github.com/dictation-toolbox/Caster/issues/27) -- Remove bottle dependency [\#26](https://github.com/dictation-toolbox/Caster/issues/26) -- add the browser path [\#25](https://github.com/dictation-toolbox/Caster/issues/25) -- "highlight selection" for Legion [\#22](https://github.com/dictation-toolbox/Caster/issues/22) -- settings file overhaul [\#21](https://github.com/dictation-toolbox/Caster/issues/21) -- "Add to Vocabulary" command [\#20](https://github.com/dictation-toolbox/Caster/issues/20) -- RainbowGrid and replace DPGrid [\#18](https://github.com/dictation-toolbox/Caster/issues/18) -- reduce the range of IntegerRef [\#15](https://github.com/dictation-toolbox/Caster/issues/15) -- selective screen reading and mouse positioning [\#13](https://github.com/dictation-toolbox/Caster/issues/13) -- Performance Optimization [\#12](https://github.com/dictation-toolbox/Caster/issues/12) -- "Legion" [\#11](https://github.com/dictation-toolbox/Caster/issues/11) -- Speed up CCR changes [\#10](https://github.com/dictation-toolbox/Caster/issues/10) -- macro recording and playback [\#9](https://github.com/dictation-toolbox/Caster/issues/9) -- Element: Aliasing [\#8](https://github.com/dictation-toolbox/Caster/issues/8) -- Response windows and response queuing system [\#7](https://github.com/dictation-toolbox/Caster/issues/7) -- Support for WSR [\#5](https://github.com/dictation-toolbox/Caster/issues/5) -- standardize the speaking syntax between languages [\#1](https://github.com/dictation-toolbox/Caster/issues/1) - -**Merged pull requests:** - -- Atom Integration [\#70](https://github.com/dictation-toolbox/Caster/pull/70) ([ghost](https://github.com/ghost)) -- Revised HTML CCR formatting and spacing. [\#62](https://github.com/dictation-toolbox/Caster/pull/62) ([ghost](https://github.com/ghost)) -- Reorganized and expanded HTML CCR. [\#57](https://github.com/dictation-toolbox/Caster/pull/57) ([ghost](https://github.com/ghost)) - - - -\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* diff --git a/Install_Caster_DNS-WSR.bat b/Install_Caster_DNS-WSR.bat deleted file mode 100644 index 114aa3752..000000000 --- a/Install_Caster_DNS-WSR.bat +++ /dev/null @@ -1,28 +0,0 @@ - -@echo off - -SetLocal EnableDelayedExpansion -set python_version=3.10-32 -set currentpath=%~dp0 -echo Installation path: %currentpath% - -@REM execute python launcher for python directory -FOR /F "tokens=1 USEBACKQ delims=" %%i IN (`py -%python_version% -c "import sys; print(sys.exec_prefix)"`) DO ( set python_path=%%i ) - -@REM whack a funny trailing character (newline?) from end -set python_path=!python_path:~0,-1! - -set PATH=%python_path%;%python_path%/Scripts;%PATH% -echo %PATH% - -echo Next line should clearly state python version: -python --version - -echo Using this python/pip: - -py -%python_version% -m pip install --upgrade pip - -echo Installing Caster Dependencies for DNS/WSR -py -%python_version% -m pip install -r "%currentpath%requirements.txt" - -pause 1 diff --git a/Install_Caster_Kaldi.bat b/Install_Caster_Kaldi.bat deleted file mode 100644 index 0baf9a74a..000000000 --- a/Install_Caster_Kaldi.bat +++ /dev/null @@ -1,14 +0,0 @@ -@echo off -set currentpath=%~dp0 -echo Installation path: %currentpath% -echo Using this python/pip: -python -m pip -V - -echo Installing Caster Dependencies -py -m pip install -r "%currentpath%requirements.txt" -py -m pip install dragonfly2[kaldi] - -echo Remember: Manually install kaldi a model. -echo See Caster kaldi install instructions on ReadTheDocs. - -pause 1 diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 989905f27..000000000 --- a/LICENSE +++ /dev/null @@ -1,185 +0,0 @@ -##Contents -1. License for Original Code -2. License for Non-Original Code - -##License for Original Code -GNU LESSER GENERAL PUBLIC LICENSE -​ Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - -``` - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. -``` - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. - -##Licenses for Non-Original Code -Below is a list of all the non-original code used in this work, and the licenses each respective piece uses. - -- Dragonfly: LGPL3 -- Future: OSI Approved, MIT License (MIT) -- Pywin32: Python Software Foundation License -- Pillow: PIL Software License -- Mock: BSD License (OSI Approved :: BSD License) -- TiRG by trg787: Public Domain License, (https://github.com/synkarius/tirg-dll) -- Tomlkit: MIT License (MIT) -- Wxpython: OSI Approved (wxWindows Library License (https://opensource.org/licenses/wxwindows.php) -- Pathlib2: MIT License (MIT), (https://github.com/mcmtroffaes/pathlib2) diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 6fa3eaaae..000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,20 +0,0 @@ -global-exclude *.pyc -include _caster.py -include Run_Caster_Kaldi.bat -include Run_Caster_WSR.bat -include Run_Caster_DNS.bat -include Run_Caster_Test_Engine.bat -include docs/README.md -include castervoice/bin/share/words.txt -include castervoice/bin/share/git_repo_local_to_remote_match.toml.defaults -include castervoice/bin/reboot.bat -include castervoice/bin/reboot_wsr.bat -include castervoice/lib/dll/tirg-32.dll -include castervoice/lib/dll/tirg-64.dll -include castervoice/asynch/sikuli/server/xmlrpc_server.sikuli/xmlrpc_server.html -include castervoice/asynch/sikuli/server/xmlrpc_server.sikuli/xmlrpc_server.py -include castervoice/lib/github_automation.ahk -include requirements.txt -include requirements-dev.txt -include requirements-mac-linux.txt -include post_setup.py \ No newline at end of file diff --git a/Run_Caster_Kaldi.bat b/Run_Caster_Kaldi.bat deleted file mode 100644 index 3d398af25..000000000 --- a/Run_Caster_Kaldi.bat +++ /dev/null @@ -1,9 +0,0 @@ -@echo off -echo Running Kaldi from Dragonfly CLI - -set currentpath=%~dp0 - -TITLE Caster: Status Window -py -m dragonfly load _*.py --engine kaldi --no-recobs-messages --engine-options "model_dir=kaldi_model, vad_padding_end_ms=300" - -pause 1 diff --git a/Run_Caster_Test_Engine.bat b/Run_Caster_Test_Engine.bat deleted file mode 100644 index 4ce933936..000000000 --- a/Run_Caster_Test_Engine.bat +++ /dev/null @@ -1,21 +0,0 @@ -@echo off -echo Running Test Engine from Dragonfly CLI. -echo( - -set currentpath=%~dp0 - -TITLE Caster: Test Engine Window -echo --------------------------Instructions ------------------------- -echo Type commands to emulate as if they are being dictated by voice. -echo lowercase mimics `commands`, UPPERCASE mimics `free dictation` -echo Upper and lowercase words can be mixed e.g `say THIS IS A TEST` -echo( -echo Edit the `--delay 3` in bat file to change command delay in seconds. -echo The delay allows user to switch to the relevant application to test commands -echo ---------------------------------------------------------------- -echo( -echo( - -py -m dragonfly test _caster.py --delay 3 - -pause 1 diff --git a/Run_Caster_WSR.bat b/Run_Caster_WSR.bat deleted file mode 100644 index 02280b510..000000000 --- a/Run_Caster_WSR.bat +++ /dev/null @@ -1,9 +0,0 @@ -@echo off -echo Running WRS from Dragonfly CLI. - -set currentpath=%~dp0 - -TITLE Caster: Status Window -py -m dragonfly load --engine sapi5inproc _*.py --no-recobs-messages - -pause 1 diff --git a/_caster.py b/_caster.py deleted file mode 100644 index 7aff0eeeb..000000000 --- a/_caster.py +++ /dev/null @@ -1,45 +0,0 @@ -''' -main Caster module -Created on Jun 29, 2014 -''' -import logging -import importlib -from dragonfly import get_engine, get_current_engine -from castervoice.lib import control -from castervoice.lib import settings -from castervoice.lib import printer -from castervoice.lib.ctrl.configure_engine import EngineConfigEarly, EngineConfigLate -from castervoice.lib.ctrl.dependencies import DependencyMan -from castervoice.lib.ctrl.updatecheck import UpdateChecker -from castervoice.asynch import hud_support - -printer.out("@ - Starting {} with `{}` Engine -\n".format(settings.SOFTWARE_NAME, get_engine().name)) - -DependencyMan().initialize() # requires nothing -settings.initialize() -UpdateChecker().initialize() # requires settings/dependencies -EngineConfigEarly() # requires settings/dependencies - - -if control.nexus() is None: - from castervoice.lib.ctrl.mgr.loading.load.content_loader import ContentLoader - from castervoice.lib.ctrl.mgr.loading.load.content_request_generator import ContentRequestGenerator - from castervoice.lib.ctrl.mgr.loading.load.reload_fn_provider import ReloadFunctionProvider - from castervoice.lib.ctrl.mgr.loading.load.modules_access import SysModulesAccessor - _crg = ContentRequestGenerator() - _rp = ReloadFunctionProvider() - _sma = SysModulesAccessor() - _content_loader = ContentLoader(_crg, importlib.import_module, _rp.get_reload_fn(), _sma) - control.init_nexus(_content_loader) - EngineConfigLate() # Requires grammars to be loaded and nexus - -if settings.SETTINGS["sikuli"]["enabled"]: - from castervoice.asynch.sikuli import sikuli_controller - sikuli_controller.get_instance().bootstrap_start_server_proxy() - -if get_current_engine().name != "text": - hud_support.start_hud() - -dh = printer.get_delegating_handler() -dh.register_handler(hud_support.HudPrintMessageHandler()) # After hud starts -printer.out("\n") # Force update to display text diff --git a/caster_example_rule.py b/caster_example_rule.py deleted file mode 100644 index 913b11b13..000000000 --- a/caster_example_rule.py +++ /dev/null @@ -1,87 +0,0 @@ -# These lines that start with the '#' are called comments. They don't affect the way the code runs. -# In this tutorial file, I put comments above the relevant lines. - -# 1. Before we begin. Caster Rules should be placed in [Caster User Directory](https://dictation-toolbox.github.io/Caster/#/User_Dir/Caster_User_Dir) `rules` directory. See hyperlink for directory file path based on OS. The `rules` folder is where all your created rules should be stored. This folder can be summoned by voice say `bring me caster rules` If Caster is running. -# The function 'get_rule()' that loads this rule is commented out. Therefore will cause it to never run. -# You will need to scroll to the very end of the file and uncomment the following: - -# def get_rule(): -# return MyRule, RuleDetails(name="my rule") - -# 2. Now that it's uncommented simply start/restart Caster. -# 3. To enable the rule, say "enable my rule" - -# You can skip down to the next comment, for now this is not important... - -from dragonfly import (BringApp, Key, Function, Playback, - IntegerRef, Dictation, Choice, WaitWindow, MappingRule) - -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.actions import Key, Text, Mouse - - -def my_function(n, text): - print("put some Python logic here: " + str(text)) - -class MyRule(MappingRule): - - # It is this section that you want to edit if you're new to: mapping, extras, and defaults concepts. - mapping = { - # Here I'm just saying two words to trigger some other words - "hotel info": Text("These types of hospitality services are not cheap."), - - # In the next line, there are two things to observe: - # 1. The use of parentheses and the pipe symbol ( | ) lets me use either "motel" or "lodging" to trigger that command. - # 2. The playback action, lets me tell the speech recognition engine to simulate me speaking some words. - '(motel | lodging)': Playback([(["hotel", "info"], 0.0)]), - - # Here I'm using BringApp -- this is the same as typing what goes in between the parentheses - # Into the command prompt/terminnal, without the quotes and commas, like: - # Windows OS: explorer C:\NatLink\NatLink\MacroSystem - # Could be changed changed for Linux/Mac (which would open Windows Explorer at the specified location). Anything you can do with the command line can be done this way - "open natlink folder": BringApp("explorer", r"C:\NatLink\NatLink\MacroSystem"), - - # Here I'm using the Key action to press some keys -- see the documentation here: https://dragonfly2.readthedocs.io/en/latest/actions.html?#module-dragonfly.actions.action_key - # "a-" Everything before "-" is a keyboard modifier, "a" is for the "alt" Key. - # "-space" reprresents the SpaceBar Key. - # "/10" After "a-space" Slows down the keypresses by 10 ms" with a seriess of keypresses as demonstrated this may be necessary. - # The comma "," after "a-space/10" separates keypresses in a series. - # remax is Windows OS Specific to maximize the current window in the forefront - "remax": Key("a-space/10,r/10,a-space/10,x"), - - # Here I'm chaining a bunch of different actions together to do a complex task - # This is Windows OS speciffic but the path in BringApp could be changed for Linux/Mac - "(show | open) documentation": BringApp('C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe') + WaitWindow(executable="chrome.exe") + Key('c-t') + WaitWindow(title="New Tab") + Text('https://dragonfly2.readthedocs.io/en/latest') + Key('enter'), - - # If you need to do more complicated tasks, or use external resources, a function might be what you need. - # Note that here, I'm using extras: "n" and "text" - # The angle brackets <> meaning I'm using an extra, and the square brackets [] mean that I don't have to speak that word, it's optional. - # Advice: if you use an optional extra, like I am with "text", you should set a default value in the defaults section down below. - # To trigger the following command, you would have to say the word "function" followed by a number between 1 and 1000. - '[use] function []': Function(my_function, extra={'n', 'text'}), - - # Sometimes it's easier to have things as a list in a command as a choice that do different things. - # That's what `` Is defined in `extras` allows you define that list. If you dictate `i choose custom grid` Then `CustomGrid` will be printed as text. - # Items in the list are pairs. e.g `{"custom grid": "CustomGrid"}` The first item of a pair is the command "custom grid" and the second "CustomGrid" output text action. - "i choose ": Text("%(choice)s"), - } - extras = [ - IntegerRef("n", 1, 1000), - Dictation("text"), - Choice("choice", - { - "alarm": "alarm", - "custom grid": "CustomGrid", - "element": "e" - }), - ] - defaults = { - "n": 1, - "text": "", - } -# This stuff below is required too -- -# However you will learn more about how to change the rule types and contexts later in the documentation. - -# Uncomment the next two lines. -#def get_rule(): -# return MyRule, RuleDetails(name="my rule") diff --git a/castervoice/__init__.py b/castervoice/__init__.py deleted file mode 100644 index b4fdb8fe7..000000000 --- a/castervoice/__init__.py +++ /dev/null @@ -1 +0,0 @@ -name = "castervoice" \ No newline at end of file diff --git a/castervoice/asynch/__init__.py b/castervoice/asynch/__init__.py deleted file mode 100644 index a879640f7..000000000 --- a/castervoice/asynch/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -import os -import glob -modules = glob.glob(os.path.dirname(__file__) + "/*.py") -__all__ = [ - os.path.basename(f)[:-3] - for f in modules - if not f.endswith('__init__.py') and not f.endswith('settingswindow.py') -] diff --git a/castervoice/asynch/hmc/__init__.py b/castervoice/asynch/hmc/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/asynch/hmc/h_launch.py b/castervoice/asynch/hmc/h_launch.py deleted file mode 100644 index 9a2f1c5b1..000000000 --- a/castervoice/asynch/hmc/h_launch.py +++ /dev/null @@ -1,71 +0,0 @@ -import os -import subprocess -import sys - -from xmlrpc.server import SimpleXMLRPCServer - -try: # Style C -- may be imported into Caster, or externally - BASE_PATH = os.path.realpath(__file__).rsplit(os.path.sep + "castervoice", 1)[0] - if BASE_PATH not in sys.path: - sys.path.append(BASE_PATH) -finally: - from castervoice.lib import settings - - -def launch(hmc_type, data=None): - from dragonfly import (WaitWindow, FocusWindow, Key) - instructions = _get_instructions(hmc_type) - if data is not None: - instructions.append(data) - subprocess.Popen(instructions) - hmc_title = _get_title(hmc_type) - WaitWindow(title=hmc_title, timeout=5).execute() - FocusWindow(title=hmc_title).execute() - - -def _get_instructions(hmc_type): - if hmc_type == settings.QTTYPE_SETTINGS: - return [ - settings.SETTINGS["paths"]["PYTHONW"], - settings.SETTINGS["paths"]["SETTINGS_WINDOW_PATH"] - ] - else: - return [ - settings.SETTINGS["paths"]["PYTHONW"], - settings.SETTINGS["paths"]["HOMUNCULUS_PATH"], hmc_type - ] - - -def _get_title(hmc_type): - default = settings.HOMUNCULUS_VERSION - if hmc_type == settings.QTYPE_DEFAULT or hmc_type == settings.QTYPE_INSTRUCTIONS: - return default - elif hmc_type == settings.QTYPE_RECORDING: - return default + settings.HMC_TITLE_RECORDING - elif hmc_type == settings.QTYPE_DIRECTORY: - return default + settings.HMC_TITLE_DIRECTORY - elif hmc_type == settings.QTYPE_CONFIRM: - return default + settings.HMC_TITLE_CONFIRM - elif hmc_type == settings.QTTYPE_SETTINGS: - return settings.SETTINGS_WINDOW_TITLE + settings.SOFTWARE_VERSION_NUMBER - return default - - -def main(): - from castervoice.lib.qt import QtWidgets, qapp_exec - from castervoice.asynch.hmc.homunculus import Homunculus - from castervoice.lib.merge.communication import Communicator - server_address = (Communicator.LOCALHOST, Communicator().com_registry["hmc"]) - # Enabled by default logging causes RPC to malfunction when the GUI runs on - # pythonw. Explicitly disable logging for the XML server. - server = SimpleXMLRPCServer(server_address, logRequests=False, allow_none=True) - app = QtWidgets.QApplication(sys.argv) - window = Homunculus(server, sys.argv) - window.show() - exit_code = qapp_exec(app) - server.shutdown() - sys.exit(exit_code) - - -if __name__ == '__main__': - main() diff --git a/castervoice/asynch/hmc/hmc_ask_directory.py b/castervoice/asynch/hmc/hmc_ask_directory.py deleted file mode 100644 index 8fad0cce5..000000000 --- a/castervoice/asynch/hmc/hmc_ask_directory.py +++ /dev/null @@ -1,50 +0,0 @@ -import os -import sys -from threading import Timer -from tkinter import Entry, Label, StringVar -from tkinter import filedialog as tkFileDialog - -try: # Style C -- may be imported into Caster, or externally - BASE_PATH = os.path.realpath(__file__).rsplit(os.path.sep + "castervoice", 1)[0] - if BASE_PATH not in sys.path: - sys.path.append(BASE_PATH) -finally: - from castervoice.asynch.hmc.homunculus import Homunculus - from castervoice.lib import settings - - -class HomunculusDirectory(Homunculus): - def __init__(self, params): - Homunculus.__init__(self, params[0], args=None) - self.title(settings.HOMUNCULUS_VERSION + settings.HMC_TITLE_DIRECTORY) - - self.geometry("640x50+" + str(int(self.winfo_screenwidth()/2 - 320)) + "+" + - str(int(self.winfo_screenheight()/2 - 25))) - Label(self, text="Enter directory or say 'browse'", name="pathlabel").pack() - self.content = StringVar() - self.word_box = Entry(self, name="word_box", width=640, textvariable=self.content) - self.word_box.pack() - - def xmlrpc_get_message(self): - if self.completed: - response = {"mode": "ask_dir"} - response["path"] = self.word_box.get() - - Timer(1, self.xmlrpc_kill).start() - self.after(10, self.withdraw) - return response - else: - return None - - def _ask_directory(self): - dir_opt = {} - dir_opt['initialdir'] = os.path.expanduser('~') #os.environ["HOME"] - dir_opt['mustexist'] = False - dir_opt['parent'] = self - dir_opt['title'] = 'Please select directory' - result = tkFileDialog.askdirectory(**dir_opt) - self.content.set(result) - - def xmlrpc_do_action(self, action, details=None): - if action == "dir": - self.after(10, self._ask_directory) diff --git a/castervoice/asynch/hmc/hmc_confirm.py b/castervoice/asynch/hmc/hmc_confirm.py deleted file mode 100644 index 18e38ea32..000000000 --- a/castervoice/asynch/hmc/hmc_confirm.py +++ /dev/null @@ -1,42 +0,0 @@ -from tkinter import Label -import os -import sys -from threading import Timer - -try: # Style C -- may be imported into Caster, or externally - BASE_PATH = os.path.realpath(__file__).rsplit(os.path.sep + "castervoice", 1)[0] - if BASE_PATH not in sys.path: - sys.path.append(BASE_PATH) -finally: - from castervoice.lib import settings - from castervoice.asynch.hmc.homunculus import Homunculus - - -class HomunculusConfirm(Homunculus): - def __init__(self, params): - Homunculus.__init__(self, params[0], args=None) - self.title(settings.HOMUNCULUS_VERSION + settings.HMC_TITLE_CONFIRM) - - self.geometry("320x50+" + str(int(self.winfo_screenwidth()/2 - 160)) + "+" + - str(int(self.winfo_screenheight()/2 - 25))) - Label( - self, - text="Please confirm: " + " ".join(params[1].split(settings.HMC_SEPARATOR)), - name="i").pack() - Label(self, text="(say \"confirm\" or \"disconfirm\")", name="i2").pack() - - def xmlrpc_get_message(self): - if self.completed: - response = {"mode": "confirm"} - response["confirm"] = self.value - Timer(1, self.xmlrpc_kill).start() - self.after(10, self.withdraw) - return response - else: - return None - - def xmlrpc_do_action(self, action, details=None): - if isinstance(action, bool): - self.completed = True - '''1 is True, 2 is False''' - self.value = 1 if action else 2 diff --git a/castervoice/asynch/hmc/hmc_recording.py b/castervoice/asynch/hmc/hmc_recording.py deleted file mode 100644 index 5d6dd45ad..000000000 --- a/castervoice/asynch/hmc/hmc_recording.py +++ /dev/null @@ -1,134 +0,0 @@ -import sys, os -from threading import Timer - -from tkinter import Label, Entry, Checkbutton -import tkinter as tk - -try: # Style C -- may be imported into Caster, or externally - BASE_PATH = os.path.realpath(__file__).rsplit(os.path.sep + "castervoice", 1)[0] - if BASE_PATH not in sys.path: - sys.path.append(BASE_PATH) -finally: - from castervoice.lib import settings - from castervoice.asynch.hmc.homunculus import Homunculus - - -class HomunculusRecording(Homunculus): - def get_row(self, cut_off=0): - result = self.grid_row - cut_off - self.grid_row += 1 - return result - - def __init__(self, params): - self.grid_row = 0 - Homunculus.__init__(self, params[0], args=None) - self.title(settings.HOMUNCULUS_VERSION + settings.HMC_TITLE_RECORDING) - - self.geometry("640x480+" + str(int(self.winfo_screenwidth()/2 - 320)) + "+" + - str(int(self.winfo_screenheight()/2 - 240))) - self.instructions = "Macro Recording Options" - Label( - self, text=self.instructions, name="pathlabel").grid( - row=self.get_row(), column=1, sticky=tk.E) - - wf_row = self.get_row() - Label( - self, text="Command Words:", name="wordlabel").grid( - row=wf_row, column=0, sticky=tk.W) - self.word_box = Entry(self, name="word_box") - self.word_box.grid(row=wf_row, column=1, sticky=tk.W) - - self.repeatable = tk.IntVar() - Checkbutton( - self, text="Make Repeatable", variable=self.repeatable).grid( - row=self.get_row(), column=0, sticky=tk.W) - - Label( - self, text="Dictation History", name="optionslabel").grid( - row=self.get_row(), column=1, sticky=tk.E) - self.word_state = [] - cb_number = 1 - - sentences = params[1].split("[s]") - sentences.pop() - for sentence in sentences: - sentence_words = sentence.split("[w]") - sentence_words.pop() - display_sentence = " ".join(sentence_words).decode("unicode_escape") - - cb_row = 0 # self.get_row() - cb_col = 0 - row_cut_off = 14 - col2_inc = -1 - word_state_var = tk.IntVar() - - if cb_number == 1: - word_state_var.set(True) - - if cb_number < row_cut_off: - cb_row = cb_row = self.get_row() - else: - cb_row = cb_row = self.get_row(row_cut_off + col2_inc) - cb_col = 2 - col2_inc += 1 - - Checkbutton( - self, text="(" + str(cb_number) + ")", variable=word_state_var).grid( - row=cb_row, column=cb_col + 1, sticky=tk.W) - self.word_state.append((word_state_var, cb_number)) - cb_number += 1 - Label( - self, text=display_sentence, name="cb_label" + str(cb_number)).grid( - row=cb_row, column=cb_col, sticky=tk.W) - - self.cb_max = cb_number - - def xmlrpc_get_message(self): - if self.completed: - response = {"mode": "recording"} - word = self.word_box.get() - if len(word) == 0: - self.xmlrpc_kill() - response["word"] = word - response["repeatable"] = self.repeatable.get() - - selected_indices = [] - for ws in self.word_state: - if ws[0].get() == 1: - selected_indices.append(ws[1] - 1) - response["selected_indices"] = selected_indices - - Timer(1, self.xmlrpc_kill).start() - self.after(10, self.withdraw) - return response - else: - return None - - def check_boxes(self, details): - for box_index in details: - if box_index >= 1 and box_index <= self.cb_max: - self.word_state[box_index - 1][0].set(self.word_state[box_index - - 1][0].get() == 0) - - def check_range_of_boxes(self, details): - box_index_from = details[0] - 1 - box_index_to = details[1] - 1 - for i in range(0, self.cb_max): - if i <= self.cb_max: - self.word_state[i][0].set(i >= box_index_from and i <= box_index_to) - - def xmlrpc_do_action(self, action, details=None): - '''acceptable keys are numbers and w and p''' - if action == "check": - self.check_boxes(details) - elif action == "focus": - if details == "word": - self.word_box.focus_set() - elif action == "check_range": - self.check_range_of_boxes(details) - elif action == "exclude": - box_index = details - if box_index >= 1 and box_index <= self.cb_max: - self.word_state[box_index - 1][0].set(False) - elif action == "repeatable": - self.repeatable.set(not self.repeatable.get()) diff --git a/castervoice/asynch/hmc/homunculus.py b/castervoice/asynch/hmc/homunculus.py deleted file mode 100644 index 49484c9c6..000000000 --- a/castervoice/asynch/hmc/homunculus.py +++ /dev/null @@ -1,268 +0,0 @@ -import os -import sys -import threading - -import dragonfly - -try: # Style C -- may be imported into Caster, or externally - BASE_PATH = os.path.realpath(__file__).rsplit(os.path.sep + "castervoice", 1)[0] - if BASE_PATH not in sys.path: - sys.path.append(BASE_PATH) -finally: - from castervoice.lib import settings - -try: - from castervoice.lib.qt import QtCore, QtWidgets, qt_attr -except ImportError: - sys.exit(0) - -QApplication = QtWidgets.QApplication -QCheckBox = QtWidgets.QCheckBox -QDialog = QtWidgets.QDialog -QFileDialog = QtWidgets.QFileDialog -QFormLayout = QtWidgets.QFormLayout -QLabel = QtWidgets.QLabel -QLineEdit = QtWidgets.QLineEdit -QScrollArea = QtWidgets.QScrollArea -QTextEdit = QtWidgets.QTextEdit -QVBoxLayout = QtWidgets.QVBoxLayout -QWidget = QtWidgets.QWidget - -ALIGN_CENTER = qt_attr(QtCore, ("Qt", "AlignCenter"), ("Qt", "AlignmentFlag", "AlignCenter")) -SHOW_DIRS_ONLY = qt_attr( - QtWidgets, - ("QFileDialog", "ShowDirsOnly"), - ("QFileDialog", "Option", "ShowDirsOnly"), -) - -RPC_DIR_EVENT = QtCore.QEvent.Type(QtCore.QEvent.registerEventType(-1)) - - -class Homunculus(QDialog): - - def __init__(self, server, args): - QDialog.__init__(self, None) - self.htype = args[1] - self.completed = False - self.server = server - self.setup_xmlrpc_server() - self.mainLayout = QVBoxLayout() - found_word = None - if len(args) > 2: - found_word = args[2] - if self.htype == settings.QTYPE_DEFAULT: - self.setup_base_window() - elif self.htype == settings.QTYPE_INSTRUCTIONS: - self.setup_base_window(found_word) - elif self.htype == settings.QTYPE_CONFIRM: - self.setup_confirm_window(found_word) - elif self.htype == settings.QTYPE_DIRECTORY: - self.setup_directory_window() - elif self.htype == settings.QTYPE_RECORDING: - self.setup_recording_window(found_word) - self.setLayout(self.mainLayout) - self.expiration = threading.Timer(300, self.xmlrpc_kill) - self.expiration.start() - - def setup_base_window(self, data=None): - x = dragonfly.monitors[0].rectangle.dx / 2 - 150 - y = dragonfly.monitors[0].rectangle.dy / 2 - 100 - self.setGeometry(x, y, 300, 200) - self.setWindowTitle(settings.HOMUNCULUS_VERSION) - self.data = data.split("|") if data else [0, 0] - label = QLabel(" ".join(self.data[0].split(settings.HMC_SEPARATOR))) if data else QLabel("Enter response then say 'complete'") # pylint: disable=no-member - label.setAlignment(ALIGN_CENTER) - self.ext_box = QTextEdit() - self.mainLayout.addWidget(label) - self.mainLayout.addWidget(self.ext_box) - self.setWindowTitle(settings.HOMUNCULUS_VERSION) - - def setup_confirm_window(self, params): - x = dragonfly.monitors[0].rectangle.dx / 2 - 160 - y = dragonfly.monitors[0].rectangle.dy / 2 - 25 - self.setGeometry(x, y, 320, 50) - self.setWindowTitle(settings.HOMUNCULUS_VERSION + settings.HMC_TITLE_CONFIRM) - label1 = QLabel("Please confirm: " + " ".join(params.split(settings.HMC_SEPARATOR))) - label2 = QLabel("(say \"confirm\" or \"disconfirm\")") - self.mainLayout.addWidget(label1) - self.mainLayout.addWidget(label2) - - def setup_directory_window(self): - x = dragonfly.monitors[0].rectangle.dx / 2 - 320 - y = dragonfly.monitors[0].rectangle.dy / 2 - 25 - self.setGeometry(x, y, 640, 50) - self.setWindowTitle(settings.HOMUNCULUS_VERSION + settings.HMC_TITLE_DIRECTORY) - label = QLabel("Enter directory or say 'browse'") - self.word_box = QLineEdit() - label.setBuddy(self.word_box) - self.mainLayout.addWidget(label) - self.mainLayout.addWidget(self.word_box) - - def setup_recording_window(self, history): - self.grid_row = 0 - x = dragonfly.monitors[0].rectangle.dx / 2 - 320 - y = dragonfly.monitors[0].rectangle.dy / 2 - 240 - self.setGeometry(x, y, 640, 480) - self.setWindowTitle(settings.HOMUNCULUS_VERSION + settings.HMC_TITLE_RECORDING) - label = QLabel("Macro Recording Options") - label.setAlignment(ALIGN_CENTER) - self.mainLayout.addWidget(label) - label = QLabel("Command Words:") - self.word_box = QLineEdit() - label.setBuddy(self.word_box) - self.mainLayout.addWidget(label) - self.mainLayout.addWidget(self.word_box) - self.repeatable = QCheckBox("Make Repeatable") - self.mainLayout.addWidget(self.repeatable) - label = QLabel("Dictation History") - label.setAlignment(ALIGN_CENTER) - self.mainLayout.addWidget(label) - self.word_state = [] - cb_number = 1 - sentences = history.split("[s]") - sentences.pop() - form = QFormLayout() - for sentence in sentences: - sentence_words = sentence.split("[w]") - sentence_words.pop() - display_sentence = " ".join(sentence_words) - cb = QCheckBox("(" + str(cb_number) + ")") - form.addRow(QLabel(display_sentence), cb) - self.word_state.append(cb) - cb_number += 1 - self.word_state[0].setChecked(True) - self.cb_max = cb_number - area = QScrollArea(self) - area.setWidgetResizable(True) - group = QWidget(area) - group.setLayout(form) - area.setWidget(group) - self.mainLayout.addWidget(area) - - def check_boxes(self, details): - for box_index in details: - if 0 < box_index and box_index < self.cb_max: - self.word_state[box_index - 1].setChecked(True) - - def check_range_of_boxes(self, details): - box_index_from = details[0] - 1 - box_index_to = details[1] - for i in range(max(0, box_index_from), min(box_index_to, self.cb_max - 1)): - self.word_state[i].setChecked(True) - - def ask_directory(self): - result = QFileDialog.getExistingDirectory(self, "Please select directory", os.environ["HOME"], SHOW_DIRS_ONLY) - self.word_box.setText(result) - - def event(self, event): - if event.type() == RPC_DIR_EVENT: - self.ask_directory() - return True - return QDialog.event(self, event) - - def reject(self): - self.expiration.cancel() - QApplication.quit() - - ''' - XMLRPC methods - ''' - - def setup_xmlrpc_server(self): - self.server.register_function(self.xmlrpc_kill, "kill") - self.server.register_function(self.xmlrpc_complete, "complete") - if self.htype == settings.QTYPE_DEFAULT or self.htype == settings.QTYPE_INSTRUCTIONS: - self.server.register_function(self.xmlrpc_do_action, "do_action") - self.server.register_function(self.xmlrpc_get_message, "get_message") - elif self.htype == settings.QTYPE_CONFIRM: - self.server.register_function(self.xmlrpc_do_action_confirm, "do_action") - self.server.register_function(self.xmlrpc_get_message_confirm, "get_message") - elif self.htype == settings.QTYPE_DIRECTORY: - self.server.register_function(self.xmlrpc_do_action_directory, "do_action") - self.server.register_function(self.xmlrpc_get_message_directory, "get_message") - elif self.htype == settings.QTYPE_RECORDING: - self.server.register_function(self.xmlrpc_do_action_recording, "do_action") - self.server.register_function(self.xmlrpc_get_message_recording, "get_message") - server_thread = threading.Thread(target=self.server.serve_forever) - server_thread.daemon = True - server_thread.start() - - def xmlrpc_kill(self): - self.expiration.cancel() - QApplication.quit() - - def xmlrpc_complete(self): - self.completed = True - threading.Timer(10, self.xmlrpc_kill).start() - - def xmlrpc_do_action(self, action, details=None): - pass - - def xmlrpc_get_message(self): - response = None - if self.completed: - response = [self.ext_box.toPlainText(), self.data] - threading.Timer(1, self.xmlrpc_kill).start() - return response - - def xmlrpc_do_action_confirm(self, action, details=None): - if isinstance(action, bool): - self.completed = True - '''1 is True, 2 is False''' - self.value = 1 if action else 2 - - def xmlrpc_get_message_confirm(self): - response = None - if self.completed: - response = {"mode": "confirm"} - response["confirm"] = self.value - threading.Timer(1, self.xmlrpc_kill).start() - return response - - def xmlrpc_do_action_directory(self, action, details=None): - if action == "dir": - QtCore.QCoreApplication.postEvent(self, QtCore.QEvent(RPC_DIR_EVENT)) - - def xmlrpc_get_message_directory(self): - response = None - if self.completed: - response = {"mode": "ask_dir"} - response["path"] = self.word_box.text() - threading.Timer(1, self.xmlrpc_kill).start() - return response - - def xmlrpc_do_action_recording(self, action, details=None): - '''acceptable keys are numbers and w and p''' - if action == "check": - self.check_boxes(details) - elif action == "focus": - if details == "word": - self.word_box.setFocus() - elif action == "check_range": - self.check_range_of_boxes(details) - elif action == "exclude": - box_index = details - if 0 < box_index and box_index < self.cb_max: - self.word_state[box_index - 1].setChecked(False) - elif action == "repeatable": - self.repeatable.setChecked(not self.repeatable.isChecked()) - - def xmlrpc_get_message_recording(self): - response = None - if self.completed: - word = self.word_box.text() - if len(word) > 0: - response = {"mode": "recording"} - response["word"] = word - response["repeatable"] = self.repeatable.isChecked() - selected_indices = [] - index = 0 - for ws in self.word_state: - if ws.isChecked(): - selected_indices.append(index) - index += 1 - response["selected_indices"] = selected_indices - if len(selected_indices) == 0: - response = None - threading.Timer(1, self.xmlrpc_kill).start() - return response diff --git a/castervoice/asynch/hmc_rules/__init__.py b/castervoice/asynch/hmc_rules/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/asynch/hmc_rules/hmc_base_rule.py b/castervoice/asynch/hmc_rules/hmc_base_rule.py deleted file mode 100644 index cd024673a..000000000 --- a/castervoice/asynch/hmc_rules/hmc_base_rule.py +++ /dev/null @@ -1,25 +0,0 @@ -from dragonfly import Function, MappingRule - -from castervoice.asynch.hmc_rules.hmc_support import kill -from castervoice.lib import control, settings -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -def complete(): - control.nexus().comm.get_com("hmc").complete() - - -class HMCRule(MappingRule): - mapping = { - "kill homunculus": - R(Function(kill)), - "complete": - R(Function(complete)) - } - - -def get_rule(): - details = RuleDetails(name="h m c rule", - title=settings.HOMUNCULUS_VERSION) - return HMCRule, details diff --git a/castervoice/asynch/hmc_rules/hmc_confirm_rule.py b/castervoice/asynch/hmc_rules/hmc_confirm_rule.py deleted file mode 100644 index 5a27b9aed..000000000 --- a/castervoice/asynch/hmc_rules/hmc_confirm_rule.py +++ /dev/null @@ -1,26 +0,0 @@ -from dragonfly import Function, MappingRule - -from castervoice.lib import control, settings -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -def hmc_confirm(value): - control.nexus().comm.get_com("hmc").do_action(value) - - -class HMCConfirmRule(MappingRule): - mapping = { - # specific to confirm - "confirm": - R(Function(hmc_confirm, value=True)), - "disconfirm": - R(Function(hmc_confirm, value=False), - rspec="hmc_cancel") - } - - -def get_rule(): - details = RuleDetails(name="h m c confirm rule", - title=settings.HMC_TITLE_CONFIRM) - return HMCConfirmRule, details diff --git a/castervoice/asynch/hmc_rules/hmc_directory_rule.py b/castervoice/asynch/hmc_rules/hmc_directory_rule.py deleted file mode 100644 index 526abdcf7..000000000 --- a/castervoice/asynch/hmc_rules/hmc_directory_rule.py +++ /dev/null @@ -1,23 +0,0 @@ -from dragonfly import Function, MappingRule - -from castervoice.lib import control, settings -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -def hmc_directory_browse(): - control.nexus().comm.get_com("hmc").do_action("dir") - - -class HMCDirectoryRule(MappingRule): - mapping = { - # specific to directory browser - "browse": - R(Function(hmc_directory_browse)) - } - - -def get_rule(): - details = RuleDetails(name="h m c directory rule", - title=settings.HMC_TITLE_DIRECTORY) - return HMCDirectoryRule, details diff --git a/castervoice/asynch/hmc_rules/hmc_history_rule.py b/castervoice/asynch/hmc_rules/hmc_history_rule.py deleted file mode 100644 index b80969dcb..000000000 --- a/castervoice/asynch/hmc_rules/hmc_history_rule.py +++ /dev/null @@ -1,46 +0,0 @@ -from dragonfly import Function, MappingRule, ShortIntegerRef - -from castervoice.lib import control, settings -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -def hmc_recording_exclude(n): - control.nexus().comm.get_com("hmc").do_action("exclude", int(n)) - - -def hmc_recording_repeatable(): - control.nexus().comm.get_com("hmc").do_action("repeatable") - - -def hmc_recording_check_range(n, n2): - control.nexus().comm.get_com("hmc").do_action("check_range", [int(n), int(n2)]) - - -def hmc_checkbox(n): - # can easily check multiple boxes, use a comma-separated list of numbers instead of str(n) - control.nexus().comm.get_com("hmc").do_action("check", [int(n)]) - - -class HMCHistoryRule(MappingRule): - mapping = { - # specific to macro recorder - "check ": - R(Function(hmc_checkbox)), - "check from to ": - R(Function(hmc_recording_check_range)), - "exclude ": - R(Function(hmc_recording_exclude)), - "[make] repeatable": - R(Function(hmc_recording_repeatable)) - } - extras = [ - ShortIntegerRef("n", 1, 25), - ShortIntegerRef("n2", 1, 25), - ] - - -def get_rule(): - details = RuleDetails(name="h m c history rule", - title=settings.HMC_TITLE_RECORDING) - return HMCHistoryRule, details diff --git a/castervoice/asynch/hmc_rules/hmc_launch_rule.py b/castervoice/asynch/hmc_rules/hmc_launch_rule.py deleted file mode 100644 index d9a723562..000000000 --- a/castervoice/asynch/hmc_rules/hmc_launch_rule.py +++ /dev/null @@ -1,35 +0,0 @@ -from dragonfly import Function, MappingRule - -from castervoice.asynch.hmc import h_launch -from castervoice.lib import settings -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.actions import AsynchronousAction -from castervoice.lib.merge.state.short import R, S, L - - -def receive_settings(data): - settings.SETTINGS = data - settings.save_config() - # TODO: apply new settings - - -def settings_window(): - h_launch.launch(settings.QTTYPE_SETTINGS) - on_complete = AsynchronousAction.hmc_complete(lambda data: receive_settings(data)) - AsynchronousAction( - [L(S(["cancel"], on_complete))], - time_in_seconds=1, - repetitions=300, - blocking=False).execute() - - -class HMCLaunchRule(MappingRule): - mapping = { - "launch caster settings": - R(Function(settings_window)), - } - - -def get_rule(): - details = RuleDetails(name="settings window launcher") - return HMCLaunchRule, details diff --git a/castervoice/asynch/hmc_rules/hmc_settings_rule.py b/castervoice/asynch/hmc_rules/hmc_settings_rule.py deleted file mode 100644 index 19dac1aad..000000000 --- a/castervoice/asynch/hmc_rules/hmc_settings_rule.py +++ /dev/null @@ -1,23 +0,0 @@ -from dragonfly import Function, MappingRule - -from castervoice.asynch.hmc_rules.hmc_support import kill -from castervoice.lib import control, settings -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -def hmc_settings_complete(): - control.nexus().comm.get_com("hmc").complete() - - -class HMCSettingsRule(MappingRule): - mapping = { - "kill homunculus": R(Function(kill)), - "complete": R(Function(hmc_settings_complete)), - } - - -def get_rule(): - details = RuleDetails(name="h m c settings rule", - title=settings.SETTINGS_WINDOW_TITLE) - return HMCSettingsRule, details diff --git a/castervoice/asynch/hmc_rules/hmc_support.py b/castervoice/asynch/hmc_rules/hmc_support.py deleted file mode 100644 index a750d9ac4..000000000 --- a/castervoice/asynch/hmc_rules/hmc_support.py +++ /dev/null @@ -1,9 +0,0 @@ -from castervoice.lib import control, settings, printer - - -def kill(): - control.nexus().comm.get_com("hmc").kill() - - -if not settings.settings(["miscellaneous", "hmc"]): - printer.out("WARNING: Tk Window controls have been disabled -- this is not advised!") \ No newline at end of file diff --git a/castervoice/asynch/hud.py b/castervoice/asynch/hud.py deleted file mode 100644 index 1129be09d..000000000 --- a/castervoice/asynch/hud.py +++ /dev/null @@ -1,241 +0,0 @@ -#! python -''' -Caster HUD Window module -''' -# pylint: disable=import-error,no-name-in-module -import html -import json -import os -import signal -import sys -import threading -import dragonfly -from xmlrpc.server import SimpleXMLRPCServer -try: # Style C -- may be imported into Caster, or externally - BASE_PATH = os.path.realpath(__file__).rsplit(os.path.sep + "castervoice", 1)[0] - if BASE_PATH not in sys.path: - sys.path.append(BASE_PATH) -finally: - from castervoice.lib.merge.communication import Communicator - from castervoice.lib import settings - from castervoice.lib.qt import QtCore, QtGui, QtWidgets, qt_attr, qapp_exec - -QApplication = QtWidgets.QApplication -QMainWindow = QtWidgets.QMainWindow -QTextEdit = QtWidgets.QTextEdit -QTreeView = QtWidgets.QTreeView -QVBoxLayout = QtWidgets.QVBoxLayout -QWidget = QtWidgets.QWidget - -WINDOW_STAYS_ON_TOP_HINT = qt_attr( - QtCore, - ("Qt", "WindowStaysOnTopHint"), - ("Qt", "WindowType", "WindowStaysOnTopHint"), -) -TEXT_CURSOR_END = qt_attr( - QtGui, - ("QTextCursor", "End"), - ("QTextCursor", "MoveOperation", "End"), -) - -CLEAR_HUD_EVENT = QtCore.QEvent.Type(QtCore.QEvent.registerEventType(-1)) -HIDE_HUD_EVENT = QtCore.QEvent.Type(QtCore.QEvent.registerEventType(-1)) -SHOW_HUD_EVENT = QtCore.QEvent.Type(QtCore.QEvent.registerEventType(-1)) -HIDE_RULES_EVENT = QtCore.QEvent.Type(QtCore.QEvent.registerEventType(-1)) -SHOW_RULES_EVENT = QtCore.QEvent.Type(QtCore.QEvent.registerEventType(-1)) -SEND_COMMAND_EVENT = QtCore.QEvent.Type(QtCore.QEvent.registerEventType(-1)) - - -class RPCEvent(QtCore.QEvent): - - def __init__(self, type, text): - QtCore.QEvent.__init__(self, type) - self._text = text - - @property - def text(self): - return self._text - - -class RulesWindow(QWidget): - - _WIDTH = 600 - _MARGIN = 30 - - def __init__(self, text): - QWidget.__init__(self, f=WINDOW_STAYS_ON_TOP_HINT) - x = dragonfly.monitors[0].rectangle.dx - (RulesWindow._WIDTH + RulesWindow._MARGIN) - y = 300 - dx = RulesWindow._WIDTH - dy = dragonfly.monitors[0].rectangle.dy - (y + 2 * RulesWindow._MARGIN) - self.setGeometry(x, y, dx, dy) - self.setWindowTitle("Active Rules") - rules_tree = QtGui.QStandardItemModel() - rules_tree.setColumnCount(2) - rules_tree.setHorizontalHeaderLabels(['phrase', 'action']) - rules_dict = json.loads(text) - rules = rules_tree.invisibleRootItem() - for g in rules_dict: - gram = QtGui.QStandardItem(g["name"]) if len(g["rules"]) > 1 else None - for r in g["rules"]: - rule = QtGui.QStandardItem(r["name"]) - rule.setRowCount(len(r["specs"])) - rule.setColumnCount(2) - row = 0 - for s in r["specs"]: - phrase, _, action = s.partition('::') - rule.setChild(row, 0, QtGui.QStandardItem(phrase)) - rule.setChild(row, 1, QtGui.QStandardItem(action)) - row += 1 - if gram is None: - rules.appendRow(rule) - else: - gram.appendRow(rule) - if gram: - rules.appendRow(gram) - tree_view = QTreeView(self) - tree_view.setModel(rules_tree) - tree_view.setColumnWidth(0, RulesWindow._WIDTH // 2) - layout = QVBoxLayout() - layout.addWidget(tree_view) - self.setLayout(layout) - - -class HUDWindow(QMainWindow): - - _WIDTH = 300 - _HEIGHT = 200 - _MARGIN = 30 - - def __init__(self, server): - QMainWindow.__init__(self, flags=WINDOW_STAYS_ON_TOP_HINT) - x = dragonfly.monitors[0].rectangle.dx - (HUDWindow._WIDTH + HUDWindow._MARGIN) - y = HUDWindow._MARGIN - dx = HUDWindow._WIDTH - dy = HUDWindow._HEIGHT - self.server = server - self.setup_xmlrpc_server() - self.setGeometry(x, y, dx, dy) - self.setWindowTitle(settings.HUD_TITLE) - self.output = QTextEdit() - self.output.setReadOnly(True) - self.setCentralWidget(self.output) - self.rules_window = None - self.commands_count = 0 - - def event(self, event): - if event.type() == SHOW_HUD_EVENT: - self.show() - return True - if event.type() == HIDE_HUD_EVENT: - self.hide() - return True - if event.type() == SHOW_RULES_EVENT: - self.rules_window = RulesWindow(event.text) - self.rules_window.show() - return True - if event.type() == HIDE_RULES_EVENT and self.rules_window: - self.rules_window.close() - self.rules_window = None - return True - if event.type() == SEND_COMMAND_EVENT: - escaped_text = html.escape(event.text) - if escaped_text.startswith('$'): - formatted_text = '<{}'.format(escaped_text[1:]) - if self.commands_count == 0: - self.output.setHtml(formatted_text) - else: - # self.output.append('
') - self.output.append(formatted_text) - cursor = self.output.textCursor() - cursor.movePosition(TEXT_CURSOR_END) - self.output.setTextCursor(cursor) - self.output.ensureCursorVisible() - self.commands_count += 1 - if self.commands_count == 50: - self.commands_count = 0 - return True - if escaped_text.startswith('@'): - formatted_text = '>{}'.format(escaped_text[1:]) - elif escaped_text.startswith(''): - formatted_text = '>{}'.format(escaped_text) - else: - formatted_text = escaped_text - self.output.append(formatted_text) - self.output.ensureCursorVisible() - return True - if event.type() == CLEAR_HUD_EVENT: - self.commands_count = 0 - return True - return QMainWindow.event(self, event) - - def closeEvent(self, event): - event.accept() - - def setup_xmlrpc_server(self): - self.server.register_function(self.xmlrpc_clear, "clear_hud") - self.server.register_function(self.xmlrpc_ping, "ping") - self.server.register_function(self.xmlrpc_hide_hud, "hide_hud") - self.server.register_function(self.xmlrpc_hide_rules, "hide_rules") - self.server.register_function(self.xmlrpc_kill, "kill") - self.server.register_function(self.xmlrpc_send, "send") - self.server.register_function(self.xmlrpc_show_hud, "show_hud") - self.server.register_function(self.xmlrpc_show_rules, "show_rules") - server_thread = threading.Thread(target=self.server.serve_forever) - server_thread.daemon = True - server_thread.start() - - - def xmlrpc_clear(self): - QtCore.QCoreApplication.postEvent(self, QtCore.QEvent(CLEAR_HUD_EVENT)) - return 0 - - def xmlrpc_ping(self): - return 0 - - def xmlrpc_hide_hud(self): - QtCore.QCoreApplication.postEvent(self, QtCore.QEvent(HIDE_HUD_EVENT)) - return 0 - - def xmlrpc_show_hud(self): - QtCore.QCoreApplication.postEvent(self, QtCore.QEvent(SHOW_HUD_EVENT)) - return 0 - - def xmlrpc_hide_rules(self): - QtCore.QCoreApplication.postEvent(self, QtCore.QEvent(HIDE_RULES_EVENT)) - return 0 - - def xmlrpc_kill(self): - QApplication.quit() - - def xmlrpc_send(self, text): - QtCore.QCoreApplication.postEvent(self, RPCEvent(SEND_COMMAND_EVENT, text)) - return len(text) - - def xmlrpc_show_rules(self, text): - QtCore.QCoreApplication.postEvent(self, RPCEvent(SHOW_RULES_EVENT, text)) - return len(text) - - -def handler(signum, frame): - """ - This handler doesn't stop the application when ^C is pressed, - but it prevents exceptions being thrown when later - the application is terminated from GUI. Normally, HUD is started - by the recognition process and can't be killed from shell prompt, - in which case this handler is not needed. - """ - pass - - -if __name__ == "__main__": - signal.signal(signal.SIGINT, handler) - server_address = (Communicator.LOCALHOST, Communicator().com_registry["hud"]) - # allow_none=True means Python constant None will be translated into XML - server = SimpleXMLRPCServer(server_address, logRequests=False, allow_none=True) - app = QApplication(sys.argv) - window = HUDWindow(server) - window.show() - exit_code = qapp_exec(app) - server.shutdown() - sys.exit(exit_code) diff --git a/castervoice/asynch/hud_support.py b/castervoice/asynch/hud_support.py deleted file mode 100644 index 0974a28f4..000000000 --- a/castervoice/asynch/hud_support.py +++ /dev/null @@ -1,141 +0,0 @@ -import sys, subprocess, json, time - -from dragonfly import CompoundRule, MappingRule, get_current_engine, Function - -from pathlib import Path - -try: # Style C -- may be imported into Caster, or externally - BASE_PATH = str(Path(__file__).resolve().parent.parent) - if BASE_PATH not in sys.path: - sys.path.append(BASE_PATH) -finally: - from castervoice.lib import settings - -from castervoice.lib import printer, control, utilities -from castervoice.lib.rules_collection import get_instance - -def start_hud(): - hud = control.nexus().comm.get_com("hud") - try: - hud.ping() - except Exception: - subprocess.Popen([settings.SETTINGS["paths"]["PYTHONW"], - settings.SETTINGS["paths"]["HUD_PATH"]]) - - -def show_hud(): - hud = control.nexus().comm.get_com("hud") - try: - hud.show_hud() - except Exception as e: - printer.out("Unable to show hud. Hud not available. \n{}".format(e)) - - -def hide_hud(): - hud = control.nexus().comm.get_com("hud") - try: - hud.hide_hud() - except Exception as e: - printer.out("Unable to hide hud. Hud not available. \n{}".format(e)) - - -def clear_hud(): - hud = control.nexus().comm.get_com("hud") - try: - hud.clear_hud() - except Exception as e: - printer.out("Unable to clear hud. Hud not available. \n{}".format(e)) - # clear cmd output if hud unavailable - Function(utilities.clear_log).execute() - - -def show_rules(): - """ - Get a list of active grammars loaded into the current engine, - including active rules and their attributes. Send the list - to HUD GUI for display. - """ - grammars = [] - engine = get_current_engine() - for grammar in engine.grammars: - if any([r.active for r in grammar.rules]): - rules = [] - for rule in grammar.rules: - if rule.active and not rule.name.startswith('_'): - if isinstance(rule, CompoundRule): - specs = [rule.spec] - elif isinstance(rule, MappingRule): - specs = sorted(["{}::{}".format(x, rule._mapping[x]) for x in rule._mapping]) - else: - specs = [rule.element.gstring()] - rules.append({ - "name": rule.name, - "exported": rule.exported, - "specs": specs - }) - grammars.append({"name": grammar.name, "rules": rules}) - grammars.extend(get_instance().serialize()) - hud = control.nexus().comm.get_com("hud") - try: - hud.show_rules(json.dumps(grammars)) - except Exception as e: - printer.out("Unable to show hud. Hud not available. \n{}".format(e)) - -def hide_rules(): - """ - Instruct HUD to hide the frame with the list of rules. - """ - hud = control.nexus().comm.get_com("hud") - try: - hud.hide_rules() - except Exception as e: - printer.out("Unable to show hud. Hud not available. \n{}".format(e)) - - -class HudPrintMessageHandler(printer.BaseMessageHandler): - """ - Hud message handler which prints formatted messages to the gui Hud. - Add symbols as the 1st character in strings utilizing printer.out - - @ Purple arrow - Bold Text - Important Info - # Red arrow - Plain text - Caster Info - $ Blue arrow - Plain text - Commands/Dictation - """ - - def __init__(self): - super(HudPrintMessageHandler, self).__init__() - self.hud = control.nexus().comm.get_com("hud") - self.is_hud_active = False - - if get_current_engine().name != "text": - # Retry loop to handle the cold-boot race condition - max_retries = 10 - for attempt in range(max_retries): - try: - self.hud.ping() # HUD running? - self.is_hud_active = True - break # Connection successful, break out of loop - except Exception as e: - if attempt < max_retries - 1: - time.sleep(0.5) # Wait 500ms before next attempt - else: - # Log failure if it still won't connect after 5 seconds - self.is_hud_active = False - printer.out("Hud not available after {} retries. \n{}".format(max_retries, e)) - - def handle_message(self, items): - if self.is_hud_active is True: - # The timeout with the hud can interfere with the dragonfly speech recognition loop. - # This appears as a stutter in recognition. - # This stutter only happens to end user once, while self.hud.ping() is executing. - # is_hud_active is False if the hud is not available/text engine - # TODO: handle raising exception gracefully - try: - self.hud.send("\n".join([str(m) for m in items])) - except Exception as e: - # If an exception, print is managed by SimplePrintMessageHandler - self.is_hud_active = False - printer.out("Hud not available. \n{}".format(e)) - raise("") # pylint: disable=raising-bad-type - else: - raise("") # pylint: disable=raising-bad-type \ No newline at end of file diff --git a/castervoice/asynch/mouse/__init__.py b/castervoice/asynch/mouse/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/asynch/mouse/grids.py b/castervoice/asynch/mouse/grids.py deleted file mode 100644 index 753a89da6..000000000 --- a/castervoice/asynch/mouse/grids.py +++ /dev/null @@ -1,563 +0,0 @@ -import getopt -import os -import signal -import sys -import threading as th -from dragonfly import monitors - -from xmlrpc.server import SimpleXMLRPCServer -import tkinter as tk - -try: # Style C -- may be imported into Caster, or externally - BASE_PATH = os.path.realpath(__file__).rsplit(os.path.sep + "castervoice", 1)[0] - if BASE_PATH not in sys.path: - sys.path.append(BASE_PATH) -finally: - from castervoice.lib import settings, utilities - from castervoice.lib.actions import Mouse - from castervoice.lib.contexts import is_linux - from castervoice.lib.merge.communication import Communicator - settings.initialize() - -if is_linux(): - from tkinter import ttk,font - -from PIL import ImageGrab, ImageTk, ImageDraw, ImageFont - - -class Dimensions: - def __init__(self, w, h, x, y): - self.width = w - self.height = h - self.x = x - self.y = y - - -# rewrite dp grid using this -class TkTransparent(tk.Tk): - def reset_xs_ys(self): - self.xs = [] - self.ys = [] - - def xs_ys_filled(self): - return len(self.xs) > 0 or len(self.ys) > 0 - - def get_dimensions_fullscreen(self): - return Dimensions(self.winfo_screenwidth(), self.winfo_screenheight(), 0, 0) - - def get_dimensions_string(self): - return "%dx%d+%d+%d" % (self.dimensions.width, self.dimensions.height, - self.dimensions.x, self.dimensions.y) - - def __init__(self, name, dimensions=None, canvas=True): - tk.Tk.__init__(self, baseName="") - self.setup_xmlrpc_server() - if not dimensions: - dimensions = self.get_dimensions_fullscreen() - self.dimensions = dimensions - self.reset_xs_ys() - self.overrideredirect(True) - self.resizable(False, False) - self.wm_attributes("-topmost", True) - self.wait_visibility(self) - self.attributes("-alpha", 0.5) - self.wm_title(name) - self.wm_geometry(self.get_dimensions_string()) - if canvas: - self._canvas = tk.Canvas( - master=self, - width=dimensions.width, - height=dimensions.height, - bg='white', - bd=-2) - self._canvas.pack() - self.protocol("WM_DELETE_WINDOW", self.xmlrpc_kill) - - # self.bind("", self.key) - # self.mainloop()#do this in the child classes - def start_server(): - self.server.serve_forever() - - th.Timer(1, start_server).start() - - def setup_xmlrpc_server(self): - comm = Communicator() - self.server = SimpleXMLRPCServer( - (Communicator.LOCALHOST, comm.com_registry["grids"]), - logRequests=False, allow_none=True) - self.server.register_function(self.xmlrpc_kill, "kill") - - def pre_redraw(self): - '''gets the window ready to be redrawn''' - self.deiconify() - self._canvas.delete("all") - - def unhide(self): - '''''' - self.deiconify() - self.lift() - - def hide(self): - self.withdraw() - - def xmlrpc_kill(self): - self.after(10, self.die) - - def die(self): - self.server.shutdown() - self.destroy() - os.kill(os.getpid(), signal.SIGTERM) - - @staticmethod - def move_mouse(mx, my): - Mouse("[{}, {}]".format(mx, my)).execute() - - -class RainbowGrid(TkTransparent): - def __init__(self, grid_size=None, square_size=None, square_alpha=None): - '''square_size is an integer''' - TkTransparent.__init__(self, settings.RAINBOW_TITLE, grid_size) - self.attributes("-alpha", 0.5) - self.square_size = square_size if square_size else 37 - self.square_alpha = square_alpha if square_alpha else 125 - self.colors = [ - (255, 0, 0, self.square_alpha), # red - (187, 122, 0, self.square_alpha), # orange 255, 165, 0 - (255, 255, 0, self.square_alpha), # yellow - (0, 128, 0, self.square_alpha), # green - (0, 0, 125, self.square_alpha), # blue - (128, 0, 128, self.square_alpha) # purple - ] - self.position_index = None - - self.info_pre = 0 - self.info_color = 0 - self.info_num = 0 - - self.refresh() - self.mainloop() - - def refresh(self): - '''thread safe''' - if not sys.platform.startswith("linux"): - # When the grid is hidden on Linux it fails to draw on the correct monitor - self.hide() - self.after(10, self.draw) - - def finalize(self): - self.imgtk = ImageTk.PhotoImage(self.img) - self._canvas.create_image( - self.dimensions.width/2, self.dimensions.height/2, image=self.imgtk) - - def setup_xmlrpc_server(self): - TkTransparent.setup_xmlrpc_server(self) - self.server.register_function(self.xmlrpc_move_mouse, "move_mouse") - - def xmlrpc_move_mouse(self, pre, color, num): - if pre > 0: - pre -= 1 - selected_index = self.position_index[color + pre*len(self.colors)][num] - self.move_mouse(selected_index[0] + self.dimensions.x, - selected_index[1] + self.dimensions.y) - - def fill_xs_ys(self): - # only figure out the coordinates of the lines once - if not self.xs_ys_filled(): - for x in range(0, int(self.dimensions.width/self.square_size) + 2): - self.xs.append(x*self.square_size) - for y in range(0, int(self.dimensions.height/self.square_size) + 2): - self.ys.append(y*self.square_size) - self.position_index = [] - # add first "color": - self.position_index.append([]) - - def draw(self): - self.pre_redraw() - self.img = ImageGrab.grab([ - self.dimensions.x, self.dimensions.y, - self.dimensions.x + self.dimensions.width, - self.dimensions.y + self.dimensions.height - ]) # .filter(ImageFilter.BLUR) - self.draw_squares() - self.finalize() - self.unhide() - - def draw_squares(self): - self.fill_xs_ys() - # - - text_background_buffer = int(self.square_size/6) - xs_size = len(self.xs) - ys_size = len(self.ys) - box_number = 0 - colors_index = 0 - if is_linux(): - font = ImageFont.truetype("FreeMono.ttf", 15) - else: - font = ImageFont.truetype("arialbd.ttf", 15) - draw = ImageDraw.Draw(self.img, 'RGBA') - - for ly in range(0, ys_size - 1): - for lx in range(0, xs_size - 1): - txt = str(box_number) - tw, th = draw.textsize(txt, font) - text_x = int((self.xs[lx] + self.xs[lx + 1] - tw)/2) + 1 - text_y = int((self.ys[ly] + self.ys[ly + 1] - th)/2) - 1 - draw.rectangle( - [ - self.xs[lx] + text_background_buffer, - self.ys[ly] + text_background_buffer, - self.xs[lx + 1] - text_background_buffer, - self.ys[ly + 1] - text_background_buffer - ], - fill=self.colors[colors_index], - outline=False) - - draw.text((text_x + 1, text_y + 1), txt, (0, 0, 0), font=font) - draw.text((text_x - 1, text_y + 1), txt, (0, 0, 0), font=font) - draw.text((text_x + 1, text_y - 1), txt, (0, 0, 0), font=font) - draw.text((text_x - 1, text_y - 1), txt, (0, 0, 0), font=font) - draw.text((text_x, text_y), txt, (255, 255, 255), font=font) - # index the position - self.position_index[len(self.position_index) - 1].append( - (int((self.xs[lx] + self.xs[lx + 1])/2), - int((self.ys[ly] + self.ys[ly + 1])/2))) - - # update for next iteration - box_number += 1 - if box_number == 100: - # next color - box_number = 0 - colors_index += 1 - colors_index %= len(self.colors) # cycle colors - self.position_index.append([]) - - del draw - - -class DouglasGrid(TkTransparent): - def __init__(self, grid_size=None, square_size=None): - TkTransparent.__init__(self, settings.DOUGLAS_TITLE, grid_size) - self.square_size = square_size if square_size else 25 - - self.draw() - self.mainloop() - - def setup_xmlrpc_server(self): - TkTransparent.setup_xmlrpc_server(self) - self.server.register_function(self.xmlrpc_move_mouse, "move_mouse") - - def xmlrpc_move_mouse(self, x, y): - DouglasGrid.move_mouse( - x*self.square_size + int(self.square_size/2) + self.dimensions.x, - y*self.square_size + int(self.square_size/2) + self.dimensions.y) - - def draw(self): - self.pre_redraw() - self.draw_lines_and_numbers() - self.unhide() - - def fill_xs_ys(self): - # only figure out the coordinates of the lines once - if not self.xs_ys_filled(): - for x in range(0, int(self.dimensions.width/self.square_size) + 2): - self.xs.append(x*self.square_size) - for y in range(0, int(self.dimensions.height/self.square_size)): - self.ys.append(y*self.square_size) - - def draw_lines_and_numbers(self): - - self.fill_xs_ys() - - text_background_buffer = int(self.square_size/10) - xs_size = len(self.xs) - for lx in range(0, xs_size): - fill = "black" - if lx % 3: - fill = "gray" - self._canvas.create_line( - self.xs[lx], 0, self.xs[lx], self.dimensions.height, fill=fill) - if lx + 1 < xs_size: - self._canvas.create_rectangle( - self.xs[lx] + text_background_buffer, - 0 + text_background_buffer, - self.xs[lx + 1] - text_background_buffer, - self.square_size - text_background_buffer, - fill='Black') - self._canvas.create_rectangle( - self.xs[lx] + text_background_buffer, - self.dimensions.height - self.square_size + text_background_buffer, - self.xs[lx + 1] - text_background_buffer, - self.dimensions.height - text_background_buffer, - fill='Black') - text_x = int((self.xs[lx] + self.xs[lx + 1])/2) - self._canvas.create_text( - text_x, - int(self.square_size/2), - text=str(lx), - font="Arial 10 bold", - fill='White') - self._canvas.create_text( - text_x, - self.dimensions.height - int(self.square_size/2), - text=str(lx), - font="Arial 10 bold", - fill='White') - - ys_size = len(self.ys) - for ly in range(0, ys_size): - fill = "black" - if ly % 3: - fill = "gray" - self._canvas.create_line( - 0, self.ys[ly], self.dimensions.width, self.ys[ly], fill=fill) - if ly + 1 < ys_size and ly != 0: - self._canvas.create_rectangle( - 0 + text_background_buffer, - self.ys[ly] + text_background_buffer, - self.square_size - text_background_buffer, - self.ys[ly + 1] - text_background_buffer, - fill='Black') - self._canvas.create_rectangle( - self.dimensions.width - self.square_size + text_background_buffer, - self.ys[ly] + text_background_buffer, - self.dimensions.width - text_background_buffer, - self.ys[ly + 1] - text_background_buffer, - fill='Black') - text_y = int((self.ys[ly] + self.ys[ly + 1])/2) - self._canvas.create_text( - int(self.square_size/2), - text_y, - text=str(ly), - font="Arial 10 bold", - fill='White') - self._canvas.create_text( - self.dimensions.width - int(self.square_size/2), - text_y, - text=str(ly), - font="Arial 10 bold", - fill='White') - - -''' -Divide screen into grid of 3 x 3 squares and assign each one a number. - The user can specify a square number and further refine the selection - with one of the numbers from 1 to 9. -''' -class SudokuGrid(TkTransparent): - def __init__(self, grid_size=None, square_size=32): - TkTransparent.__init__(self, settings.SUDOKU_TITLE, grid_size) - - screen_w = self.dimensions.width - screen_h = self.dimensions.height - - self.square_width = square_size - while (screen_w % self.square_width != 0): - self.square_width -= 1 - - self.square_height = square_size - while (screen_h % self.square_height != 0): - self.square_height -= 1 - - self.width = int(screen_w / self.square_width) - self.height = int(screen_h / self.square_height) - self.num_squares = self.width * self.height - self.up_w = int((self.width - 1) / 3 + 1) * 3 - self.up_h = int((self.height - 1) / 3 + 1) * 3 - self.down_w = (int(self.up_w / 3) - 1) * 3 - self.down_h = (int(self.up_h / 3) - 1) * 3 - - # Put this in a try so we don't freeze if draw fails - try: - self.draw() - finally: - try: - self.mainloop() - except KeyboardInterrupt: - self.server.shutdown() - - def click(self): - Mouse("left:1").execute() - - # Set up the RPC server - def setup_xmlrpc_server(self): - TkTransparent.setup_xmlrpc_server(self) - self.server.register_function(self.xmlrpc_move_mouse, "move_mouse") - self.server.register_function(self.xmlrpc_get_mouse_pos, "get_mouse_pos") - - # RPC function to move the mouse using screen number and inner number - # n1 - the screen number from 1 to m - # n2 - inner number from 1 to 9 - def xmlrpc_move_mouse(self, n1, n2): - x, y = self.get_mouse_pos(n1, n2) - self.move_mouse(x + self.dimensions.x, y + self.dimensions.y) - - # RPC function to get the mouse position from screen number and inner number - # n1 - the screen number from 1 to m - # n2 - inner number from 1 to 9 - def xmlrpc_get_mouse_pos(self, n1, n2): - return self.get_mouse_pos(n1, n2) - - # Draw the grid on screen - def draw(self): - self.pre_redraw() - self.draw_lines_and_numbers() - self.unhide() - - # Get the mouse position from screen number and enter number - # n1 - the screen number from 1 to m - # n2 - inner number from 1 to 9 - def get_mouse_pos(self, n1, n2): - sq = self.num_to_square(n1) - sq_refined = self.get_refined_square(sq, n2) - return self.square_to_pos(self.fit_to_screen(sq_refined)) - - # Modify the square based on the inner number - # sq - square number - # n2 - inner number from 1 to 9 - def get_refined_square(self, sq, n2): - if n2 != 0 and n2 != 5: - n2 -= 1 - - # We use the rounded up width because this is the unadjusted square - x = n2 % 3 - y = int(n2 / 3) - - sq += (x - 1) + (y - 1) * self.up_w - - return sq - - # Convert screen number to position on screen - # n - the screen number from 1 to m - def num_to_pos(self, n): - # The number of squares is based on the rounded-up width and height - num_squares = self.up_w * self.up_h - - # If the number is out of range, fix it - if n < 1: - n = 1 - elif n >= int(num_squares / 9): - n = int(num_squares / 9) - - sq = self.num_to_square(n) - - return self.square_to_pos(self.fit_to_screen(sq)) - - # Adjust the square number if current square is offscreen - # sq - square number - def fit_to_screen(self, sq): - up_x = sq % self.up_w - up_y = int(sq / self.up_w) - - # adjust square if offscreen - if up_x >= self.width: - up_x = self.width - 1 - if up_y >= self.height: - up_y = self.height - 1 - - return up_x + up_y * self.width - - # Convert a screen number to an internal square number - # n - the screen number from 1 to m - def num_to_square(self, n): - # decrement screen number to make 0 to m-1 - n -= 1 - - # Use the rounded up width because the center square may be off screen - up_x = n % int(self.up_w / 3) - up_y = int(n / (self.up_w / 3)) - - sq = (up_x * 3 + 1) + ((up_y * 3 + 1) * self.up_w) - - return sq - - # Convert a square number to a screen position - # sq - square number - def square_to_pos(self, sq): - x, y = self.square_to_xy(sq) - return (int((x + 0.5) * self.square_width), - int((y + 0.5) * self.square_height)) - - # Convert square number to screen number - # sq - square number - def square_to_num(self, sq): - x, y = self.square_to_xy(sq) - - n = int(x / 3) + int(y / 3) * int(self.up_w / 3) - - # increment for 1... - return n + 1 - - # Convert a square number to grid coordinates - # sq - square number - def square_to_xy(self, sq): - x = sq % self.width - y = int(sq / self.width) - return x, y - - # Draw grid on background - def draw_lines_and_numbers(self): - canvas = self._canvas - - # Iterate over logical grid of squares - for sq in range(self.num_squares): - x, y = self.square_to_xy(sq) - screen_x = x * self.square_width - screen_y = y * self.square_height - - fill = "black" - if sq % 3: - fill = "gray" - - # draw vertical grid lines - if x > 0 and sq <= self.width: - canvas.create_line( - screen_x, 0, screen_x, self.dimensions.height, fill=fill) - - # draw horizontal grid lines - if x == 0: - canvas.create_line( - 0, screen_y, self.dimensions.width, screen_y, fill=fill) - - # draw number - if (x % 3 == 1 or x == self.width - 1) and (y % 3 == 1 or y == self.height - 1): - n = self.square_to_num(sq) - pos = self.num_to_pos(n) - canvas.create_text(pos[0], pos[1], text=str(n), - font="TkFixedFont 14", fill='Black') - - -# Main function -def main(argv): - help_message = 'Usage: grids.py -g [-m ]\n where is one of:\n r\trainbow grid\n d\tdouglas grid\n s\tsudoku grid' - try: - opts, args = getopt.getopt(argv, "hg:m:") - except getopt.GetoptError: - print(help_message) - sys.exit(2) - - g = None - m = 1 - for opt, arg in opts: - if opt == '-h': - print(help_message) - sys.exit() - elif opt == '-g': - if arg == "r": - g = RainbowGrid - elif arg == 'd': - g = DouglasGrid - elif arg == 's': - g = SudokuGrid - elif opt == '-m': - m = arg - - if g is None: - raise ValueError("Grid mode not specified.") - r = monitors[int(m) - 1].rectangle - grid_size = Dimensions(int(r.dx), int(r.dy), int(r.x), int(r.y)) - g(grid_size=grid_size) - - -if __name__ == '__main__': - main(sys.argv[1:]) diff --git a/castervoice/asynch/mouse/legion.py b/castervoice/asynch/mouse/legion.py deleted file mode 100644 index 4789cfaa8..000000000 --- a/castervoice/asynch/mouse/legion.py +++ /dev/null @@ -1,261 +0,0 @@ -from builtins import str - -import getopt -import os -import re -import sys -import threading -import locale -from ctypes import * -from dragonfly import monitors - -try: # Style C -- may be imported into Caster, or externally - BASE_PATH = os.path.realpath(__file__).rsplit(os.path.sep + "castervoice", 1)[0] - if BASE_PATH not in sys.path: - sys.path.append(BASE_PATH) -finally: - from castervoice.asynch.mouse.grids import TkTransparent, Dimensions - from castervoice.lib import settings, utilities - settings.initialize() - -from pathlib import Path - -from PIL import ImageGrab, ImageFilter, Image -''' -The screen will be divided into vertical columns of equal width. -The width of each Legion box cannot exceed the width of the column. -This way relative partitioning is achieved since larger resolutions -will be partitioned into columns of larger width. -''' - - -class Rectangle: - y1 = None - y2 = None - x1 = None - x2 = None - - -class LegionGrid(TkTransparent): - def __init__(self, grid_size=None, tirg=None, auto_quit=False): - self.setup_xmlrpc_server() - TkTransparent.__init__(self, settings.LEGION_TITLE, grid_size) - self.attributes("-alpha", 0.7) - self.max_rectangle_width = int( - grid_size.width/settings.SETTINGS["miscellaneous"]["legion_vertical_columns"]) - self.tirg_positions = {} - if tirg is not None: - self.process_rectangles(tirg) - self.draw_tirg_squares() - - self.mainloop() - - def setup_xmlrpc_server(self): - TkTransparent.setup_xmlrpc_server(self) - self.server.register_function(self.xmlrpc_retrieve_data_hlight, - "retrieve_data_for_highlight") - self.server.register_function(self.xmlrpc_go, "go") - - def xmlrpc_go(self, index): - self.move_mouse( - int(self.tirg_positions[index][0] + self.dimensions.x), - int(self.tirg_positions[index][1] + self.dimensions.y)) - - def xmlrpc_retrieve_data_hlight(self, strindex): - if strindex in self.tirg_positions: - position_data = self.tirg_positions[strindex] - return { - "l": position_data[2] + self.dimensions.x, - "r": position_data[3] + self.dimensions.x, - "y": position_data[1] + self.dimensions.y - } - else: - return {"err": strindex + " not in map"} - - def process_rectangles(self, tirg_string): - self.tirg_rectangles = [] - if tirg_string.endswith(","): - tirg_string = tirg_string[:-1] - tirg_list = tirg_string.split(",") - curr_rect = None - for i in range(0, len(tirg_list)): - ii = i % 4 - if ii == 0: - curr_rect = Rectangle() - curr_rect.x1 = int(tirg_list[i]) - elif ii == 1: - curr_rect.y1 = int(tirg_list[i]) - elif ii == 2: - curr_rect.x2 = int(tirg_list[i]) - elif ii == 3: - curr_rect.y2 = int(tirg_list[i]) - self.tirg_rectangles.append(curr_rect) - self.split_rectangles() - - def split_rectangles(self): - # Split larger rectangles into smaller ones to allow greater precision. - rectangles_to_split = [] - for rect in self.tirg_rectangles: # Collect all the rectangles that are too large. - if rect.x2 - rect.x1 >= self.max_rectangle_width: - rectangles_to_split.append(rect) - self.tirg_rectangles = [ - x for x in self.tirg_rectangles if x not in rectangles_to_split - ] # Remove large rectangles. - self.perform_split(rectangles_to_split) - - def perform_split(self, rectangles_to_split): - # Helper class for splitting larger rectangles to smaller ones. - for rect in rectangles_to_split: - width = rect.x2 - rect.x1 - pieces = width//self.max_rectangle_width - new_width = width/pieces - for i in range(0, pieces): - r = Rectangle() - r.x1 = rect.x1 + new_width*i - r.y1 = rect.y1 - r.x2 = r.x1 + new_width - r.y2 = rect.y2 - self.tirg_rectangles.append(r) - - def draw(self): - ''' or self.server.has_rect_update''' - self.pre_redraw() - self.draw_tirg_squares() - self.unhide() - - def draw_tirg_squares(self): - '''''' - font = "Arial 12 bold" - fill_inner = "Orange" - fill_outer = "Black" - rect_num = 0 - for rect in self.tirg_rectangles: - center_x = int((rect.x1 + rect.x2)/2) - center_y = int((rect.y1 + rect.y2)/2) - label = str(rect_num) - # lines - self._canvas.create_line(rect.x1, rect.y1, rect.x2, rect.y1, fill=fill_inner) - self._canvas.create_line(rect.x1, rect.y2, rect.x2, rect.y2, fill=fill_inner) - self._canvas.create_line(rect.x1, rect.y1, rect.x1, rect.y2, fill=fill_inner) - self._canvas.create_line(rect.x2, rect.y1, rect.x2, rect.y2, fill=fill_inner) - - # text - self._canvas.create_text( - center_x + 1, center_y + 1, text=label, font=font, fill=fill_outer) - self._canvas.create_text( - center_x - 1, center_y + 1, text=label, font=font, fill=fill_outer) - self._canvas.create_text( - center_x + 1, center_y - 1, text=label, font=font, fill=fill_outer) - self._canvas.create_text( - center_x - 1, center_y - 1, text=label, font=font, fill=fill_outer) - self._canvas.create_text( - center_x, center_y, text=label, font=font, fill=fill_inner) - '''rect.x1, rect.x2 are now being saved below for the highlight function''' - self.tirg_positions[label] = (center_x, center_y, rect.x1, rect.x2) - rect_num += 1 - - -class LegionScanner: - def __init__(self): - # setup dll - self.tirg_dll = None - self.setup_dll() - - self.lock = threading.Lock() - self.last_signature = None - self.screen_has_changed = False - - def setup_dll(self): - import sys - import struct - try: - if struct.calcsize("P") * 8 == 32: - self.tirg_dll = cdll.LoadLibrary(str(Path(settings.SETTINGS["paths"]["DLL_PATH"]).joinpath("tirg-32.dll"))) - else: - self.tirg_dll = cdll.LoadLibrary(str(Path(settings.SETTINGS["paths"]["DLL_PATH"]).joinpath("tirg-64.dll"))) - except Exception as e: - print("Legion loading failed with '%s'" % str(e)) - self.tirg_dll.getTextBBoxesFromFile.argtypes = [c_char_p, c_int, c_int] - self.tirg_dll.getTextBBoxesFromFile.restype = c_char_p - self.tirg_dll.getTextBBoxesFromBytes.argtypes = [c_char_p, c_int, c_int] - self.tirg_dll.getTextBBoxesFromBytes.restype = c_char_p - - def tirg_scan(self, img): - bbstring = self.tirg_dll.getTextBBoxesFromBytes(img.tobytes(), img.size[0], - img.size[1]) - # clean the results in case any garbage letters come through - result = re.sub("[^0-9,]", "", str(bbstring)) - return result - - def scan(self, bbox=None, rough=True): - img = ImageGrab.grab(bbox, all_screens=True) - if rough: - factor = settings.SETTINGS["miscellaneous"]["legion_downscale_factor"] - if str(factor) == "auto": - # Choose a fixed "rough" final size that will work in most circumstances - factor = min(1500 / float(img.size[0]), 1) - new_size = (img.size[0]*factor, img.size[1]*factor) - img.thumbnail(new_size) - - img = img.filter(ImageFilter.FIND_EDGES) - result = self.tirg_scan(img) - if rough: - result = result.split(",") - result = list(filter(None, result)) # Removes empty items - result= [int(float(i)/factor) for i in result] - result = ",".join(str(bit) for bit in result) - - if result != self.last_signature: - with self.lock: - self.last_signature = result - self.screen_has_changed = True - # do rectangle scans here - - def get_update(self): - with self.lock: - if self.screen_has_changed: - self.screen_has_changed = False - return self.last_signature, None # None should be replaced with rectangle scan results - else: - return None - - -def main(argv): - help_message = 'legion.py -t [-m ] [-d ] [-a ]' - tirg = None - monitor = 1 - dimensions = None - auto_quit = False - - try: - opts, args = getopt.getopt(argv, "ht:a:d:m:", - ["tirg=", "dimensions=", "autoquit="]) - except getopt.GetoptError: - print(help_message) - sys.exit(2) - try: - for opt, arg in opts: - if opt == '-h': - print(help_message) - sys.exit() - elif opt in ("-t", "--tirg"): - tirg = arg - elif opt == '-m': - monitor = arg - elif opt in ("-d", "--dimensions"): - # wxh+x+y - dimensions = Dimensions(*[int(n) for n in arg.split("_")]) - elif opt in ("-a", "--autoquit"): - auto_quit = arg in ("1", "t") - - if dimensions is None: - r = monitors[int(monitor) - 1].rectangle - dimensions = Dimensions(int(r.dx), int(r.dy), int(r.x), int(r.y)) - - lg = LegionGrid(grid_size=dimensions, tirg=tirg, auto_quit=auto_quit) - except Exception: - utilities.simple_log(True) - - -if __name__ == "__main__": - main(sys.argv[1:]) diff --git a/castervoice/asynch/settingswindow.py b/castervoice/asynch/settingswindow.py deleted file mode 100644 index 0fc76db3f..000000000 --- a/castervoice/asynch/settingswindow.py +++ /dev/null @@ -1,256 +0,0 @@ -import numbers -import os -import sys -import threading - -from xmlrpc.server import SimpleXMLRPCServer - -try: # Style C -- may be imported into Caster, or externally - BASE_PATH = os.path.realpath(__file__).rsplit(os.path.sep + "castervoice", 1)[0] - if BASE_PATH not in sys.path: - sys.path.append(BASE_PATH) -finally: - from castervoice.lib import printer - from castervoice.lib import settings - from castervoice.lib.merge.communication import Communicator - -from castervoice.lib.qt import QtCore, QtGui, QtWidgets, qt_attr, qapp_exec - -QPalette = QtGui.QPalette -QApplication = QtWidgets.QApplication -QDialogButtonBox = QtWidgets.QDialogButtonBox -QCheckBox = QtWidgets.QCheckBox -QDialog = QtWidgets.QDialog -QFormLayout = QtWidgets.QFormLayout -QGroupBox = QtWidgets.QGroupBox -QLabel = QtWidgets.QLabel -QLineEdit = QtWidgets.QLineEdit -QScrollArea = QtWidgets.QScrollArea -QTabWidget = QtWidgets.QTabWidget -QVBoxLayout = QtWidgets.QVBoxLayout -QWidget = QtWidgets.QWidget - - - -settings.initialize() -DICT_SETTING = 1 -STRING_SETTING = 2 -STRING_LIST_SETTING = 4 -NUMBER_LIST_SETTING = 8 -NUMBER_SETTING = 16 -BOOLEAN_SETTING = 32 - -KEY_META = qt_attr(QtCore, ("Qt", "Key_Meta"), ("Qt", "Key", "Key_Meta")) -KEY_CONTROL = qt_attr(QtCore, ("Qt", "Key_Control"), ("Qt", "Key", "Key_Control")) -KEY_TAB = qt_attr(QtCore, ("Qt", "Key_Tab"), ("Qt", "Key", "Key_Tab")) - -CONTROL_KEY = int(KEY_META if sys.platform == "darwin" else KEY_CONTROL) -TAB_KEY = int(KEY_TAB) -SHIFT_TAB_KEY = TAB_KEY + 1 - -KEY_RELEASE_EVENT = qt_attr(QtCore, ("QEvent", "KeyRelease"), ("QEvent", "Type", "KeyRelease")) -PALETTE_MID = qt_attr(QtGui, ("QPalette", "Mid"), ("QPalette", "ColorRole", "Mid")) -FORM_GROW_ALL_NON_FIXED = qt_attr( - QtWidgets, - ("QFormLayout", "AllNonFixedFieldsGrow"), - ("QFormLayout", "FieldGrowthPolicy", "AllNonFixedFieldsGrow"), -) - -RPC_COMPLETE_EVENT = QtCore.QEvent.Type(QtCore.QEvent.registerEventType(-1)) - - -class Field: - def __init__(self, widget, original, text_type=None): - self.children = [] - self.widget = widget - self.original = original - self.text_type = text_type - - def add_child(self, field): - self.children.append(field) - - -class SettingsDialog(QDialog): - - def __init__(self, server): - QDialog.__init__(self, None) - self.modifier = 0 - self.server = server - self.setup_xmlrpc_server() - self.completed = False - self.fields = [] - self.tabs = QTabWidget() - for top in sorted(settings.SETTINGS.keys()): # pylint: disable=no-member - self.tabs.addTab(self.make_tab(top), top) - buttons = QDialogButtonBox( - QDialogButtonBox.StandardButtons((int(QDialogButtonBox.StandardButton.Ok) | - int(QDialogButtonBox.StandardButton.Cancel)))) - buttons.accepted.connect(self.accept) # pylint: disable=no-member - buttons.rejected.connect(self.reject) # pylint: disable=no-member - mainLayout = QVBoxLayout() - mainLayout.addWidget(self.tabs) - mainLayout.addWidget(buttons) - self.setLayout(mainLayout) - self.setWindowTitle(settings.SETTINGS_WINDOW_TITLE + - settings.SOFTWARE_VERSION_NUMBER) - self.expiration = threading.Timer(300, self.xmlrpc_kill) - self.expiration.start() - - def event(self, event): - if event.type() == KEY_RELEASE_EVENT: - if self.modifier == 1: - curr = self.tabs.currentIndex() - tabs_count = self.tabs.count() - if event.key() == TAB_KEY: - next = curr + 1 - next = 0 if next == tabs_count else next - self.tabs.setCurrentIndex(next) - return True - elif event.key() == SHIFT_TAB_KEY: - next = curr - 1 - next = tabs_count - 1 if next == -1 else next - self.tabs.setCurrentIndex(next) - return True - elif event.type() == RPC_COMPLETE_EVENT: - self.completed = True - self.hide() - return True - return QDialog.event(self, event) - - def keyPressEvent(self, event): - if event.key() == CONTROL_KEY: - self.modifier |= 1 - QDialog.keyPressEvent(self, event) - - def keyReleaseEvent(self, event): - if event.key() == CONTROL_KEY: - self.modifier &= ~1 - QDialog.keyReleaseEvent(self, event) - - def make_tab(self, title): - area = QScrollArea() - field = Field(area, title) - area.setBackgroundRole(PALETTE_MID) - area.setWidgetResizable(True) - area.setWidget(self.add_fields(self, title, field)) - self.fields.append(field) - return area - - def add_fields(self, parent, title, field): - tab = QWidget(parent) - form = QFormLayout() - form.setFieldGrowthPolicy(FORM_GROW_ALL_NON_FIXED) - for label in sorted(settings.SETTINGS[title].keys()): - value = settings.SETTINGS[title][label] - subfield = Field(None, label) - subfield.widget = self.field_from_value(tab, value, subfield) - form.addRow(QLabel(label), subfield.widget) - field.add_child(subfield) - tab.setLayout(form) - return tab - - def field_from_value(self, parent, value, field): - if isinstance(value, bool): - item = QCheckBox('') - item.setChecked(value) - return item - if isinstance(value, str): - field.text_type = STRING_SETTING - return QLineEdit(value) - if isinstance(value, numbers.Real): - field.text_type = NUMBER_SETTING - return QLineEdit(str(value)) - if isinstance(value, list): - if isinstance(value[0], str): - field.text_type = STRING_LIST_SETTING - return QLineEdit(", ".join(value)) - elif isinstance(value[0], numbers.Real): - field.text_type = NUMBER_LIST_SETTING - return QLineEdit(", ".join((str(x) for x in value))) - if isinstance(value, dict): - subpage = QGroupBox(parent) - form = QFormLayout() - for label in sorted(value.keys()): - subfield = Field(None, label) - subfield.widget = self.field_from_value(subpage, value[label], subfield) - field.add_child(subfield) - form.addRow(QLabel(label), subfield.widget) - subpage.setLayout(form) - return subpage - # This is left for bug reporting purposes. - printer.out("{} was not assigned to {} because type {} is unknown.".format(value, parent, type(value))) - return None - - def tree_to_dictionary(self, t=None): - d = {} - children = self.fields if t is None else t.children - for field in children: - value = None - if isinstance(field.widget, QLineEdit): - value = field.widget.text() - if field.text_type == STRING_LIST_SETTING: - d[field.original] = [ - x for x in value.replace(", ", ",").split(",") if x - ] # don't count empty strings - elif field.text_type == NUMBER_LIST_SETTING: - temp_list = ( - float(x) for x in value.replace(", ", ",").split(",") if x - ) # don't count empty strings - d[field.original] = [int(x) if x.is_integer() else x for x in temp_list] - elif field.text_type == NUMBER_SETTING: - value = float(value) - if value.is_integer(): - value = int(value) - d[field.original] = float(value) - else: - d[field.original] = value - elif isinstance(field.widget, (QScrollArea, QGroupBox)): - d[field.original] = self.tree_to_dictionary(field) - elif isinstance(field.widget, QCheckBox): - d[field.original] = field.widget.isChecked() - return d - - def setup_xmlrpc_server(self): - self.server.register_function(self.xmlrpc_get_message, "get_message") - self.server.register_function(self.xmlrpc_complete, "complete") - self.server.register_function(self.xmlrpc_kill, "kill") - server_thread = threading.Thread(target=self.server.serve_forever) - server_thread.daemon = True - server_thread.start() - - def xmlrpc_kill(self): - self.expiration.cancel() - QApplication.quit() - - def xmlrpc_get_message(self): - if self.completed: - threading.Timer(1, self.xmlrpc_kill).start() - return self.tree_to_dictionary() - else: - return None - - def xmlrpc_complete(self): - QtCore.QCoreApplication.postEvent(self, QtCore.QEvent(RPC_COMPLETE_EVENT)) - - def accept(self): - self.xmlrpc_complete() - - def reject(self): - self.xmlrpc_kill() - - -def main(): - server_address = (Communicator.LOCALHOST, Communicator().com_registry["hmc"]) - # Enabled by default logging causes RPC to malfunction when the GUI runs on - # pythonw. Explicitly disable logging for the XML server. - server = SimpleXMLRPCServer(server_address, logRequests=False, allow_none=True) - app = QApplication(sys.argv) - window = SettingsDialog(server) - window.show() - exit_code = qapp_exec(app) - server.shutdown() - sys.exit(exit_code) - - -if __name__ == "__main__": - main() diff --git a/castervoice/asynch/sikuli/__init__.py b/castervoice/asynch/sikuli/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/asynch/sikuli/server/xmlrpc_server.sikuli/xmlrpc_server.html b/castervoice/asynch/sikuli/server/xmlrpc_server.sikuli/xmlrpc_server.html deleted file mode 100644 index 0ec2cfd2a..000000000 --- a/castervoice/asynch/sikuli/server/xmlrpc_server.sikuli/xmlrpc_server.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - -
-

xmlrpc_server.sikuli\xmlrpc_server.sikuli

(Download this script) -
-
-import SimpleXMLRPCServer
-from SimpleXMLRPCServer import *
-import sys
-from inspect import getmembers, isfunction
-
-SCRIPTS_PATH = sys.argv[0].split("\\xmlrpc_server.sikuli")[0]
-BASE_PATH = sys.argv[0].split("MacroSystem")[0] + "MacroSystem"
-
-modules = []
-server = SimpleXMLRPCServer(("127.0.0.1", 8000), allow_none=True)
-quit = 0
-
-def ping():
-    return 1
-def list_functions():
-    global modules
-    return modules
-def terminate():
-    global quit
-    quit = 1
-    return 1
-
-server.register_function(list_functions, "list_functions")
-server.register_function(terminate, "terminate")
-
-if SCRIPTS_PATH not in sys.path:
-    sys.path.append(SCRIPTS_PATH)
-for s in [x[0] for x in os.walk(SCRIPTS_PATH)]:
-    if s.endswith(".sikuli") and not s.endswith("xmlrpc_server.sikuli"):
-        mdl_name = s.split(".")[0].split("\\")[-1]
-        exec("import " + mdl_name)
-        exec("l = getmembers(" + mdl_name+", isfunction)")
-        for d in l:
-            if d[0].startswith("export_"):
-                registered_function_name=mdl_name+"_"+d[0].replace("export_", "")
-                modules.append(registered_function_name)
-                exec("server.register_function("+mdl_name+"."+d[0]+", '"+registered_function_name+"')")
-
-
-print "Caster Sikuli Bridge\n\nlist of available commands " + str(modules)
-
-
-
-# examples
-def add(self, x, y):
-    return x + y
-
-
-
-
-try:
-    while not quit:
-        server.handle_request()
-#     server.serve_forever()
-except KeyboardInterrupt:
-    print 'Exiting'
-
- - diff --git a/castervoice/asynch/sikuli/server/xmlrpc_server.sikuli/xmlrpc_server.py b/castervoice/asynch/sikuli/server/xmlrpc_server.sikuli/xmlrpc_server.py deleted file mode 100644 index c73a2eb16..000000000 --- a/castervoice/asynch/sikuli/server/xmlrpc_server.sikuli/xmlrpc_server.py +++ /dev/null @@ -1,62 +0,0 @@ -import os -import sys - -if sys.version_info[0] < 3: - from SimpleXMLRPCServer import SimpleXMLRPCServer # pylint: disable=import-error -else: - from xmlrpc.server import SimpleXMLRPCServer # pylint: disable=no-name-in-module - -from inspect import getmembers, isfunction - -modules = [] -server = SimpleXMLRPCServer(("127.0.0.1", 8000), logRequests=False, allow_none=True) -quit = 0 - -SCRIPTS_PATH = sys.argv[1] - -def ping(): - return 1 - -def list_functions(): - global modules - return modules - -def terminate(): - global quit - quit = 1 - return 1 - -server.register_function(list_functions, "list_functions") -server.register_function(terminate, "terminate") - -print("\nCaster Sikuli Bridge [started]\n") -print(" Loading commands from: {} ...".format(SCRIPTS_PATH)) - -if SCRIPTS_PATH not in sys.path: - sys.path.append(SCRIPTS_PATH) -for s in [x[0] for x in os.walk(SCRIPTS_PATH)]: - if s.endswith(".sikuli") and not s.endswith("xmlrpc_server.sikuli"): - mdl_name = s.split(".sikuli")[0].split("\\")[-1] - exec("import " + mdl_name) - exec("l = getmembers(" + mdl_name + ", isfunction)") - for d in l: # pylint: disable=undefined-variable - if d[0].startswith("export_"): - registered_function_name = mdl_name + "_" + d[0].replace("export_", "") - modules.append(registered_function_name) - exec("server.register_function(" + mdl_name + "." + d[0] + ", '" + - registered_function_name + "')") - -print(" Loaded. Available commands:\n") -for fn_name in modules: - print(" {}".format(str(fn_name).replace("_", " "))) -print("") - -# examples -def add(self, x, y): - return x + y - -try: - while not quit: - server.handle_request() -except KeyboardInterrupt: - print('Exiting') diff --git a/castervoice/asynch/sikuli/sikuli_controller.py b/castervoice/asynch/sikuli/sikuli_controller.py deleted file mode 100644 index 68565fad3..000000000 --- a/castervoice/asynch/sikuli/sikuli_controller.py +++ /dev/null @@ -1,112 +0,0 @@ -from subprocess import Popen -import traceback -import socket - -from dragonfly import get_current_engine, Function, Playback - -from castervoice.lib import settings, utilities, control, printer - - -class SikuliController(object): - - _ENABLE_GEN_RULE = Playback([(["enable", "sikuli", "custom"], 0.0)]) - _DISABLE_GEN_RULE = Playback([(["disable", "sikuli", "custom"], 0.0)]) - - def __init__(self): - self._server_proxy = None - self._timer = None - - def launch_IDE(self): - """ - Launches the Sikuli IDE. Has no effect on anything else. - """ - ide_path = settings.SETTINGS["paths"]["SIKULI_IDE"] - if ide_path == "": - print("No 'SIKULI_IDE' path is available. Did you configure it in " + settings.get_filename()) - else: - Popen(["java", "-jar", ide_path]) - - def bootstrap_start_server_proxy(self): - """ - There are two parts to getting Sikuli running: the server and the - server proxy. The server is an independent process, which needs to - already be running before the server proxy is started. This method - attempts to start the server proxy and then if that fails, it starts - the server and sets a timer to retry the server proxy. - """ - try: - # if the server is already running, this should go off without a hitch - self._start_server_proxy() - except Exception: - self._start_server() - five_seconds = 5 - self._timer = get_current_engine().create_timer(self._retry_server_proxy, five_seconds) - - def _start_server(self): - runner_path = settings.SETTINGS["paths"]["SIKULI_RUNNER"] - if runner_path == "": - print("No 'SIKULI_RUNNER' path is available. Did you configure it in " + settings.get_filename()) - else: - command = [] if settings.SETTINGS["sikuli"]["version"] == "1.1.3" else ["java", "-jar"] - command.extend([ - settings.SETTINGS["paths"]["SIKULI_RUNNER"], - "-r", settings.SETTINGS["paths"]["SIKULI_SERVER_PATH"], - "--args", settings.SETTINGS["paths"]["SIKULI_SCRIPTS_PATH"] - ]) - Popen(command) - - def _start_server_proxy(self): - """ - This method will fail if the server isn't started yet. - """ - # this will never fail: - self._server_proxy = control.nexus().comm.get_com("sikuli") - # this will fail if the server isn't started yet: - self._server_proxy.list_functions() - # success at this point: - printer.out("Caster-Sikuli server started successfully.") - SikuliController._ENABLE_GEN_RULE.execute() - - def _retry_server_proxy(self): - printer.out("Attempting Caster-Sikuli connection [...]") - try: - self._start_server_proxy() - if self._timer: - self._timer.stop() - self._timer = None - except socket.error: - pass - except Exception: - traceback.print_exc() - - def terminate_server_proxy(self): - control.nexus().comm.coms.pop('sikuli') - self._server_proxy.terminate() - SikuliController._DISABLE_GEN_RULE.execute() - - def _execute(self, fname): - try: - fn = getattr(self._server_proxy, fname) - fn() - except Exception: - utilities.simple_log() - - def generate_commands(self): - list_of_functions = [] - if self._server_proxy is not None: - list_of_functions = self._server_proxy.list_functions() - mapping = {} - for fname in list_of_functions: - spec = " ".join(fname.split("_")) - mapping[spec] = Function(self._execute, fname=fname) - return mapping - - -_INSTANCE = None - - -def get_instance(): - global _INSTANCE - if _INSTANCE is None: - _INSTANCE = SikuliController() - return _INSTANCE diff --git a/castervoice/asynch/sikuli/sikuli_gen_rule.py b/castervoice/asynch/sikuli/sikuli_gen_rule.py deleted file mode 100644 index 3274572e7..000000000 --- a/castervoice/asynch/sikuli/sikuli_gen_rule.py +++ /dev/null @@ -1,29 +0,0 @@ -from dragonfly import MappingRule - -from castervoice.asynch.sikuli import sikuli_controller -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.actions2 import NullAction - - -class SikuliRule(MappingRule): - """ - The tricky thing about this rule is that its commands must be retrieved from - the running Sikuli server. So it can't be instantiated properly unless the - Sikuli server is already running. - - Therefore, it must itself be activated as a side effect of the function - which starts the Sikuli server. - """ - - def __init__(self, name="sikuli custom"): - super(SikuliRule, self).__init__(name=name, mapping=self._get_mapping()) - - def _get_mapping(self): - mapping = sikuli_controller.get_instance().generate_commands() - if len(mapping) == 0: - mapping["this was a test instantiation"] = NullAction() - return mapping - - -def get_rule(): - return SikuliRule, RuleDetails(name="sikuli custom") diff --git a/castervoice/asynch/sikuli/sikuli_mgmt_rule.py b/castervoice/asynch/sikuli/sikuli_mgmt_rule.py deleted file mode 100644 index 3ffe19c68..000000000 --- a/castervoice/asynch/sikuli/sikuli_mgmt_rule.py +++ /dev/null @@ -1,23 +0,0 @@ -from dragonfly import Function, MappingRule - -from castervoice.asynch.sikuli import sikuli_controller -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R -from castervoice.asynch.sikuli import sikuli_gen_rule - -_sc = sikuli_controller.get_instance() - - -class SikuliManagementRule(MappingRule): - - mapping = { - "launch sick IDE": R(Function(_sc.launch_IDE)), - "launch sick server": R(Function(_sc.bootstrap_start_server_proxy)), - "terminate sick server": R(Function(_sc.terminate_server_proxy)), - "refresh sick server": R(Function(_sc.terminate_server_proxy) + Function(_sc.bootstrap_start_server_proxy)), - } - - -def get_rule(): - details = RuleDetails(name="sikuli control rule") - return SikuliManagementRule, details diff --git a/castervoice/bin/data/configdebug.txt b/castervoice/bin/data/configdebug.txt deleted file mode 100644 index 67bfdbc53..000000000 --- a/castervoice/bin/data/configdebug.txt +++ /dev/null @@ -1,20 +0,0 @@ -from dragonfly import * -from castervoice.lib import navigation -from castervoice.lib.merge.state.short import R - -release = Key("shift:up, ctrl:up") -# this gets added on the right side -noSpaceNoCaps = Mimic("\\no-caps-on") + Mimic("\\no-space-on") - -# Spoken-form -> -> Action object -cmd.map = { - "some command goes here": R(Pause("100"), rdescript="test command"), -} - -cmd.extras = [ - -] - -cmd.defaults = { - -} diff --git a/castervoice/bin/reboot.bat b/castervoice/bin/reboot.bat deleted file mode 100644 index b39ea0dc8..000000000 --- a/castervoice/bin/reboot.bat +++ /dev/null @@ -1,8 +0,0 @@ -taskkill /IM natspeak.exe /f /s localhost -taskkill /IM dgnuiasvr_x64.exe /f /s localhost -taskkill /IM dnsspserver.exe /f /s localhost -taskkill /IM dragonbar.exe /f /s localhost -sleep 1 -start "" %1 /user %2 - - diff --git a/castervoice/bin/reboot_wsr.bat b/castervoice/bin/reboot_wsr.bat deleted file mode 100644 index b071fa12c..000000000 --- a/castervoice/bin/reboot_wsr.bat +++ /dev/null @@ -1,3 +0,0 @@ -taskkill /IM sapisvr.exe /f /s localhost -sleep 1 -start "" %1 -SpeechUX \ No newline at end of file diff --git a/castervoice/bin/share/git_repo_local_to_remote_match.toml.defaults b/castervoice/bin/share/git_repo_local_to_remote_match.toml.defaults deleted file mode 100644 index cf8760bb7..000000000 --- a/castervoice/bin/share/git_repo_local_to_remote_match.toml.defaults +++ /dev/null @@ -1,2 +0,0 @@ -[github] -# "https://github.com/dictation-toolbox/Caster" = "%USERPROFILE%\\Documents\\caster" diff --git a/castervoice/bin/share/words.txt b/castervoice/bin/share/words.txt deleted file mode 100644 index 1766aabb3..000000000 --- a/castervoice/bin/share/words.txt +++ /dev/null @@ -1,6 +0,0 @@ -<<>> -shock -> earthquake -<<>> -sauce -> up -dunce -> down -lease -> left \ No newline at end of file diff --git a/castervoice/lib/__init__.py b/castervoice/lib/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/actions.py b/castervoice/lib/actions.py deleted file mode 100644 index d1a0875a3..000000000 --- a/castervoice/lib/actions.py +++ /dev/null @@ -1,19 +0,0 @@ -from dragonfly import Key, Mouse -from dragonfly import Text as TextBase - -from castervoice.lib import settings - -class Text(TextBase): - # dragonfly _pause_default 0.02 is too slow! Caster default 0.003 - _pause_default = settings.settings(["miscellaneous", "dragonfly_pause_default"]) - def __init__(self, spec=None, static=False, pause=_pause_default, autofmt=False, use_hardware=False): - TextBase.__init__(self, spec=spec, static=static, pause=pause, autofmt=autofmt, use_hardware=use_hardware) - -# Override imported dragonfly actions with aenea's if the 'use_aenea' setting -# is set to true. -if settings.settings(["miscellaneous", "use_aenea"]): - try: - from aenea import Key, Text, Mouse - except ImportError: - print("Unable to import aenea actions. Dragonfly actions will be used " - "instead.") diff --git a/castervoice/lib/available_commands_tracker.py b/castervoice/lib/available_commands_tracker.py deleted file mode 100644 index 0993e03ff..000000000 --- a/castervoice/lib/available_commands_tracker.py +++ /dev/null @@ -1,31 +0,0 @@ - -class AvailableCommandsTracker(object): - """ - This class should have NO dependencies. - - Do NOT make this more sophisticated. If you are considering doing so, you - probably don't understand the problem as well as you think you do. - - This is nothing more than a container to set and get some formatted output. - """ - - def __init__(self): - self._available_commands = "Available commands not set yet." - - def set_available_commands(self, commands): - if not isinstance(commands, str): - raise Exception("Do not set 'commands' to a non-string format.") - self._available_commands = commands - - def get_available_commands(self): - return self._available_commands - - -_INSTANCE = None - - -def get_instance(): - global _INSTANCE - if _INSTANCE is None: - _INSTANCE = AvailableCommandsTracker() - return _INSTANCE diff --git a/castervoice/lib/clipboard.py b/castervoice/lib/clipboard.py deleted file mode 100644 index e972df03b..000000000 --- a/castervoice/lib/clipboard.py +++ /dev/null @@ -1,56 +0,0 @@ -from castervoice.lib import settings, printer - -Clipboard = None -try: - from dragonfly import Clipboard as DragonflyClipboard - # Use DragonflyClipboard as Clipboard. - Clipboard = DragonflyClipboard -except: - printer.out("dragonfly.Clipboard failed to import.") - -def _is_aenea_available(): - try: - import aenea - return True - except ImportError: - print("Unable to import aenea, dragonfly.Clipboard will be used " - "instead.") - return False - - -# Use a subclass of dragonfly's clipboard class instead if the 'use_aenea' -# setting is set to true. This will allow commands like 'stoosh' to work -# properly server-side if the RPC functions are available. -if settings.settings(["miscellaneous", "use_aenea"]) and _is_aenea_available(): - # pylint: disable=import-error - import aenea - from jsonrpclib import ProtocolError - - class Clipboard(DragonflyClipboard): # pylint: disable=function-redefined - - @classmethod - def get_system_text(cls): - # Get the server's clipboard content if possible and update this - # system's clipboard. - try: - server_text = aenea.communications.server.paste() - DragonflyClipboard.set_system_text(server_text) - return server_text - except ProtocolError as e: - print("ProtocolError caught when calling server.paste(): %s" - % e) - print("Only getting local clipboard content.") - return DragonflyClipboard.get_system_text() - - @classmethod - def set_system_text(cls, content): - # Set the server's clipboard content if possible. - try: - aenea.communications.server.copy(content) - except ProtocolError as e: - print("ProtocolError caught when calling server.copy(): %s" - % e) - print("Only setting local clipboard content.") - - # Set this system's clipboard content. - DragonflyClipboard.set_system_text(content) diff --git a/castervoice/lib/config/__init__.py b/castervoice/lib/config/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/config/config_base.py b/castervoice/lib/config/config_base.py deleted file mode 100644 index 90ac8566e..000000000 --- a/castervoice/lib/config/config_base.py +++ /dev/null @@ -1,9 +0,0 @@ -class BaseConfig(object): - def __init__(self): - self._config = {} - - def get(self, key): - return None if key not in self._config else self._config[key] - - def put(self, key, value): - self._config[key] = value diff --git a/castervoice/lib/config/config_toml.py b/castervoice/lib/config/config_toml.py deleted file mode 100644 index f10d6e72e..000000000 --- a/castervoice/lib/config/config_toml.py +++ /dev/null @@ -1,15 +0,0 @@ -from castervoice.lib import utilities -from castervoice.lib.config.config_base import BaseConfig - - -class TomlConfig(BaseConfig): - - def __init__(self, config_path): - super(TomlConfig, self) - self._config_path = config_path - - def save(self): - utilities.save_toml_file(self._config, self._config_path) - - def load(self): - self._config = utilities.load_toml_file(self._config_path) diff --git a/castervoice/lib/const.py b/castervoice/lib/const.py deleted file mode 100644 index 523d2b21e..000000000 --- a/castervoice/lib/const.py +++ /dev/null @@ -1,55 +0,0 @@ -import dragonfly -import sys - - -class CCRType(object): - GLOBAL = "global" - APP = "app" - SELFMOD = "selfmod" - - -# default-on modules -CORE = [ - # Caster CCR "core" set: - "Alphabet", "Navigation", "NavigationNon", "Numbers", "Punctuation", "Keyboard", - # Rules which were split out of _caster.py: - "CasterRule", "CasterMicRule", "HardwareRule", "MouseAlternativesRule", "WindowManagementRule", - # Alternate mouse grid controls: - "DouglasGridRule", "RainbowGridRule", "SudokuGridRule", - # HMC GUI control rules: - "HMCRule", "HMCConfirmRule", "HMCDirectoryRule", - "HMCHistoryRule", "HMCLaunchRule", "HMCSettingsRule", - # GUI Rules - "HistoryRule", "ChainAlias", "Alias", - # other common rules - "BringRule", "Again" - ] - -# default-on modules that are platform or engine specific -if sys.platform == "win32": - CORE.extend([ - "LegionGridRule", - "IERule" - ]) - # get_engine() is used here as a workaround for running Natlink inprocess - if dragonfly.get_engine().name == 'natlink': - CORE.append("DragonRule") - -# internal rules -INTERNAL = [ - "GrammarActivatorRule", "HooksActivationRule", "TransformersActivationRule", - "ManualGrammarReloadRule" -] - -# default companion rules -COMPANION_STARTER = { - "Navigation": ["NavigationNon"], - "Java": ["JavaNon"], - "Matlab": ["MatlabNon"], - "Prolog": ["PrologNon"], - "Python": ["PythonNon"], - "Rust": ["RustNon"], - "VHDL": ["VHDLnon"], - "EclipseCCR": ["EclipseRule"], - "VSCodeCcrRule": ["VSCodeNonCcrRule"] -} diff --git a/castervoice/lib/context.py b/castervoice/lib/context.py deleted file mode 100644 index 04f5f1452..000000000 --- a/castervoice/lib/context.py +++ /dev/null @@ -1,193 +0,0 @@ -import time -import sys - -from dragonfly import AppContext, Pause - -from castervoice.lib import utilities, settings -from castervoice.lib.actions import Key -from castervoice.lib.clipboard import Clipboard - -# Override dragonfly.AppContext with aenea.ProxyAppContext if the 'use_aenea' -# setting is set to true. -if settings.settings(["miscellaneous", "use_aenea"]): - try: - from aenea import ProxyAppContext as AppContext - except ImportError: - print("Unable to import aenea.ProxyAppContext. dragonfly.AppContext " - "will be used instead.") - - -def _target_is_character(target): - '''determines if the target is a single character''' - if len(target) == 1: - return True - '''if the character is in the character group:''' - for s in target.split("~"): - if s in ".,()[]{}<>": - return True - return False - - -def _find_index_in_context(target, context, look_left): - '''attempts to find index of target in clipboard content''' - tlist = target.split("~") - index = -1 - if look_left: - index = -99999 - for t in tlist: - tmpindex = context.rfind(t) # - if tmpindex != -1 and tmpindex > index: # when looking left, we want the largest index - index = tmpindex - else: - index = 99999 # arbitrarily large number - for t in tlist: - tmpindex = context.find(t) - if tmpindex != -1 and tmpindex < index: # conversely, when looking right, we want the smallest index - index = tmpindex - if index == 99999 or index == -99999: - return -1 - return index - - -def navigate_to_character(direction3, target, fill=False): - try: - look_left = str(direction3) == "left" - - # make sure nothing is highlighted to boot - if not fill: # (except when doing "fill" -- if at end of line, there is no space for this ) - Key("right, left" if look_left else "left, right").execute() - if look_left: - Key("cs-left").execute() - else: - Key("cs-right").execute() - - context = read_nmax_tries(5, .01) - if context is None: - return False - - # if we got to this point, we have a copy result - index = _find_index_in_context(target, context, look_left) - - if index != -1: # target found - '''move the cursor to the left of the target if looking left, - to the right of the target if looking right:''' - Key("left" if look_left else "right").execute() - '''number of times to press left or right before the highlight - (the target may be a part of a fully highlighted word): ''' - nt = index if look_left else len(context) - index - 1 # pylint: disable=no-member - if nt != 0: - Key("right/5:" + str(nt) if look_left else "left/5:" + str(nt)).execute() - '''highlight only the target''' - if _target_is_character(target): - Key("s-right" if look_left else "s-left").execute() - else: - Key("cs-right" if look_left else "cs-left").execute() - return True - else: - # reset cursor - Key("left" if look_left else "right").execute() - return False - - except Exception: - utilities.simple_log() - - -def read_nmax_tries(n, slp=0.1): - tries = 0 - while True: - tries += 1 - results = read_selected_without_altering_clipboard() - error_code = results[0] - if error_code == 0: - return results[1] - if tries > n: - return None - time.sleep(slp) - - -def read_selected_without_altering_clipboard(same_is_okay=False, cb_timeout=0.200, pause_time="0", key_override=None): - '''Returns selected item from temporary clipboard buffer. - - Args: - same_is_okay (bool, optional): Initial clipboard contents is same as copied contents. Defaults to False. - cb_timeout (int, optional): Timeout monitoring for clipboard change. - - Windows OS increments clipboard contents, other OS's comparing clipboard contents - pause_time (str, optional): Keypress delay. Defaults to 0 ms. - - Allows foreground window to process key events - key_override (str, optional): Override platform copy key spec. Defaults to None. - - Allows non-standard key specs to invoke copy action - - Returns tuple: - (0, "text from system") - indicates success - (1, None) - indicates no change - (2, None) - indicates clipboard error - ''' - if key_override is None: - _default_copy_spec = "w-c/20" if sys.platform == "darwin" else "c-c/20" - else: - _default_copy_spec = key_override - - original_cb = Clipboard(from_system=True) - new_cb = Clipboard(from_system=True) - try: - with Clipboard.synchronized_changes(cb_timeout, initial_clipboard=original_cb): - Key(_default_copy_spec, use_hardware=True).execute() - Pause(pause_time).execute() - new_cb.copy_from_system() - except Exception as e: - print(e) - return (2, None) - original_cb.copy_to_system() - if original_cb == new_cb and not same_is_okay: - return (1, None) - else: - return(0, new_cb.get_text()) - - -def paste_string_without_altering_clipboard(content, cb_timeout=0.200, pause_time="1", key_override=None): - '''Paste content from temporary clipboard buffer. - Args: - content (str): content to insert into clipboard buffer. - cb_timeout (int, optional): timeout monitoring for clipboard change - - Windows OS increments clipboard contents, other OS's comparing clipboard contents - pause_time (str, optional): Keypress delay. Defaults to 1. - - Allows foreground window to process key events - key_override (str, optional): Override platform paste key spec. Defaults to None. - - Allows non-standard key specs to invoke paste action - - Returns bool: - True - indicates success - False - indicates clipboard error - ''' - - if key_override is None: - _default_paste_spec = "w-v/20" if sys.platform == "darwin" else "c-v/20" - else: - _default_paste_spec = key_override - - - cb = Clipboard(from_system=True) - try: - with cb.synchronized_changes(cb_timeout): - Clipboard.set_system_text(content) - Key(_default_paste_spec, use_hardware=True).execute() - Pause(pause_time).execute() - except Exception as e: - print(e) - return False - cb.copy_to_system() - return True - -def fill_within_line(target): - result = navigate_to_character("left", str(target), True) - if result: - from castervoice.lib import control - control.nexus().state.terminate_asynchronous(success=True) - return result - - -def nav(parameters): - result = navigate_to_character(str(parameters[0]), str(parameters[1])) - if result: - Key(str(parameters[0])).execute() - return result diff --git a/castervoice/lib/contexts.py b/castervoice/lib/contexts.py deleted file mode 100644 index 7b3ae7997..000000000 --- a/castervoice/lib/contexts.py +++ /dev/null @@ -1,41 +0,0 @@ -import os -import sys -from dragonfly import FuncContext -from castervoice.lib.context import AppContext - -def is_windows(): - return sys.platform == "win32" - -def is_macos(): - return sys.platform == "darwin" - -def is_linux(): - return sys.platform.startswith("linux") - -def is_x11(): - return os.environ.get("XDG_SESSION_TYPE") == "x11" - -WINDOWS_CONTEXT = FuncContext(is_windows) -MACOS_CONTEXT = FuncContext(is_macos) -LINUX_CONTEXT = FuncContext(is_linux) -X11_CONTEXT = FuncContext(is_x11) - -TERMINAL_CONTEXT = AppContext(executable=[ - "\\sh.exe", - "\\bash.exe", - "\\cmd.exe", - "\\mintty.exe", - "\\powershell.exe", - "gnome-terminal" - ]) - -JETBRAINS_CONTEXT = AppContext(executable="idea", title="IntelliJ") \ - | AppContext(executable="idea64", title="IntelliJ") \ - | AppContext(executable="studio64") \ - | AppContext(executable="pycharm") - -DIALOGUE_CONTEXT = AppContext(title=[ - "open", - "save", - "select", - ]) diff --git a/castervoice/lib/control.py b/castervoice/lib/control.py deleted file mode 100644 index 88c7be3de..000000000 --- a/castervoice/lib/control.py +++ /dev/null @@ -1,11 +0,0 @@ -_NEXUS = None - - -def init_nexus(content_loader): - global _NEXUS - from castervoice.lib.ctrl.nexus import Nexus - _NEXUS = Nexus(content_loader) - - -def nexus(): - return _NEXUS diff --git a/castervoice/lib/ctrl/__init__.py b/castervoice/lib/ctrl/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/ctrl/configure_engine.py b/castervoice/lib/ctrl/configure_engine.py deleted file mode 100644 index 6446f342c..000000000 --- a/castervoice/lib/ctrl/configure_engine.py +++ /dev/null @@ -1,121 +0,0 @@ -import time -from dragonfly import get_current_engine, register_recognition_callback, RecognitionObserver -from castervoice.lib import settings -from castervoice.lib import printer - - -class Observer(RecognitionObserver): - def __init__(self): - from castervoice.lib import control - self.mic_mode = None - self._engine_modes_manager = control.nexus().engine_modes_manager - - def on_begin(self): - self.mic_mode = self._engine_modes_manager.get_mic_mode() - - def on_recognition(self, words): - if not self.mic_mode == "sleeping": - printer.out("$ {}".format(" ".join(words))) - - def on_failure(self): - if not self.mic_mode == "sleeping": - printer.out("?!") - - - -class EngineConfigEarly: - """ - Initializes engine customizations before Nexus initializes. - Grammars are not loaded - """ - # get_engine used as a workaround for running Natlink inprocess - def __init__(self): - self.engine = get_current_engine().name - self._set_cancel_word() - - def _set_cancel_word(self): - """ - Defines SymbolSpecs cancel word as "escape" for windows speech recognition (WSR) - """ - if self.engine in ["sapi5shared", "sapi5", "sapi5inproc"]: - settings.WSR = True - from castervoice.rules.ccr.standard import SymbolSpecs - SymbolSpecs.set_cancel_word("escape") - - -class EngineConfigLate: - """ - Initializes engine specific customizations after Nexus has initialized. - Grammars are loaded into engine. - """ - def __init__(self): - from castervoice.lib import control - self._engine_modes_manager = control.nexus().engine_modes_manager - self.engine = get_current_engine().name - self.sync_timer = None - self.sleep_timer = None - Observer().register() - - - if self.engine != 'natlink': - # Other engines besides natlink needs a default mic state for sleep_timer - self._engine_modes_manager.mic_state = "on" - if self.engine != "text": - self._engine_timers() - self._set_default_mic_mode() - self._set_engine_default_mode() - - def _engine_timers(self): - # Timer to synchronize natlink.getMicState/SetRecognitionMode with mode_state in case of changed by end-user via DNS GUI. - if self.engine == 'natlink' and self.sync_timer is None: - sync_timer = get_current_engine().create_timer( - callback=self._engine_modes_manager._sync_mode, interval=1) - sync_timer.start() - # A timer to change microphone state to "sleep" after X amount of seconds after last successful recognition - if self.sleep_timer is None and settings.SETTINGS["engine"][ - "mic_sleep_timer_on"] == True: - self.sleep_timer = get_current_engine().create_timer( - callback=self._sleep_timer, - interval=int(settings.SETTINGS["engine"]["mic_sleep_timer"])) - self.sleep_timer.start() - register_recognition_callback(function=self._reset_sleep_timer) - - def _sleep_timer(self): - """ - Puts microphone to sleep if "on" via sleep_timer callback every x seconds - """ - if self._engine_modes_manager.get_mic_mode() == "on": - self._engine_modes_manager.set_mic_mode("sleeping") - - def _reset_sleep_timer(self, words=None): - """ - A register_recognition_callback to reset the timer for sleep_timer based on last successful recognition - """ - self.sleep_timer.stop() - time.sleep(0.15) - self.sleep_timer.start() - - def _set_default_mic_mode(self): - """ - Sets the microphone state on Caster startup. - """ - # Only DNS supports mic_state 'off'. Substituts `sleep` mode on other engines" - if settings.SETTINGS["engine"]["default_mic"]: # Default is `False` - # Default is `on` - default_mic_state = settings.SETTINGS["engine"]["mic_mode"] - if self.engine != "natlink" and default_mic_state == "off": - default_mic_state = "sleep" - self._engine_modes_manager.set_mic_mode(default_mic_state) - - def _set_engine_default_mode(self): - """ - Sets the engine mode on Caster startup. - """ - # Only DNS supports 'normal'. Substituts `command` mode on other engines" - # Default is `False` - if settings.SETTINGS["engine"]["default_engine_mode"]: - # Default is `normal` - default_mode = settings.SETTINGS["engine"]["engine_mode"] - if self.engine != "natlink" and default_mode == "normal": - default_mode = "command" - self._engine_modes_manager.set_engine_mode(mode=default_mode, state=True) diff --git a/castervoice/lib/ctrl/dependencies.py b/castervoice/lib/ctrl/dependencies.py deleted file mode 100644 index 74bb8fb3c..000000000 --- a/castervoice/lib/ctrl/dependencies.py +++ /dev/null @@ -1,82 +0,0 @@ -''' -Created on Oct 7, 2015 - -@author: synkarius -''' -import os, sys, time -from importlib.metadata import version, PackageNotFoundError -from packaging.version import Version -from castervoice.lib import printer - -DARWIN = sys.platform == "darwin" -LINUX = sys.platform == "linux" - -def install_type(): - # Checks if Caster install is Classic or PIP. - try: - version("castervoice") - except PackageNotFoundError: - return "classic" - return "pip" - - -def find_pip(): - # Find the pip script for Python. - python_scripts = os.path.join(sys.exec_prefix, - "bin" if DARWIN or LINUX else "Scripts") - pip_exec = "pip.exe" if sys.platform == "win32" else "pip" - return os.path.join(python_scripts, pip_exec) - - -def dep_missing(): - uppath = lambda _path, n: os.sep.join(_path.split(os.sep)[:-n]) - requirements_file = "requirements-mac-linux.txt" if DARWIN or LINUX else "requirements.txt" - requirements = os.path.join(uppath(__file__, 4), requirements_file) - missing_list = [] - with open(requirements) as f: - requirements = f.read().splitlines() - for dep in requirements: - dep = dep.split(">=", 1)[0] - try: - version(dep) - except PackageNotFoundError: - missing_list.append(dep) - if missing_list: - pippackages = (' '.join(map(str, missing_list))) - printer.out("\nCaster: dependencys are missing. Use 'python -m pip install {0}'".format(pippackages)) - time.sleep(10) - - -def dep_min_version(): - # For classic: Checks for Maintainer specified package requirements. - # Needs to be manually resolved if Caster requires a specific version of dependency - # A GitHub Issue URL needed to explain the change to version specific '==' dependency. - listdependency = ([ - ["dragonfly2", ">=", "0.34.0", "https://github.com/dictation-toolbox/dragonfly/blob/master/CHANGELOG.rst#fixed"], - ]) - for dep in listdependency: - package = dep[0] - operator = dep[1] - req_version = dep[2] - issue_url = dep[3] - try: - installed = Version(version(package)) - required = Version(req_version) - if operator == ">=" and installed < required: - if issue_url is not None: - printer.out("\nCaster: Requires {0} v{1} or greater.\nIssue reference: {2}".format(package, req_version, issue_url)) - printer.out("Update with: 'python -m pip install {} --upgrade' \n".format(package)) - elif operator == "==" and installed != required: - printer.out("\nCaster: Requires an exact version of {0}.\nIssue reference: {1}".format(package, issue_url)) - printer.out("Install with: 'python -m pip install {0}=={1}' \n".format(package, req_version)) - except PackageNotFoundError: - pass - - -class DependencyMan: - # Initializes functions - def initialize(self): - install = install_type() - if install == "classic": - dep_missing() - dep_min_version() diff --git a/castervoice/lib/ctrl/mgr/__init__.py b/castervoice/lib/ctrl/mgr/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/ctrl/mgr/ccr_toggle.py b/castervoice/lib/ctrl/mgr/ccr_toggle.py deleted file mode 100644 index 2f0eae0dc..000000000 --- a/castervoice/lib/ctrl/mgr/ccr_toggle.py +++ /dev/null @@ -1,11 +0,0 @@ -from castervoice.lib import settings - - -class CCRToggle(object): - - def is_active(self): - return settings.SETTINGS["miscellaneous"]["ccr_on"] - - def set_active(self, active): - settings.SETTINGS["miscellaneous"]["ccr_on"] = active - settings.save_config() diff --git a/castervoice/lib/ctrl/mgr/companion/__init__.py b/castervoice/lib/ctrl/mgr/companion/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/ctrl/mgr/companion/companion_config.py b/castervoice/lib/ctrl/mgr/companion/companion_config.py deleted file mode 100644 index 8e0da0a6f..000000000 --- a/castervoice/lib/ctrl/mgr/companion/companion_config.py +++ /dev/null @@ -1,21 +0,0 @@ -from castervoice.lib import settings, const -from castervoice.lib.config.config_toml import TomlConfig - - -class CompanionConfig(TomlConfig): - """ - Controls companion rules. It is possible to make a circular companion rule relationship. Do not do this. - """ - - def __init__(self): - super(CompanionConfig, self).__init__(settings.settings(["paths", "COMPANION_CONFIG_PATH"])) - self.load() - self._initialize() - - def _initialize(self): - if len(self._config) == 0: - self._config = const.COMPANION_STARTER - self.save() - - def get_companions(self, rcn): - return [] if rcn not in self._config else list(self._config[rcn]) diff --git a/castervoice/lib/ctrl/mgr/engine_manager.py b/castervoice/lib/ctrl/mgr/engine_manager.py deleted file mode 100644 index a014f7971..000000000 --- a/castervoice/lib/ctrl/mgr/engine_manager.py +++ /dev/null @@ -1,137 +0,0 @@ -from dragonfly import get_current_engine -from castervoice.lib import printer - -try: - import natlink -except ImportError: - natlink = None - - -class EngineModesManager(object): - """ - Manages engine modes and microphone states using backend engine API and through dragonfly grammar exclusivity. - """ - def __init__(self, ExclusiveManager): - self.engine_modes = { - "normal": 0, - "command": 2, - "dictation": 1, - "numbers": 3, - "spell": 4 - } - self.mic_modes = {"on": 5, "sleeping": 6, "off": 7} - self.engine_state = None - self.previous_engine_state = None - self.mic_state = None - engine = get_current_engine() - self.engine = engine.name if engine is not None else "text" - self._exclusive_manager = ExclusiveManager - - # Remove "normal" and "off" from 'states' for non-DNS based engines. - if self.engine != 'natlink': - self.engine_modes.pop("normal", 0) - self.mic_modes.pop("off", 7) - # Sets 1st index key ("normal" or "command") depending on engine type as default mode - self.engine_state = self.previous_engine_state = next( - iter(self.engine_modes.keys())) - - def set_mic_mode(self, mode): - """ - Changes the engine microphone mode - :param mode: str - 'on': mic is on - 'sleeping': mic from the sleeping and can be woken up by command - 'off': mic off and cannot be turned back on by voice. (DPI Only) - """ - if mode in self.mic_modes: - self.mic_state = mode - if self.engine == 'natlink': - if natlink is not None: - natlink.setMicState(mode) - else: - printer.out("Caster: natlink is not available on this system") - # Overrides DNS/DPI is built in sleep grammar - self._exclusive_manager.set_mode(mode, modetype="mic_mode") - else: - printer.out( - "Caster: '{}' is not valid. set_mic_state modes are: 'off' - DPI Only, 'on', 'sleeping'" - .format(mode)) - - def get_mic_mode(self): - """ - Returns mic state. - mode: str - """ - return self.mic_state - - def set_engine_mode(self, mode=None, state=True): - """ - Sets the engine mode so that only certain types of commands/dictation are recognized. - :param state: Bool - enable/disable mode. - 'True': replaces current mode (Default) - 'False': restores previous mode - :param mode: str - 'normal': dictation and command (Default: DPI only) - 'dictation': Dictation only - 'command': Commands only (Default: Other engines) - 'numbers': Numbers only - 'spell': Spelling only - """ - if state and mode is not None: - # Track previous engine state - self.previous_engine_state = self.engine_state - else: - if not state: - # Restore previous mode - mode = self.previous_engine_state - else: - printer.out( - "Caster: set_engine_mode: 'State' cannot be 'True' with a undefined a 'mode'" - ) - - if mode in self.engine_modes: - if self.engine == 'natlink': - if natlink is None: - printer.out("Caster: natlink is not available on this system") - return - try: - natlink.execScript("SetRecognitionMode {}".format( - self.engine_modes[mode])) # mode is an integer - self.engine_state = mode - self._exclusive_manager.set_mode(mode, modetype="engine_mode") - except Exception as e: - printer.out("natlink.execScript failed \n {}".format(e)) - else: - # TODO: Implement set_engine_mode exclusivity. This should override DPI is built mode but kept in sync automatically. - if self.engine == 'text': - self.engine_state = mode - else: - printer.out( - "Caster: 'set_engine_mode' is not implemented for '{}'".format( - self.engine)) - else: - printer.out( - "Caster: '{}' mode is not valid. set_engine_mode: Modes: 'normal'- DPI Only, 'dictation', 'command', 'numbers', 'spell'" - .format(mode)) - - def get_engine_mode(self): - """ - Returns engine mode. - mode: str - """ - return self.engine_state - - def _sync_mode(self): - """ - Synchronizes Caster exclusivity modes an with DNS/DPI GUI built-in modes state. - """ - # TODO: Implement set_engine_mode logic with modes not just mic_state. - if self.engine != 'natlink' or natlink is None: - return - caster_mic = self.get_mic_mode() - natlink_mic = natlink.getMicState() - if caster_mic is None: - self.mic_state = natlink_mic - else: - if natlink_mic != caster_mic: - self.set_mic_mode(natlink_mic) diff --git a/castervoice/lib/ctrl/mgr/errors/__init__.py b/castervoice/lib/ctrl/mgr/errors/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/ctrl/mgr/errors/base_class_error.py b/castervoice/lib/ctrl/mgr/errors/base_class_error.py deleted file mode 100644 index e07e81cbc..000000000 --- a/castervoice/lib/ctrl/mgr/errors/base_class_error.py +++ /dev/null @@ -1,4 +0,0 @@ -class DontUseBaseClassError(Exception): - def __init__(self, base_instance): - super(DontUseBaseClassError, self).__init__( - "Do not use base class ({}).".format(base_instance.__class__.__name__)) diff --git a/castervoice/lib/ctrl/mgr/errors/guidance_rejection.py b/castervoice/lib/ctrl/mgr/errors/guidance_rejection.py deleted file mode 100644 index 1775e81ca..000000000 --- a/castervoice/lib/ctrl/mgr/errors/guidance_rejection.py +++ /dev/null @@ -1,6 +0,0 @@ -class GuidanceRejectionException(Exception): - - _MSG = "Unit tests should not write files unless they clean them up too." - - def __init__(self): - super(GuidanceRejectionException, self).__init__(GuidanceRejectionException._MSG) \ No newline at end of file diff --git a/castervoice/lib/ctrl/mgr/errors/invalid_companion_configuration_error.py b/castervoice/lib/ctrl/mgr/errors/invalid_companion_configuration_error.py deleted file mode 100644 index 82eec8eec..000000000 --- a/castervoice/lib/ctrl/mgr/errors/invalid_companion_configuration_error.py +++ /dev/null @@ -1,7 +0,0 @@ -class ICCEMessage(object): - COMPANION_TYPE = "MergeRules cannot be companion rules; only MappingRules. {} is invalid." - - -class InvalidCompanionConfigurationError(Exception): - def __init__(self, rcn, msg=ICCEMessage.COMPANION_TYPE): - super(InvalidCompanionConfigurationError, self).__init__(msg.format(rcn)) diff --git a/castervoice/lib/ctrl/mgr/errors/invalid_transformation_error.py b/castervoice/lib/ctrl/mgr/errors/invalid_transformation_error.py deleted file mode 100644 index b991942c0..000000000 --- a/castervoice/lib/ctrl/mgr/errors/invalid_transformation_error.py +++ /dev/null @@ -1,9 +0,0 @@ -class ITMessage(object): - BAD_TYPE = "{} rejected because it no longer descends from its original parent class." - CLASS_KEY = "{} rejected because its class name changed." - - -class InvalidTransformationError(Exception): - - def __init__(self, msg, rcn): - super(InvalidTransformationError, self).__init__(msg.format(rcn)) diff --git a/castervoice/lib/ctrl/mgr/errors/module_qualification_error.py b/castervoice/lib/ctrl/mgr/errors/module_qualification_error.py deleted file mode 100644 index 912c68a7f..000000000 --- a/castervoice/lib/ctrl/mgr/errors/module_qualification_error.py +++ /dev/null @@ -1,4 +0,0 @@ -class ModuleQualificationError(Exception): - - def __init__(self): - super(ModuleQualificationError, self).__init__("Module cannot be qualified.") diff --git a/castervoice/lib/ctrl/mgr/errors/no_pronunciation_error.py b/castervoice/lib/ctrl/mgr/errors/no_pronunciation_error.py deleted file mode 100644 index 845b5f669..000000000 --- a/castervoice/lib/ctrl/mgr/errors/no_pronunciation_error.py +++ /dev/null @@ -1,9 +0,0 @@ -class NoPronunciationError(Exception): - """ - This error should NEVER actually be thrown since rules without - pronunciations should get rejected by loading safety checks. - """ - - def __init__(self, rcn): - super(NoPronunciationError, self).__init__( - "Rule has no pronunciation: {}.".format(rcn)) diff --git a/castervoice/lib/ctrl/mgr/errors/not_a_module.py b/castervoice/lib/ctrl/mgr/errors/not_a_module.py deleted file mode 100644 index fdcbd352f..000000000 --- a/castervoice/lib/ctrl/mgr/errors/not_a_module.py +++ /dev/null @@ -1,3 +0,0 @@ -class NotAModuleError(Exception): - def __init__(self, file_path): - super(NotAModuleError, self).__init__(file_path + " is not a module.") \ No newline at end of file diff --git a/castervoice/lib/ctrl/mgr/errors/tree_rule_config_error.py b/castervoice/lib/ctrl/mgr/errors/tree_rule_config_error.py deleted file mode 100644 index 986e9a194..000000000 --- a/castervoice/lib/ctrl/mgr/errors/tree_rule_config_error.py +++ /dev/null @@ -1,3 +0,0 @@ -class TreeRuleConfigurationError(Exception): - def __init__(self, msg): - super(TreeRuleConfigurationError, self).__init__(msg) \ No newline at end of file diff --git a/castervoice/lib/ctrl/mgr/exclusivity_manager.py b/castervoice/lib/ctrl/mgr/exclusivity_manager.py deleted file mode 100644 index 8b44cae39..000000000 --- a/castervoice/lib/ctrl/mgr/exclusivity_manager.py +++ /dev/null @@ -1,59 +0,0 @@ -from dragonfly import get_engine, MimicFailure -from castervoice.lib import printer, control - - -# TODO: ExclusiveManager should be integrated into or with grammar_manager/grammar_activator? -class ExclusiveManager(object): - """ - Loads and switches exclusivity for caster modes - """ - def __init__(self): - self._get_engine = get_engine - self.rule_names = ["CasterMicRule", "DictationSinkRule"] - self.exclusive_grammars = {} - - def set_mode(self, mode, modetype): - """ - Sets modes - :param mode: str - sleeping, on, off - :param modetype: 'mic_mode' or 'engine_mode' str - """ - if modetype == "mic_mode": - self._get_grammars_loaded() - if mode == "sleeping": - self._set_grammars_exclusivity(self.exclusive_grammars, True) - printer.out("Caster: Microphone is sleeping") - if mode == "on": - self._set_grammars_exclusivity(self.exclusive_grammars, False) - printer.out("Caster: Microphone is on") - if mode == "off": - printer.out("Caster: Microphone is off") - else: - printer.out("{}, {} not implemented".format(mode, modetype)) - - def _get_grammars_loaded(self): - self.exclusive_grammars.clear() - for rule_name in self.rule_names: - for grammar in get_engine().grammars: - for rule in grammar.rules: - if rule.exported and rule_name in str(rule): - self.exclusive_grammars.update({rule_name: grammar}) - if rule_name not in self.exclusive_grammars: - self._activate_grammar(rule_name) - - def _activate_grammar(self, rule_name): - # TODO: This is a hack. `_change_rule_enabled` should only be accessed in the grammar_manager - try: - if str(rule_name) == "CasterMicRule": - control.nexus()._grammar_manager._change_rule_enabled("CasterMicRule", True) - if str(rule_name) == "DictationSinkRule": - control.nexus()._grammar_manager._change_rule_enabled("DictationSinkRule", True) - self._get_grammars_loaded() - except MimicFailure as e: - printer.out("Caster: {}".format(e)) - - - def _set_grammars_exclusivity(self, grammars, state): - for rule_name, grammar in grammars.items(): - grammar.set_exclusive(state) - self._get_engine().process_grammars_context() diff --git a/castervoice/lib/ctrl/mgr/grammar_activator.py b/castervoice/lib/ctrl/mgr/grammar_activator.py deleted file mode 100644 index 00e506c89..000000000 --- a/castervoice/lib/ctrl/mgr/grammar_activator.py +++ /dev/null @@ -1,72 +0,0 @@ -from dragonfly import MappingRule, Function - -from castervoice.lib.ctrl.mgr.errors.no_pronunciation_error import NoPronunciationError -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails - - -class GrammarActivator(object): - """ - It is the responsibility of the Activator to manage a grammar for activating - and deactivating rules. It is stateful. - """ - - def __init__(self, merge_rule_checker_fn): - self._class_name_to_trigger = {} - self._activation_rule_class = None - self._activation_fn = None - self._merge_rule_checker_fn = merge_rule_checker_fn - - def set_activation_fn(self, activation_fn): - """ - De/activator function is injected from somewhere else. - It is a function which takes: - trigger: string representing what to call the rule - active: boolean to set active or inactive - """ - self._activation_fn = activation_fn - - def register_rule(self, managed_rule): - """ - register or re-register a rule; - the "trigger" is what the rule is called when you say "enabled X" or "disable X" - """ - trigger = self._get_trigger(managed_rule) - self._class_name_to_trigger[managed_rule.get_rule_class_name()] = trigger - - def _get_trigger(self, managed_rule): - """ - Ideally we're dealing with a MergeRule and the trigger is its pronunciation. But since - GrammarManager also manages pure Dragonfly rules, we might need to derive the name otherwise. - """ - rule_instance = managed_rule.get_rule_instance() - if self._merge_rule_checker_fn(rule_instance): - return rule_instance.get_pronunciation() - if managed_rule.get_details().name is not None: - return managed_rule.get_details().name - raise NoPronunciationError(managed_rule.get_rule_class_name()) - - def construct_activation_rule(self): - """ - Construct new rule and for activation. - Should be called once only, after initial content loading. - Rule reloading does not watch for new files, so no need to ever call this again. - """ - if self._activation_rule_class is not None: - return None - - _mapping = {} - for class_name, trigger in self._class_name_to_trigger.items(): - enable_spec = "enable {}".format(trigger) - disable_spec = "disable {}".format(trigger) - _mapping[enable_spec] = Function(lambda rcn: self._activation_fn(rcn, True), rcn=class_name) - _mapping[disable_spec] = Function(lambda rcn: self._activation_fn(rcn, False), rcn=class_name) - - class GrammarActivatorRule(MappingRule): - mapping = _mapping - self._activation_rule_class = GrammarActivatorRule - - # name that should be pretty difficult to say by mistake: - details = RuleDetails(name="grammar manager grammar activator rule", - watch_exclusion=True) - - return self._activation_rule_class, details diff --git a/castervoice/lib/ctrl/mgr/grammar_container/__init__.py b/castervoice/lib/ctrl/mgr/grammar_container/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/ctrl/mgr/grammar_container/base_grammar_container.py b/castervoice/lib/ctrl/mgr/grammar_container/base_grammar_container.py deleted file mode 100644 index a7857bc19..000000000 --- a/castervoice/lib/ctrl/mgr/grammar_container/base_grammar_container.py +++ /dev/null @@ -1,13 +0,0 @@ -from castervoice.lib.ctrl.mgr.errors.base_class_error import DontUseBaseClassError - - -class BaseGrammarContainer(object): - - def set_non_ccr(self, rcn, grammar): - raise DontUseBaseClassError(self) - - def set_ccr(self, ccr_grammars): - raise DontUseBaseClassError(self) - - def wipe_ccr(self): - raise DontUseBaseClassError(self) diff --git a/castervoice/lib/ctrl/mgr/grammar_container/basic_grammar_container.py b/castervoice/lib/ctrl/mgr/grammar_container/basic_grammar_container.py deleted file mode 100644 index 1628c8544..000000000 --- a/castervoice/lib/ctrl/mgr/grammar_container/basic_grammar_container.py +++ /dev/null @@ -1,43 +0,0 @@ -from castervoice.lib.ctrl.mgr.grammar_container.base_grammar_container import BaseGrammarContainer - - -class BasicGrammarContainer(BaseGrammarContainer): - """ - Responsible for holding and destroying - CCR and non-CCR grammars. - """ - - def __init__(self): - """ - ccr grammars ALL get wiped every merge = list - non-ccr grammars get turned on/off one at a time = dict - """ - self._ccr_grammars = [] - self._non_ccr_grammars = {} - - def set_non_ccr(self, rcn, grammar): - if rcn in self._non_ccr_grammars: - old_grammar = self._non_ccr_grammars[rcn] - BasicGrammarContainer._empty_grammar(old_grammar) - del self._non_ccr_grammars[rcn] - - if grammar is not None: - self._non_ccr_grammars[rcn] = grammar - - def set_ccr(self, ccr_grammars): - # first, wipe out old ccr rules - for ccr_grammar in self._ccr_grammars: - BasicGrammarContainer._empty_grammar(ccr_grammar) - self._ccr_grammars = ccr_grammars - - def wipe_ccr(self): - self.set_ccr([]) - - @staticmethod - def _empty_grammar(grammar): - # disable all of the grammar's rules - for rule in grammar.rules: - rule.disable() - # disable / unload grammar - grammar.disable() - grammar.unload() diff --git a/castervoice/lib/ctrl/mgr/grammar_manager.py b/castervoice/lib/ctrl/mgr/grammar_manager.py deleted file mode 100644 index 9bc3a3b76..000000000 --- a/castervoice/lib/ctrl/mgr/grammar_manager.py +++ /dev/null @@ -1,394 +0,0 @@ -import os -import traceback - -from dragonfly import Grammar - -from castervoice.lib import printer -from castervoice.lib.ctrl.mgr.errors.invalid_companion_configuration_error import InvalidCompanionConfigurationError -from castervoice.lib.ctrl.mgr.errors.not_a_module import NotAModuleError -from castervoice.lib.ctrl.mgr.loading.load.content_request import ContentRequest -from castervoice.lib.ctrl.mgr.loading.load.content_type import ContentType -from castervoice.lib.ctrl.mgr.managed_rule import ManagedRule -from castervoice.lib.ctrl.mgr.rule_formatter import _set_rdescripts -from castervoice.lib.ctrl.mgr.rules_enabled_diff import RulesEnabledDiff -from castervoice.lib.merge.ccrmerging2.hooks.events.activation_event import RuleActivationEvent -from castervoice.lib.merge.ccrmerging2.hooks.events.on_error_event import OnErrorEvent -from castervoice.lib.merge.ccrmerging2.hooks.events.rules_loaded_event import RulesLoadedEvent -from castervoice.lib.merge.ccrmerging2.sorting.config_ruleset_sorter import ConfigBasedRuleSetSorter -from castervoice.lib.util.ordered_set import OrderedSet - - -class GrammarManager(object): - - def __init__(self, config, - merger, - content_loader, - ccr_rules_validator, - details_validator, - reload_observable, - activator, - mapping_rule_maker, - grammars_container, - hooks_runner, - ccr_toggle, - smrc, - t_runner, - companion_config, - combo_validator): - """ - Holds both the current merged ccr rules and the most recently instantiated/validated - copies of all ccr and non-ccr rules. - Loads all previously acti TODO this description - - TODO: this is a god object; it should be broken apart - - :param config: config impl which externally tracks which rules are activated - :param merger: The CCRMerger - :param ccr_rules_validator: validation for ccr rules - :param details_validator: validation of rule details configuration objects - :param reload_observable: the thing that signals that a file or files have changed - :param activator: manages the "enable/disable X" grammar - :param mapping_rule_maker: instantiates - :param grammars_container: holds and destroys grammars - :param hooks_runner: runs all hooks at different events - :param smrc: grants limited access to other parts of framework to selfmod rules- don't keep reference - :param t_runner: a reference is kept to it so can instantly activate its activation rule - :param companion_config: a config which controls which rules can be enabled/disabled instantly by other rules - :param combo_validator: validates all (ccr/non-ccr) rule+detail combinations - """ - self._config = config - self._merger = merger - self._content_loader = content_loader - self._ccr_rules_validator = ccr_rules_validator - self._details_validator = details_validator - self._reload_observable = reload_observable - self._activator = activator - self._mapping_rule_maker = mapping_rule_maker - self._grammars_container = grammars_container - self._hooks_runner = hooks_runner - self._ccr_toggle = ccr_toggle - self._transformers_runner = t_runner - self._companion_config = companion_config - self._combo_validator = combo_validator - - # rules: (class name : ManagedRule} - self._managed_rules = {} - # - self._reload_observable.register_listener(self) - '''The passed method references below would be a good place to start splitting the GM apart.''' - # - self._activator.set_activation_fn(lambda rcn, active: self._change_rule_enabled(rcn, active)) - # - smrc.set_reload_fn(lambda rcn: self._delegate_enable_rule(rcn, True)) - # - self._initial_activations_complete = False - - def initialize(self): - if self._initial_activations_complete: - return - - loaded_enabled_rcns = set(self._managed_rules.keys()) - enabled_ordered_rcns = self._config.get_enabled_rcns_ordered() - for rcn in enabled_ordered_rcns: - if rcn in loaded_enabled_rcns: - rd = self._managed_rules[rcn].get_details() - if rd.declared_ccrtype is None: - self._delegate_enable_rule(rcn, True) - else: - msg = "Skipping rule {} because it is enabled but not loaded." - printer.out(msg.format(rcn)) - if self._ccr_toggle.is_active(): - self._remerge_ccr_rules(enabled_ordered_rcns) - - is_timer_based_reload_observable = hasattr(self._reload_observable, "start") - if is_timer_based_reload_observable: - self._reload_observable.start() - - self._initial_activations_complete = True - - def register_rule(self, rule_class, details): - """ - Takes a newly loaded copy of a rule (MappingRule or MergeRule), - validates it, stores it for later instantiation, and adds it to the - file tracking list. - - :param rule_class: - :param details: - :return: - """ - class_name = rule_class.__name__ - - # do not load or watch invalid rules - invalidation = self._get_invalidation(rule_class, details) - if invalidation is not None: - printer.out(invalidation) - return - - _set_rdescripts(rule_class.mapping, class_name) - ''' - rule should be safe for loading at this point: register it - but do not load here -- this method only registers - ''' - managed_rule = ManagedRule(rule_class, details) - self._managed_rules[class_name] = managed_rule - # set up de/activation command - self._activator.register_rule(managed_rule) - # watch this file for future changes - if not details.watch_exclusion: - self._reload_observable.register_watched_file(details.get_filepath()) - - def _change_rule_enabled(self, class_name, enabled, tail=True): - """ - This is called by the GrammarActivator. The necessity of this function - means something is designed wrong. Correct this in the future. - - :param class_name: str - :param enabled: boolean - :param tail: (boolean) whether this is the tail call, since this fn is recursive - :return: - """ - - # load it - enabled_diff = self._delegate_enable_rule(class_name, enabled) - # run activation hooks - self._hooks_runner.execute(RuleActivationEvent(class_name, enabled)) - - if tail: - enabled_diff = self._handle_companion_rules(enabled_diff) - self._rewrite_config_file(enabled_diff) - - ''' - Roadmap: - 8. See about pointing everything at `_change_rule_enabled` which is currently pointed to `delegate_rule_enabled` - -> "everything" is 3 functions out of the 7 which point at both functions combined. This makes - `_change_rule_enabled` the center of the GM, rather than having two centers. - ''' - - def _rewrite_config_file(self, enabled_diff): - """ - :param enabled_diff: - :return: - """ - if len(enabled_diff.newly_enabled) + len(enabled_diff.newly_disabled) > 0: - result = OrderedSet(self._config.get_enabled_rcns_ordered()) - result.remove_all(enabled_diff.newly_disabled) - result.add_all(enabled_diff.newly_enabled) - self._config.replace_enabled(result.to_list()) - self._config.save() - - def _handle_companion_rules(self, enabled_diff): - newly_enabled = list() - newly_disabled = set() - diff = [(rcn, True) for rcn in enabled_diff.newly_enabled] + \ - [(rcn, False) for rcn in enabled_diff.newly_disabled] - for difference in diff: - rcn = difference[0] - enabled = difference[1] - for companion_rcn in self._companion_config.get_companions(rcn): - if companion_rcn in self._managed_rules: - mr = self._managed_rules[companion_rcn] - is_ccr = mr.get_details().declared_ccrtype is not None - if is_ccr: - raise InvalidCompanionConfigurationError(companion_rcn) - - self._change_rule_enabled(companion_rcn, enabled, False) - if enabled: - newly_enabled.append(companion_rcn) - else: - newly_disabled.add(companion_rcn) - else: - invalid_msg = "Invalid companion rule (not loaded): {}" - printer.out(invalid_msg.format(companion_rcn)) - - return RulesEnabledDiff(enabled_diff.newly_enabled + newly_enabled, - enabled_diff.newly_disabled | newly_disabled) - - def _delegate_enable_rule(self, class_name, enabled): - """ - Either creates a standalone Dragonfly rule or - delegates to the CCRMerger to create the merged rule(s). - - The created rule is then loaded and its grammar saved in the GrammarContainer. - If a rule of the same class name was already in the GrammarContainer, that - rule and its grammar are destroyed first, by the GrammarContainer. - - :param class_name: str - :param enabled: boolean - :return: RulesEnabledDiff - """ - - managed_rule = self._managed_rules[class_name] - - if managed_rule.get_details().declared_ccrtype is None: - return self._enable_non_ccr_rule(managed_rule, enabled) - else: - rcn = managed_rule.get_rule_class_name() - enabled_rules = OrderedSet(self._config.get_enabled_rcns_ordered()) - enabled_rules.update(rcn, enabled) - enabled_diff = self._remerge_ccr_rules(enabled_rules.to_list()) - place = enabled_diff.newly_enabled.append if enabled else enabled_diff.newly_disabled.add - place(rcn) - return enabled_diff - - def _remerge_ccr_rules(self, enabled_rcns): - """ - :return: RulesEnabledDiff - """ - # if the global ccr toggle was off, activating a ccr rule turns it back on - self._ccr_toggle.set_active(True) - - # handle CCR: get all active ccr rules after de/activating one - loaded_enabled_rcns = set(self._managed_rules.keys()) - active_rule_class_names = [rcn for rcn in enabled_rcns if rcn in loaded_enabled_rcns] - active_mrs = [self._managed_rules[rcn] for rcn in active_rule_class_names] - active_ccr_mrs = [mr for mr in active_mrs if mr.get_details().declared_ccrtype is not None] - self._hooks_runner.execute(RulesLoadedEvent(rules=active_ccr_mrs)) - ''' - The merge may result in 1 to n+1 rules where n is the number of ccr app rules - which are in the active rules list. - For instance, if you have 1 app rule, you'll end up with two ccr rules. This is because - the merger has to make the global one, plus an app rule with the app stuff plus all the - global stuff. - ''' - sorter = ConfigBasedRuleSetSorter(enabled_rcns) - merge_result = self._merger.merge_rules(active_ccr_mrs, sorter) - grammars = [] - for rule_and_context in merge_result.ccr_rules_and_contexts: - rule = rule_and_context[0] - context = rule_and_context[1] - grammar = Grammar(name="ccr-" + GrammarManager._get_next_id(), context=context) - grammar.add_rule(rule) - grammars.append(grammar) - self._grammars_container.set_ccr(grammars) - for grammar in grammars: - grammar.load() - - return merge_result.rules_enabled_diff - - def _enable_non_ccr_rule(self, managed_rule, enabled): - """ - :param managed_rule: - :param enabled: - :return: RulesEnabledDiff - """ - rcn = managed_rule.get_rule_class_name() - if enabled: - grammar = self._mapping_rule_maker.create_non_ccr_grammar(managed_rule) - self._grammars_container.set_non_ccr(rcn, grammar) - grammar.load() - return RulesEnabledDiff([rcn], frozenset()) - else: - self._grammars_container.set_non_ccr(rcn, None) - return RulesEnabledDiff(frozenset(), [rcn]) - - def receive(self, file_path_changed): - """ - This being called indicates that the file at file_path_changed has been updated - and that it should be reloaded and potentially replace the old copy. - - DO NOT CALL THIS MANUALLY. Should only be called by the reload observable. - - :param file_path_changed: str - :return: - """ - try: - module_dir = GrammarManager._get_module_package(file_path_changed) - module_name = GrammarManager._get_module_name_from_file_path(file_path_changed) - # request class name not needed here -- only needed on initial load - request = ContentRequest(ContentType.GET_RULE, module_dir, module_name, None) - rule_class, details = self._content_loader.idem_import_module(request) - # re-register: - self.register_rule(rule_class, details) - - class_name = rule_class.__name__ - if class_name in self._config.get_enabled_rcns_ordered(): - self._delegate_enable_rule(class_name, True) - except Exception as error: - printer.out('Grammar Manager: {} - See error message above'.format(error)) - self._hooks_runner.execute(OnErrorEvent()) - - def _get_invalidation(self, rule_class, details): - """ - Attempts to find a reason to invalidate the rule. Return reason if can find one. - :param rule_class: - :param details: RuleDetails - :return: - """ - - class_name = rule_class.__name__ - - '''validate details configuration before anything else''' - details_invalidation = self._details_validator.validate_details(details) - if details_invalidation is not None: - return "{} rejected due to detail validation errors: {}".format(class_name, details_invalidation) - - '''attempt to instantiate the rule''' - test_instance = None - try: - test_instance = rule_class() - except: # ignore warnings on this line-- it's supposed to be broad - traceback.print_exc() - return "{} rejected due to instantiation errors".format(class_name) - - '''if ccr, validate the rule''' - if details.declared_ccrtype is not None: - error = self._ccr_rules_validator.validate_rule(test_instance, details.declared_ccrtype) - if error is not None: - return "{} rejected due to rule validation errors: {}".format(class_name, error) - - '''do combo validations''' - combo_invalidation = self._combo_validator.validate(test_instance, details) - if combo_invalidation is not None: - return "{} rejected due to rule/details combination errors: {}".format(class_name, combo_invalidation) - - return None - - def load_activation_grammars(self): - """ - Caster core mechanisms should follow the same process as everything - else. This should lead to much greater consistency, but also the - ability to shut off core Caster mechanisms more easily if desired. - """ - rules = [self._activator.construct_activation_rule(), - self._hooks_runner.construct_activation_rule(), - self._transformers_runner.construct_activation_rule()] - rules = [rule for rule in rules if len(rule[0].mapping) > 0] # there might not be *any* transformers/hooks - if hasattr(self._reload_observable, "get_loadable"): - rules.append(self._reload_observable.get_loadable()) - - for rc, d in rules: - self.register_rule(rc, d) - self._change_rule_enabled(rc.__name__, True) - - def set_ccr_active(self, active): - self._ccr_toggle.set_active(active) - if not self._ccr_toggle.is_active(): - self._grammars_container.wipe_ccr() - else: - self._change_rule_enabled("Numbers", True) - - @staticmethod - def _get_module_name_from_file_path(file_path): - """ - Used by receive(), converts full file path to module name. - :param file_path: str - :return: str - """ - if file_path.startswith("__") or not file_path.endswith(".py"): - raise NotAModuleError(file_path) - return os.path.basename(file_path).replace(".py", "") - - @staticmethod - def _get_module_package(module_path): - return module_path[:module_path.rindex(os.sep)] - - @staticmethod - def _get_next_id(): - """ - Returns a unique id for grammar names. Used to name new CCR grammars. - :return: str - """ - if not hasattr(GrammarManager._get_next_id, "id"): - GrammarManager._get_next_id.id = 0 - GrammarManager._get_next_id.id += 1 - return str(GrammarManager._get_next_id.id) diff --git a/castervoice/lib/ctrl/mgr/loading/__init__.py b/castervoice/lib/ctrl/mgr/loading/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/ctrl/mgr/loading/load/__init__.py b/castervoice/lib/ctrl/mgr/loading/load/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/ctrl/mgr/loading/load/content_loader.py b/castervoice/lib/ctrl/mgr/loading/load/content_loader.py deleted file mode 100644 index 91c78c272..000000000 --- a/castervoice/lib/ctrl/mgr/loading/load/content_loader.py +++ /dev/null @@ -1,145 +0,0 @@ -import os -import traceback -from sys import path as syspath - -from castervoice.lib import settings, printer -from castervoice.lib.ctrl.mgr.errors.module_qualification_error import ModuleQualificationError -from castervoice.lib.ctrl.mgr.loading.load.content_root import ContentRoot -from castervoice.lib.ctrl.mgr.loading.load.content_type import ContentType -from castervoice.lib.ctrl.mgr.loading.load.initial_content import FullContentSet - - -class ContentLoader(object): - """ - ContentLoader loads all starter and user content when Caster starts. - It can also reload modules by name. - - - Load all once when Caster starts. Afterwards, unload/reload only what is requested. - Pass result off to GrammarManager. - """ - - def __init__(self, content_request_generator, module_load_fn, module_reload_fn, modules_accessor): - self._content_request_generator = content_request_generator - self._module_load_fn = module_load_fn - self._module_reload_fn = module_reload_fn - self._modules_accessor = modules_accessor - - def load_everything(self, rules_config): - # Generate all requests for both starter and user locations - base_path = settings.settings(["paths", "BASE_PATH"]) - user_dir = settings.settings(["paths", "USER_DIR"]) - - starter_content_requests = self._content_request_generator.get_all_content_modules(base_path) - user_content_requests = self._content_request_generator.get_all_content_modules(user_dir) - - # user content should trump starter content - syspath.append(user_dir) - requests = {} - for item in starter_content_requests: - requests[item.module_name] = item - for item in user_content_requests: - requests[item.module_name] = item - - # categorize requests - rule_requests = [] - transformer_requests = [] - hook_requests = [] - for module_name in requests: - request = requests[module_name] - if request.content_type == ContentType.GET_RULE and \ - rules_config.load_is_allowed(request.content_class_name): - rule_requests.append(request) - elif request.content_type == ContentType.GET_TRANSFORMER and \ - request.module_name == "text_replacer": - transformer_requests.append(request) - elif request.content_type == ContentType.GET_HOOK: - hook_requests.append(request) - - # attempt to load all content - rules = self._process_requests(rule_requests) - transformers = self._process_requests(transformer_requests) - hooks = self._process_requests(hook_requests) - - return FullContentSet(rules, transformers, hooks) - - def idem_import_module(self, request): - """ - Returns the content requested from the specified module. - """ - - # import the module - try: - fully_qualified_module_name = ContentLoader._fully_qualify_module_name(request) - except ModuleQualificationError: - msg = "Invalid user content request path: '{}'. Skipping '{}'." - printer.out(msg.format(request.directory, request.module_name)) - return None - - if self._modules_accessor.has_module(fully_qualified_module_name): - module = self._modules_accessor.get_module(fully_qualified_module_name) - module = self._reimport_module(module) - else: - module = self._import_module(fully_qualified_module_name) - - if module is None: - return None - - # get them and add them to nexus - try: - fn = getattr(module, request.content_type) - except AttributeError: - msg = "No method named '{}' was found on '{}'. Did you forget to implement it?" - printer.out(msg.format(request.content_type, request.module_name)) - return None - except Exception as e: - msg = "Error loading module '{}'." - printer.out(msg.format(request.module_name)) - return None - - return fn() - - def _process_requests(self, requests): - result = [] - - for request in requests: - content_item = self.idem_import_module(request) - if content_item is not None: - result.append(content_item) - - return result - - def _import_module(self, module_name): - """ - Attempts to import a module by name. - :param module_name: string - :return: (module) module - """ - - try: - return self._module_load_fn(module_name) - except Exception as e: - printer.out("Could not import '{}'. Module has errors: {}".format(module_name, traceback.format_exc())) - return None - - def _reimport_module(self, module): - try: - return self._module_reload_fn(module) - except Exception as e: - msg = "An error occurred while importing '{}': {}" - printer.out(msg.format(str(module), traceback.format_exc())) - return None - - @staticmethod - def _fully_qualify_module_name(request): - if ContentRoot.STARTER in request.directory: - root = ContentRoot.STARTER - elif ContentRoot.USER_DIR in request.directory: - root = ContentRoot.USER_DIR - else: - raise ModuleQualificationError() - - tokens = request.directory.split(os.sep) - root_index = tokens.index(root) - tokens_for_fully_qualified_module = tokens[root_index:] - tokens_for_fully_qualified_module.append(request.module_name) - return ".".join(tokens_for_fully_qualified_module) diff --git a/castervoice/lib/ctrl/mgr/loading/load/content_request.py b/castervoice/lib/ctrl/mgr/loading/load/content_request.py deleted file mode 100644 index 6c63223c8..000000000 --- a/castervoice/lib/ctrl/mgr/loading/load/content_request.py +++ /dev/null @@ -1,6 +0,0 @@ -class ContentRequest(object): - def __init__(self, content_type, directory, module_name, content_class_name): - self.content_type = content_type - self.directory = directory - self.module_name = module_name - self.content_class_name = content_class_name diff --git a/castervoice/lib/ctrl/mgr/loading/load/content_request_generator.py b/castervoice/lib/ctrl/mgr/loading/load/content_request_generator.py deleted file mode 100644 index a241d664f..000000000 --- a/castervoice/lib/ctrl/mgr/loading/load/content_request_generator.py +++ /dev/null @@ -1,88 +0,0 @@ -import re -import os - -from castervoice.lib.ctrl.mgr.loading.load.content_request import ContentRequest -from castervoice.lib.ctrl.mgr.loading.load.content_type import ContentType - - -class ContentRequestGenerator(object): - """ - Generates a set of requests from a path. - """ - - def get_all_content_modules(self, directory): - relevant_modules = [] - for dirpath, dirnames, filenames in self._walk(directory): - for filename in filenames: - file_path = dirpath + os.sep + filename - content_type, content_class_name = self._scan_file(file_path) - if content_type is not None: - module_name = filename[:-3] - request = ContentRequest(content_type, - dirpath, - module_name, - content_class_name) - relevant_modules.append(request) - return relevant_modules - - def _walk(self, directory): - """File i/o broken out for testability""" - return os.walk(directory) - - def _get_file_lines(self, file_path): - """File i/o broken out for testability""" - content = None - with open(file_path, encoding="utf8") as f: - content = f.readlines() - return content - - def _scan_file(self, file_path): - """ - Reads the whole file, classifies it as rule, transformer, hook, or none. - Also finds a list of potential names for the loadable content class. - :param file_path: str - :return: str - """ - if not file_path.endswith(".py"): - return None, None - if file_path.endswith("__init__.py"): - return None, None - - content = self._get_file_lines(file_path) - - rule_func = "def {}():".format(ContentType.GET_RULE) - transformer_func = "def {}():".format(ContentType.GET_TRANSFORMER) - hook_func = "def {}():".format(ContentType.GET_HOOK) - - content_type = None - content_class_name = None - for line in content: - if line.strip().startswith("#") or line.isspace(): - continue - # should only be ONE 'get_' function - if content_type is None: - if rule_func in line: - content_type = ContentType.GET_RULE - # if it's a rule, keep looking for the class name - continue - elif transformer_func in line: - content_type = ContentType.GET_TRANSFORMER - break - elif hook_func in line: - content_type = ContentType.GET_HOOK - break - else: - ccn = ContentRequestGenerator._extract_class_name(line) - if ccn is not None: - content_class_name = ccn - return content_type, content_class_name - - @staticmethod - def _extract_class_name(line): - class_name_match = re.search("return (.+?),", line) - if class_name_match is not None and len(class_name_match.groups()) == 1: - result = class_name_match.group(1) - result = result.replace("[", "").replace("(", "") - return result - return None - diff --git a/castervoice/lib/ctrl/mgr/loading/load/content_result.py b/castervoice/lib/ctrl/mgr/loading/load/content_result.py deleted file mode 100644 index 4e6c32cb3..000000000 --- a/castervoice/lib/ctrl/mgr/loading/load/content_result.py +++ /dev/null @@ -1,8 +0,0 @@ -class ContentResult(object): - def __init__(self, content_type, content_item): - """ - :param content_type: a string indicating the type - :param content_item: a rule, transformer, or hook - """ - self.content_type = content_type - self.content_item = content_item diff --git a/castervoice/lib/ctrl/mgr/loading/load/content_root.py b/castervoice/lib/ctrl/mgr/loading/load/content_root.py deleted file mode 100644 index 240be0287..000000000 --- a/castervoice/lib/ctrl/mgr/loading/load/content_root.py +++ /dev/null @@ -1,3 +0,0 @@ -class ContentRoot(object): - STARTER = "castervoice" - USER_DIR = "caster_user_content" diff --git a/castervoice/lib/ctrl/mgr/loading/load/content_type.py b/castervoice/lib/ctrl/mgr/loading/load/content_type.py deleted file mode 100644 index a85166694..000000000 --- a/castervoice/lib/ctrl/mgr/loading/load/content_type.py +++ /dev/null @@ -1,4 +0,0 @@ -class ContentType(object): - GET_RULE = "get_rule" - GET_TRANSFORMER = "get_transformer" - GET_HOOK = "get_hook" diff --git a/castervoice/lib/ctrl/mgr/loading/load/initial_content.py b/castervoice/lib/ctrl/mgr/loading/load/initial_content.py deleted file mode 100644 index d3679384e..000000000 --- a/castervoice/lib/ctrl/mgr/loading/load/initial_content.py +++ /dev/null @@ -1,8 +0,0 @@ -class FullContentSet(object): - """ - Initial content, loaded once when Caster starts. - """ - def __init__(self, rules, transformers, hooks): - self.rules = rules - self.transformers = transformers - self.hooks = hooks diff --git a/castervoice/lib/ctrl/mgr/loading/load/modules_access.py b/castervoice/lib/ctrl/mgr/loading/load/modules_access.py deleted file mode 100644 index c649680f9..000000000 --- a/castervoice/lib/ctrl/mgr/loading/load/modules_access.py +++ /dev/null @@ -1,11 +0,0 @@ -import sys - - -class SysModulesAccessor(object): - """read-only access to sys.modules""" - - def has_module(self, module_name): - return module_name in sys.modules - - def get_module(self, module_name): - return sys.modules[module_name] diff --git a/castervoice/lib/ctrl/mgr/loading/load/reload_fn_provider.py b/castervoice/lib/ctrl/mgr/loading/load/reload_fn_provider.py deleted file mode 100644 index 4c639eebc..000000000 --- a/castervoice/lib/ctrl/mgr/loading/load/reload_fn_provider.py +++ /dev/null @@ -1,9 +0,0 @@ -# pylint: skip-file -class ReloadFunctionProvider(object): - def get_reload_fn(self): - """ - Reimports an already imported module. Python 2/3 compatible method. - """ - #Python 3.12 support - from importlib import reload - return reload diff --git a/castervoice/lib/ctrl/mgr/loading/reload/__init__.py b/castervoice/lib/ctrl/mgr/loading/reload/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/ctrl/mgr/loading/reload/base_reload_observable.py b/castervoice/lib/ctrl/mgr/loading/reload/base_reload_observable.py deleted file mode 100644 index 6ec883438..000000000 --- a/castervoice/lib/ctrl/mgr/loading/reload/base_reload_observable.py +++ /dev/null @@ -1,63 +0,0 @@ -import hashlib -import os - -from castervoice.lib import printer - - -class BaseReloadObservable(object): - """ - Sends signal of some sort to registered listeners - that a file or directory needs reloading. - """ - - def __init__(self): - self._file_hashes = {} - self._listeners = [] - self._deleted = set() - - def register_listener(self, listener): - self._listeners.append(listener) - - def register_watched_file(self, file_path): - self._file_hashes[file_path] = BaseReloadObservable._get_hash_of_file(file_path) - - def _update(self): - file_paths = set(self._file_hashes.keys()) - for file_path in file_paths: - if not os.path.exists(file_path): - self._print_not_found_message(file_path) - continue - - known_file_hash = self._file_hashes[file_path] - current_file_hash = BaseReloadObservable._get_hash_of_file(file_path) - if known_file_hash != current_file_hash: - self._file_hashes[file_path] = current_file_hash - self._notify_listeners(file_path) - printer.out("Reloaded {}".format(file_path)) - - def _print_not_found_message(self, file_path): - """ - Print the 'not found' error only once. - """ - if file_path not in self._deleted: - msg = "{} appears to have been deleted or renamed. Please reboot Caster to re-track." - printer.out(msg.format(file_path)) - self._deleted.add(file_path) - - def _notify_listeners(self, path_changed): - for listener in self._listeners: - listener.receive(path_changed) - - @staticmethod - def _get_hash_of_file(file_path): - """ - Gets the hash of a file. - - :param file_path: - :return: hex string hash - """ - md5_hasher = hashlib.md5() - with open(file_path, 'rb') as module: - buf = module.read() - md5_hasher.update(buf) - return md5_hasher.hexdigest() diff --git a/castervoice/lib/ctrl/mgr/loading/reload/manual_reload_observable.py b/castervoice/lib/ctrl/mgr/loading/reload/manual_reload_observable.py deleted file mode 100644 index f4da26447..000000000 --- a/castervoice/lib/ctrl/mgr/loading/reload/manual_reload_observable.py +++ /dev/null @@ -1,30 +0,0 @@ -from dragonfly import Function, MappingRule - -from castervoice.lib.ctrl.mgr.loading.reload.base_reload_observable import BaseReloadObservable -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails - - -class ManualReloadObservable(BaseReloadObservable): - """ - Allows for reloading changed files on command. - """ - - def __init__(self): - super(ManualReloadObservable, self).__init__() - - ''' - This class itself will never be reloaded, but it can - be registered like the other rules and so can have - transformers run over it, etc. - ''' - class ManualGrammarReloadRule(MappingRule): - mapping = { - "reload all rules": Function(lambda: self._update()) - } - - self._rule_class = ManualGrammarReloadRule - - def get_loadable(self): - details = RuleDetails(name="caster manual grammars reload command rule", - watch_exclusion=True) - return self._rule_class, details diff --git a/castervoice/lib/ctrl/mgr/loading/reload/timer_reload_observable.py b/castervoice/lib/ctrl/mgr/loading/reload/timer_reload_observable.py deleted file mode 100644 index 18bfd7cf3..000000000 --- a/castervoice/lib/ctrl/mgr/loading/reload/timer_reload_observable.py +++ /dev/null @@ -1,18 +0,0 @@ -from dragonfly import get_current_engine - -from castervoice.lib.ctrl.mgr.loading.reload.base_reload_observable import BaseReloadObservable - - -class TimerReloadObservable(BaseReloadObservable): - - def __init__(self, time_in_seconds): - """ - Timer-based file watcher. Checks for file changes every time_in_seconds. - - :param time_in_seconds: number, time between checking for updates - """ - super(TimerReloadObservable, self).__init__() - self._time_in_seconds = time_in_seconds - - def start(self): - get_current_engine().create_timer(lambda: self._update(), self._time_in_seconds) diff --git a/castervoice/lib/ctrl/mgr/managed_rule.py b/castervoice/lib/ctrl/mgr/managed_rule.py deleted file mode 100644 index bbb5d89dc..000000000 --- a/castervoice/lib/ctrl/mgr/managed_rule.py +++ /dev/null @@ -1,17 +0,0 @@ -class ManagedRule(object): - - def __init__(self, rule_class, details): - self._rule_class = rule_class - self._details = details - - def get_rule_class_name(self): - return self._rule_class.__name__ - - def get_rule_instance(self): - return self._rule_class() - - def get_rule_class(self): - return self._rule_class - - def get_details(self): - return self._details diff --git a/castervoice/lib/ctrl/mgr/rule_details.py b/castervoice/lib/ctrl/mgr/rule_details.py deleted file mode 100644 index b6a4e3832..000000000 --- a/castervoice/lib/ctrl/mgr/rule_details.py +++ /dev/null @@ -1,62 +0,0 @@ -import inspect -import os -import traceback -from pathlib import Path - -from castervoice.lib import printer - - -class RuleDetails(object): - """ - A per-rule instantiation configuration. - """ - - def __init__(self, name=None, function_context=None, executable=None, title=None, grammar_name=None, - ccrtype=None, transformer_exclusion=False, - watch_exclusion=False): - """ - :param name: Dragonfly rule name - :param function_context: Dragonfly FunctionContext bool variable - :param executable: Dragonfly Context executable - :param title: Dragonfly Context title - :param grammar_name: Dragonfly grammar name - :param ccrtype: global, app, selfmod, or none - :param transformer_exclusion: exclude from transformations - :param watch_exclusion: should not be watched for changes ("system" rules) - """ - self.name = name - self.function_context = function_context - self.executable = executable - self.title = title - self.grammar_name = grammar_name - self.declared_ccrtype = ccrtype - self.transformer_exclusion = transformer_exclusion - self.watch_exclusion = watch_exclusion - - # Python black magic to determine which file to track: - stack = inspect.stack(0) - self._filepath = RuleDetails._calculate_filepath_from_frame(stack, 1) - - def __str__(self): - return 'ccrtype {}'.format(self.declared_ccrtype if self.declared_ccrtype else '_') - - @staticmethod - def _calculate_filepath_from_frame(stack, index): - try: - frame = stack[index] - # module = inspect.getmodule(frame[1]) - filepath = str(Path(frame[1])) - if filepath.endswith("pyc"): - filepath = filepath[:-1] - return filepath - except AttributeError: - if not os.path.isfile(frame[1]): - pyc = frame[1] + "c" - if os.path.isfile(pyc): - printer.out('\n {}\n Caster removed a stale .pyc file. Please, restart Caster. \n'.format(pyc)) - os.remove(pyc) - else: - traceback.print_exc() - - def get_filepath(self): - return self._filepath diff --git a/castervoice/lib/ctrl/mgr/rule_formatter.py b/castervoice/lib/ctrl/mgr/rule_formatter.py deleted file mode 100644 index 91c682b87..000000000 --- a/castervoice/lib/ctrl/mgr/rule_formatter.py +++ /dev/null @@ -1,21 +0,0 @@ -import re - -def _set_rdescripts(mapping, rcn): - for spec, action in mapping.items(): - # pylint: disable=no-member - _set_the_rdescript(action, spec, rcn) - - -def _set_the_rdescript(action, spec, rcn): - if hasattr(action, "rdescript") and action.rdescript is None: - action.rdescript = _create_rdescript(spec, rcn) - -def _create_rdescript(spec, rcn): - rule_name = rcn - for unnecessary in ["Non", "Rule", "Ccr", "CCR"]: - rule_name = rule_name.replace(unnecessary, "") - extras = "" - named_extras = re.findall(r"<(.*?)>", spec) - if named_extras: - extras = ", %(" + ")s, %(".join(named_extras) + ")s" - return "%s: %s%s" % (rule_name, spec, extras) diff --git a/castervoice/lib/ctrl/mgr/rule_maker/__init__.py b/castervoice/lib/ctrl/mgr/rule_maker/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/ctrl/mgr/rule_maker/base_rule_maker.py b/castervoice/lib/ctrl/mgr/rule_maker/base_rule_maker.py deleted file mode 100644 index fdcf6b128..000000000 --- a/castervoice/lib/ctrl/mgr/rule_maker/base_rule_maker.py +++ /dev/null @@ -1,4 +0,0 @@ -class BaseRuleMaker(object): - - def create_managed_rule(self, rule_class, details): - pass \ No newline at end of file diff --git a/castervoice/lib/ctrl/mgr/rule_maker/mapping_rule_maker.py b/castervoice/lib/ctrl/mgr/rule_maker/mapping_rule_maker.py deleted file mode 100644 index 4cdbcdad3..000000000 --- a/castervoice/lib/ctrl/mgr/rule_maker/mapping_rule_maker.py +++ /dev/null @@ -1,37 +0,0 @@ -from dragonfly import Grammar, FuncContext -from castervoice.lib.context import AppContext -from castervoice.lib.ctrl.mgr.rule_maker.base_rule_maker import BaseRuleMaker - - -class MappingRuleMaker(BaseRuleMaker): - """ - Creates a MappingRule instance from the rule's class and a RuleDetails - object, then runs all transformers over it. - """ - - def __init__(self, t_runner, smr_configurer): - self._transformers_runner = t_runner - self._smr_configurer = smr_configurer - self._name_uniquefier = 0 - - def create_non_ccr_grammar(self, managed_rule): - details = managed_rule.get_details() - rule_instance = managed_rule.get_rule_class()(name=details.name) - - if not details.transformer_exclusion: - rule_instance = self._transformers_runner.transform_rule(rule_instance) - - self._smr_configurer.configure(rule_instance) - - context = None - if details.function_context is not None: - context = AppContext(executable=details.executable, title=details.title) & FuncContext(function=details.function_context) - else: - if details.executable is not None or details.title is not None: - context = AppContext(executable=details.executable, title=details.title) - self._name_uniquefier += 1 - counter = "g" + str(self._name_uniquefier) - grammar_name = counter if details.grammar_name is None else details.grammar_name + counter - grammar = Grammar(name=grammar_name, context=context) - grammar.add_rule(rule_instance) - return grammar diff --git a/castervoice/lib/ctrl/mgr/rules_config.py b/castervoice/lib/ctrl/mgr/rules_config.py deleted file mode 100644 index a6f4ebbd5..000000000 --- a/castervoice/lib/ctrl/mgr/rules_config.py +++ /dev/null @@ -1,83 +0,0 @@ -from castervoice.lib import settings, const -from castervoice.lib.config.config_toml import TomlConfig - - -class RulesConfig(TomlConfig): - """ - This config file persists three things: - 1. which rules get loaded, either in whitelist mode or blacklist mode - 2. which rules are currently enabled - 3. the order of the enabled rules (important for merging) - """ - - _WHITELISTED = "whitelisted" - _ENABLED_ORDERED = "_enabled_ordered" - _INTERNAL = "_internal" - - def __init__(self): - super(RulesConfig, self).__init__(settings.SETTINGS["paths"]["RULES_CONFIG_PATH"]) - self.load() - self._initialize() - self._validate_enabled() - - def put(self, rule_class_name, active): - """ - Puts an rcn at the end of the "active" list. If it's not in the list, - it's appended. If it is in the list, it's moved. - - :param rule_class_name: (str) - :param active: (boolean) - :return: - """ - active_rules = self._config[RulesConfig._ENABLED_ORDERED] - active_rules = [rcn for rcn in active_rules if rcn != rule_class_name] - if active: - active_rules.append(rule_class_name) - self._config[RulesConfig._ENABLED_ORDERED] = active_rules - - def replace_enabled(self, enabled_ordered_rcns): - self._config[RulesConfig._ENABLED_ORDERED] = enabled_ordered_rcns - - def get_enabled_rcns_ordered(self): - return list(self._config[RulesConfig._ENABLED_ORDERED]) - - def load_is_allowed(self, rcn): - """ - EAFP here, since it shouldn't often be the case that unknown rules are - getting added. - """ - try: - return self._config[RulesConfig._WHITELISTED][rcn] - except KeyError: - self._config[RulesConfig._WHITELISTED][rcn] = True - self.save() - return self._config[RulesConfig._WHITELISTED][rcn] - - def _validate_enabled(self): - """ - Only internal and whitelisted rules should be able to get enabled. - """ - initial = self._config[RulesConfig._ENABLED_ORDERED] - validated = [] - for rcn in initial: - is_internal = rcn in self._config[RulesConfig._INTERNAL] - if is_internal: - validated.append(rcn) - continue - is_whitelisted = rcn in self._config[RulesConfig._WHITELISTED] \ - and self._config[RulesConfig._WHITELISTED][rcn] - if is_whitelisted: - validated.append(rcn) - if initial != validated: - self._config[RulesConfig._ENABLED_ORDERED] = validated - self.save() - - def _initialize(self): - """ - Initializes default values if the config is empty. - """ - if len(self._config) == 0: - self._config[RulesConfig._ENABLED_ORDERED] = list(const.CORE) - self._config[RulesConfig._WHITELISTED] = {rcn: True for rcn in const.CORE} - self._config[RulesConfig._INTERNAL] = list(const.INTERNAL) - self.save() diff --git a/castervoice/lib/ctrl/mgr/rules_enabled_diff.py b/castervoice/lib/ctrl/mgr/rules_enabled_diff.py deleted file mode 100644 index e30f1f153..000000000 --- a/castervoice/lib/ctrl/mgr/rules_enabled_diff.py +++ /dev/null @@ -1,4 +0,0 @@ -class RulesEnabledDiff(object): - def __init__(self, newly_enabled, newly_disabled): - self.newly_enabled = list(newly_enabled) - self.newly_disabled = set(newly_disabled) diff --git a/castervoice/lib/ctrl/mgr/validation/__init__.py b/castervoice/lib/ctrl/mgr/validation/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/ctrl/mgr/validation/combo/__init__.py b/castervoice/lib/ctrl/mgr/validation/combo/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/ctrl/mgr/validation/combo/base_combo_validator.py b/castervoice/lib/ctrl/mgr/validation/combo/base_combo_validator.py deleted file mode 100644 index 079dec594..000000000 --- a/castervoice/lib/ctrl/mgr/validation/combo/base_combo_validator.py +++ /dev/null @@ -1,11 +0,0 @@ -from castervoice.lib.ctrl.mgr.errors.base_class_error import DontUseBaseClassError - - -class BaseComboValidator(object): - """ - Identifies and rejects invalid rules; has access to their - RuleDetails objects. - """ - - def validate(self, rule, details): - raise DontUseBaseClassError(self) \ No newline at end of file diff --git a/castervoice/lib/ctrl/mgr/validation/combo/combo_validation_delegator.py b/castervoice/lib/ctrl/mgr/validation/combo/combo_validation_delegator.py deleted file mode 100644 index 8109fad9f..000000000 --- a/castervoice/lib/ctrl/mgr/validation/combo/combo_validation_delegator.py +++ /dev/null @@ -1,12 +0,0 @@ -class ComboValidationDelegator(object): - - def __init__(self, *validator_delegates): - self._validator_delegates = validator_delegates - - def validate(self, rule, details): - invalidations = [] - for delegate in self._validator_delegates: - invalidation = delegate.validate(rule, details) - if invalidation is not None: - invalidations.append(invalidation) - return None if len(invalidations) == 0 else ", ".join(invalidations) diff --git a/castervoice/lib/ctrl/mgr/validation/combo/non_empty_validator.py b/castervoice/lib/ctrl/mgr/validation/combo/non_empty_validator.py deleted file mode 100644 index b6861d7eb..000000000 --- a/castervoice/lib/ctrl/mgr/validation/combo/non_empty_validator.py +++ /dev/null @@ -1,26 +0,0 @@ -from castervoice.lib.ctrl.mgr.validation.combo.base_combo_validator import BaseComboValidator -from castervoice.lib.merge.selfmod.selfmodrule import BaseSelfModifyingRule - - -class RuleNonEmptyValidator(BaseComboValidator): - """ - Any static rule should have at least one command to start. - - Some selfmod rules don't have any rules the first time they - are instantiated, but then immediately fill in and "reboot" - themselves. - - SikuliRule is not a selfmod rule, but it kind of works like - one, so it is also exempted. - """ - - def validate(self, rule, details): - invalidations = [] - if len(rule.mapping) == 0 and not self._rule_is_exempt(rule): - invalidations.append("rules must have at least one command") - return None if len(invalidations) == 0 else ", ".join(invalidations) - - def _rule_is_exempt(self, rule): - selfmod = isinstance(rule, BaseSelfModifyingRule) - sikuli = rule.__class__.__name__ == "SikuliRule" - return selfmod or sikuli diff --git a/castervoice/lib/ctrl/mgr/validation/combo/rule_family_validator.py b/castervoice/lib/ctrl/mgr/validation/combo/rule_family_validator.py deleted file mode 100644 index e3edaef78..000000000 --- a/castervoice/lib/ctrl/mgr/validation/combo/rule_family_validator.py +++ /dev/null @@ -1,45 +0,0 @@ -from dragonfly import MappingRule - -from castervoice.lib.const import CCRType -from castervoice.lib.ctrl.mgr.validation.combo.base_combo_validator import BaseComboValidator -from castervoice.lib.merge.mergerule import MergeRule -from castervoice.lib.merge.selfmod.selfmodrule import BaseSelfModifyingRule - - -class RuleFamilyValidator(BaseComboValidator): - """ - Non-MappingRules are not handled by Caster. - MappingRules must not have ccrtypes. - MergeRules must have ccrtypes. - SelfModifyingRules can have ccrtypes. - CCR SelfModifyingRules must use correct type. - Nothing else is allowed to use SelfModifyingRules CCR type. - Function Context must not have CCRType `GLOBAL` or `SELFMOD` - """ - - def validate(self, rule, details): - mapping = isinstance(rule, MappingRule) - merge = isinstance(rule, MergeRule) - selfmod = isinstance(rule, BaseSelfModifyingRule) - has_ccrtype = details.declared_ccrtype is not None - has_function_context = details.function_context is not None - - invalidations = [] - - if not mapping: - invalidations.append("non-MappingRule rules are not handled") - elif mapping and not merge and has_ccrtype: - invalidations.append("MappingRules must not have a ccrtype") - elif merge and not selfmod: - if not has_ccrtype: - invalidations.append("MergeRules must have a ccrtype") - elif details.declared_ccrtype == CCRType.SELFMOD: - invalidations.append("non-SelfModifyingRules must not use CCRType.SELFMOD") - elif selfmod and has_ccrtype and details.declared_ccrtype != CCRType.SELFMOD: - invalidations.append("CCR SelfModifyingRules must use CCRType.SELFMOD") - if has_function_context and has_ccrtype: - if details.declared_ccrtype == CCRType.GLOBAL or details.declared_ccrtype == CCRType.SELFMOD: - invalidations.append("Function Context cannot be used with `CCRType.GLOBAL` or `CCRType.SELFMOD`") - - - return None if len(invalidations) == 0 else ", ".join(invalidations) diff --git a/castervoice/lib/ctrl/mgr/validation/combo/treerule_validator.py b/castervoice/lib/ctrl/mgr/validation/combo/treerule_validator.py deleted file mode 100644 index 867668c95..000000000 --- a/castervoice/lib/ctrl/mgr/validation/combo/treerule_validator.py +++ /dev/null @@ -1,30 +0,0 @@ -from dragonfly import ActionBase -from castervoice.lib.ctrl.mgr.validation.combo.base_combo_validator import BaseComboValidator -from castervoice.lib.merge.selfmod.tree_rule.tree_node import TreeNode -from castervoice.lib.merge.selfmod.tree_rule.tree_rule import TreeRule - - -class TreeRuleValidator(BaseComboValidator): - - def validate(self, rule, details): - if not isinstance(rule, TreeRule): - return None - - return TreeRuleValidator._validate_node(rule._root_node) - - @staticmethod - def _validate_node(node): - spec = node.get_spec() - action = node.get_action() - children = node.get_children() - err = str(spec) + ", " + str(action) + ", " + str(children) - - invalidations = [] - if not isinstance(spec, str): - invalidations.append("node spec must be string ({})".format(err)) - if not isinstance(action, ActionBase): - invalidations.append("node base must be ActionBase ({})".format(err)) - for ck in children.keys(): - if not isinstance(children[ck], TreeNode): - invalidations.append("children must be nodes ({})".format(err)) - return None if len(invalidations) == 0 else ", ".join(invalidations) diff --git a/castervoice/lib/ctrl/mgr/validation/details/__init__.py b/castervoice/lib/ctrl/mgr/validation/details/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/ctrl/mgr/validation/details/base_validator.py b/castervoice/lib/ctrl/mgr/validation/details/base_validator.py deleted file mode 100644 index d32bd26b0..000000000 --- a/castervoice/lib/ctrl/mgr/validation/details/base_validator.py +++ /dev/null @@ -1,18 +0,0 @@ -from castervoice.lib.ctrl.mgr.errors.base_class_error import DontUseBaseClassError - - -class BaseDetailsValidator(object): - - def validate(self, details): - """ - Details validation, vs rules validation, is about detecting invalid configurations. - There is no need to check anything here about how the rule matches the configuration. - Details validators are only about the details objects not themselves being valid. - - Takes a Details, returns error messages if certain kind of invalid configuration - is contained within it. - - :param details: RuleDetails - :return: str - """ - raise DontUseBaseClassError(self) diff --git a/castervoice/lib/ctrl/mgr/validation/details/ccr_app_validator.py b/castervoice/lib/ctrl/mgr/validation/details/ccr_app_validator.py deleted file mode 100644 index 917277188..000000000 --- a/castervoice/lib/ctrl/mgr/validation/details/ccr_app_validator.py +++ /dev/null @@ -1,16 +0,0 @@ -from castervoice.lib.const import CCRType -from castervoice.lib.ctrl.mgr.validation.details.base_validator import BaseDetailsValidator - - -class AppCCRDetailsValidator(BaseDetailsValidator): - - ''' - Validates any CCR (APP-type) Details - ''' - def validate(self, details): - invalidations = [] - if details.declared_ccrtype == CCRType.APP: - if details.executable is None: - invalidations.append("ccr app types must have 'executable'") - - return None if len(invalidations) == 0 else ", ".join(invalidations) diff --git a/castervoice/lib/ctrl/mgr/validation/details/ccr_validator.py b/castervoice/lib/ctrl/mgr/validation/details/ccr_validator.py deleted file mode 100644 index f4150603e..000000000 --- a/castervoice/lib/ctrl/mgr/validation/details/ccr_validator.py +++ /dev/null @@ -1,17 +0,0 @@ -from castervoice.lib.ctrl.mgr.validation.details.base_validator import BaseDetailsValidator - - -class CCRDetailsValidator(BaseDetailsValidator): - """ - Validates any CCR Details - """ - - def validate(self, details): - invalidations = [] - if details.declared_ccrtype is not None: - if details.name is not None: - invalidations.append("ccr types must not have 'name'") - if details.grammar_name is not None: - invalidations.append("ccr types must not have 'grammar_name'") - - return None if len(invalidations) == 0 else ", ".join(invalidations) \ No newline at end of file diff --git a/castervoice/lib/ctrl/mgr/validation/details/details_validation_delegator.py b/castervoice/lib/ctrl/mgr/validation/details/details_validation_delegator.py deleted file mode 100644 index 085ab01b4..000000000 --- a/castervoice/lib/ctrl/mgr/validation/details/details_validation_delegator.py +++ /dev/null @@ -1,12 +0,0 @@ -class DetailsValidationDelegator(object): - - def __init__(self, *validator_delegates): - self._validator_delegates = validator_delegates - - def validate_details(self, details): - invalidations = [] - for delegate in self._validator_delegates: - invalidation = delegate.validate(details) - if invalidation is not None: - invalidations.append(invalidation) - return None if len(invalidations) == 0 else ", ".join(invalidations) diff --git a/castervoice/lib/ctrl/mgr/validation/details/non_ccr_validator.py b/castervoice/lib/ctrl/mgr/validation/details/non_ccr_validator.py deleted file mode 100644 index cab8f5201..000000000 --- a/castervoice/lib/ctrl/mgr/validation/details/non_ccr_validator.py +++ /dev/null @@ -1,17 +0,0 @@ -from castervoice.lib.ctrl.mgr.validation.details.base_validator import BaseDetailsValidator - - -class NonCCRDetailsValidator(BaseDetailsValidator): - """ - Validates any non-CCR Details - """ - - def validate(self, details): - invalidations = [] - if details.declared_ccrtype is None: - if details.name is None: - invalidations.append("non-ccr types must have 'name'") - if details.get_filepath() is None: - invalidations.append("non-ccr types must not have a filepath") - - return None if len(invalidations) == 0 else ", ".join(invalidations) \ No newline at end of file diff --git a/castervoice/lib/ctrl/mgr/validation/rules/__init__.py b/castervoice/lib/ctrl/mgr/validation/rules/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/ctrl/mgr/validation/rules/base_validator.py b/castervoice/lib/ctrl/mgr/validation/rules/base_validator.py deleted file mode 100644 index 7136231d0..000000000 --- a/castervoice/lib/ctrl/mgr/validation/rules/base_validator.py +++ /dev/null @@ -1,16 +0,0 @@ -class BaseRuleValidator(object): - - def is_applicable(self, declared_ccrtype): - return False - - def _is_valid(self, rule): - return True - - def _invalid_message(self): - return "base rule message -- you should not see this" - - def validate(self, rule): - if not self._is_valid(rule): - return self._invalid_message() - else: - return None diff --git a/castervoice/lib/ctrl/mgr/validation/rules/mergerule_validator.py b/castervoice/lib/ctrl/mgr/validation/rules/mergerule_validator.py deleted file mode 100644 index 9bb0e7a6a..000000000 --- a/castervoice/lib/ctrl/mgr/validation/rules/mergerule_validator.py +++ /dev/null @@ -1,14 +0,0 @@ -from castervoice.lib.ctrl.mgr.validation.rules.base_validator import BaseRuleValidator -from castervoice.lib.merge.mergerule import MergeRule - - -class IsMergeRuleValidator(BaseRuleValidator): - - def is_applicable(self, declared_ccrtype): - return declared_ccrtype is not None - - def _is_valid(self, rule): - return isinstance(rule, MergeRule) - - def _invalid_message(self): - return "must be or inherit MergeRule" diff --git a/castervoice/lib/ctrl/mgr/validation/rules/not_treerule_validator.py b/castervoice/lib/ctrl/mgr/validation/rules/not_treerule_validator.py deleted file mode 100644 index e0f8b514f..000000000 --- a/castervoice/lib/ctrl/mgr/validation/rules/not_treerule_validator.py +++ /dev/null @@ -1,14 +0,0 @@ -from castervoice.lib.const import CCRType -from castervoice.lib.ctrl.mgr.validation.rules.base_validator import BaseRuleValidator - - -class NotTreeRuleValidator(BaseRuleValidator): - - def is_applicable(self, declared_ccrtype): - return declared_ccrtype == CCRType.SELFMOD - - def _is_valid(self, rule): - return not hasattr(rule, "master_node") - - def _invalid_message(self): - return "must not be or inherit TreeRule" diff --git a/castervoice/lib/ctrl/mgr/validation/rules/rule_validation_delegator.py b/castervoice/lib/ctrl/mgr/validation/rules/rule_validation_delegator.py deleted file mode 100644 index 1cc464427..000000000 --- a/castervoice/lib/ctrl/mgr/validation/rules/rule_validation_delegator.py +++ /dev/null @@ -1,13 +0,0 @@ -class CCRRuleValidationDelegator(object): - - def __init__(self, *validator_delegates): - self._validator_delegates = validator_delegates - - def validate_rule(self, rule, declared_ccrtype): - invalidations = [] - for delegate in self._validator_delegates: - if delegate.is_applicable(declared_ccrtype): - invalidation = delegate.validate(rule) - if invalidation is not None: - invalidations.append(invalidation) - return None if len(invalidations) == 0 else ", ".join(invalidation) diff --git a/castervoice/lib/ctrl/mgr/validation/rules/selfmod_validator.py b/castervoice/lib/ctrl/mgr/validation/rules/selfmod_validator.py deleted file mode 100644 index 6a7cab8dd..000000000 --- a/castervoice/lib/ctrl/mgr/validation/rules/selfmod_validator.py +++ /dev/null @@ -1,15 +0,0 @@ -from castervoice.lib.const import CCRType -from castervoice.lib.ctrl.mgr.validation.rules.base_validator import BaseRuleValidator -from castervoice.lib.merge.selfmod.selfmodrule import BaseSelfModifyingRule - - -class CCRSelfModifyingRuleValidator(BaseRuleValidator): - - def is_applicable(self, declared_ccrtype): - return declared_ccrtype == CCRType.SELFMOD - - def _is_valid(self, rule): - return isinstance(rule, BaseSelfModifyingRule) - - def _invalid_message(self): - return "must inherit BaseSelfModifyingRule" diff --git a/castervoice/lib/ctrl/nexus.py b/castervoice/lib/ctrl/nexus.py deleted file mode 100644 index b65d5af68..000000000 --- a/castervoice/lib/ctrl/nexus.py +++ /dev/null @@ -1,186 +0,0 @@ -from castervoice.lib.ctrl.mgr.grammar_container.basic_grammar_container import BasicGrammarContainer -from castervoice.lib.ctrl.mgr.ccr_toggle import CCRToggle -from castervoice.lib.ctrl.mgr.companion.companion_config import CompanionConfig -from castervoice.lib.ctrl.mgr.grammar_activator import GrammarActivator -from castervoice.lib.ctrl.mgr.loading.reload.manual_reload_observable import ManualReloadObservable -from castervoice.lib.ctrl.mgr.loading.reload.timer_reload_observable import TimerReloadObservable -from castervoice.lib.ctrl.mgr.rule_maker.mapping_rule_maker import MappingRuleMaker -from castervoice.lib.ctrl.mgr.rules_config import RulesConfig -from castervoice.lib.ctrl.mgr.validation.combo.combo_validation_delegator import ComboValidationDelegator -from castervoice.lib.ctrl.mgr.validation.combo.non_empty_validator import RuleNonEmptyValidator -from castervoice.lib.ctrl.mgr.validation.combo.rule_family_validator import RuleFamilyValidator -from castervoice.lib.ctrl.mgr.validation.combo.treerule_validator import TreeRuleValidator -from castervoice.lib.merge.ccrmerging2.compatibility.simple_compat_checker import SimpleCompatibilityChecker -from castervoice.lib.merge.ccrmerging2.hooks.hooks_config import HooksConfig -from castervoice.lib.merge.ccrmerging2.hooks.hooks_runner import HooksRunner -from castervoice.lib.merge.ccrmerging2.sorting.config_ruleset_sorter import ConfigBasedRuleSetSorter -from castervoice.lib.merge.ccrmerging2.transformers.transformers_config import TransformersConfig -from castervoice.lib.merge.ccrmerging2.transformers.transformers_runner import TransformersRunner -from castervoice.lib.merge.mergerule import MergeRule -from castervoice.lib import settings -from castervoice.lib.ctrl.mgr.validation.details.ccr_app_validator import AppCCRDetailsValidator -from castervoice.lib.ctrl.mgr.validation.details.ccr_validator import CCRDetailsValidator -from castervoice.lib.ctrl.mgr.validation.details.details_validation_delegator import DetailsValidationDelegator -from castervoice.lib.ctrl.mgr.validation.details.non_ccr_validator import NonCCRDetailsValidator -from castervoice.lib.ctrl.mgr.validation.rules.mergerule_validator import IsMergeRuleValidator -from castervoice.lib.ctrl.mgr.validation.rules.not_treerule_validator import NotTreeRuleValidator -from castervoice.lib.ctrl.mgr.validation.rules.selfmod_validator import CCRSelfModifyingRuleValidator -from castervoice.lib.merge.communication import Communicator -from castervoice.lib.merge.selfmod.smr_configurer import SelfModRuleConfigurer -from castervoice.lib.merge.state.stack import CasterState -from castervoice.lib.ctrl.mgr.grammar_manager import GrammarManager -from castervoice.lib.ctrl.mgr.validation.rules.rule_validation_delegator import CCRRuleValidationDelegator -from castervoice.lib.merge.ccrmerging2.ccrmerger2 import CCRMerger2 -from castervoice.lib.merge.ccrmerging2.merging.classic_merging_strategy import ClassicMergingStrategy -from castervoice.lib.ctrl.mgr.engine_manager import EngineModesManager -from castervoice.lib.ctrl.mgr.exclusivity_manager import ExclusiveManager - -class Nexus: - def __init__(self, content_loader): - """ - The Nexus is the 'glue code' of Caster. It is where the things reside which - manage global state. It is also an access point to those things for other - things which need them. This access should be limited. - """ - - '''CasterState is used for impl of the asynchronous actions''' - - self.state = CasterState() - - '''rpc class for interacting with Caster UI elements via xmlrpclib''' - self.comm = Communicator() - - '''tracks both which rules are enabled and the rules' order''' - rules_config = RulesConfig() - - '''does post-instantiation configuration on selfmodrules''' - smrc = SelfModRuleConfigurer() - - '''hooks runner: receives and runs events, manages its hooks''' - hooks_config = HooksConfig() - hooks_runner = HooksRunner(hooks_config) - smrc.set_hooks_runner(hooks_runner) - - '''does transformations on rules when rules are activated''' - transformers_config = TransformersConfig() - transformers_runner = TransformersRunner(transformers_config) - - '''the ccrmerger -- only merges MergeRules''' - self._merger = Nexus._create_merger(smrc, transformers_runner) - - '''unified loading mechanism for [rules, transformers, hooks] - from [caster starter locations, user dir]''' - self._content_loader = content_loader - - '''mapping rule maker: like the ccrmerger, but doesn't merge and isn't ccr''' - mapping_rule_maker = MappingRuleMaker(transformers_runner, smrc) - - '''the grammar manager -- probably needs to get broken apart more''' - self._grammar_manager = Nexus._create_grammar_manager(self._merger, - self._content_loader, hooks_runner, rules_config, smrc, mapping_rule_maker, - transformers_runner) - - '''ACTION TIME:''' - self._load_and_register_all_content(rules_config, hooks_runner, transformers_runner) - self._grammar_manager.initialize() - - '''engine mode manager imp engine engine modes per engine''' - self.engine_modes_manager = EngineModesManager(ExclusiveManager()) - - def _load_and_register_all_content(self, rules_config, hooks_runner, transformers_runner): - """ - all rules go to grammar_manager - all transformers go to transformers runner - all hooks go to hooks runner - """ - content = self._content_loader.load_everything(rules_config) - [self._grammar_manager.register_rule(rc, d) for rc, d in content.rules] - [transformers_runner.add_transformer(t) for t in content.transformers] - [hooks_runner.add_hook(h) for h in content.hooks] - self._grammar_manager.load_activation_grammars() - - @staticmethod - def _create_ccr_rule_validator(): - return CCRRuleValidationDelegator( - IsMergeRuleValidator(), - CCRSelfModifyingRuleValidator(), - NotTreeRuleValidator() - ) - - @staticmethod - def _create_details_validator(): - return DetailsValidationDelegator( - CCRDetailsValidator(), - AppCCRDetailsValidator(), - NonCCRDetailsValidator(), - ) - - @staticmethod - def _create_combo_validator(): - return ComboValidationDelegator( - RuleFamilyValidator(), - RuleNonEmptyValidator(), - TreeRuleValidator() - ) - - @staticmethod - def _create_grammar_manager(merger, content_loader, hooks_runner, rule_config, smrc, - mapping_rule_maker, transformers_runner): - """ - This is where settings should be used to alter the dependency injection being done. - Setting things to alternate implementations can live here. - - :param merger: - :param content_loader: - :param hooks_runner: - :param rule_config - :param smrc - :param mapping_rule_maker - :param transformers_runner - :return: - """ - - ccr_toggle = CCRToggle() - - ccr_rule_validator = Nexus._create_ccr_rule_validator() - details_validator = Nexus._create_details_validator() - combo_validator = Nexus._create_combo_validator() - - timer = settings.SETTINGS["grammar_reloading"]["reload_timer_seconds"] - observable = TimerReloadObservable(timer) - if settings.SETTINGS["grammar_reloading"]["reload_trigger"] == "manual": - observable = ManualReloadObservable() - - grammars_container = BasicGrammarContainer() - - activator = GrammarActivator(lambda rule: isinstance(rule, MergeRule)) - - companion_config = CompanionConfig() - - gm = GrammarManager(rule_config, - merger, - content_loader, - ccr_rule_validator, - details_validator, - observable, - activator, - mapping_rule_maker, - grammars_container, - hooks_runner, - ccr_toggle, - smrc, - transformers_runner, - companion_config, - combo_validator) - return gm - - @staticmethod - def _create_merger(smrc, transformers_runner): - compat_checker = SimpleCompatibilityChecker() - merge_strategy = ClassicMergingStrategy() - max_repetitions = settings.settings(["miscellaneous", "max_ccr_repetitions"]) - - return CCRMerger2(transformers_runner, compat_checker, merge_strategy, max_repetitions, smrc) - - def set_ccr_active(self, active): - self._grammar_manager.set_ccr_active(active) diff --git a/castervoice/lib/ctrl/updatecheck.py b/castervoice/lib/ctrl/updatecheck.py deleted file mode 100644 index 05e0f6799..000000000 --- a/castervoice/lib/ctrl/updatecheck.py +++ /dev/null @@ -1,107 +0,0 @@ -import os -import sys -import socket -import subprocess -from datetime import datetime, date - -from castervoice.lib import settings -from castervoice.lib.ctrl.dependencies import find_pip, install_type # pylint: disable=no-name-in-module -from castervoice.lib import printer - -update = None - - -def internet_check(host="1.1.1.1", port=53, timeout=3): - """ - Checks for network connection via DNS resolution. - :param host: CloudFire DNS - :param port: 53/tcp - :param timeout: An integer - :return: True or False - """ - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - s.settimeout(timeout) - s.connect((host, port)) - return True - except socket.error as e: - if e.errno == 11001: - printer.out("Caster: Internet check failed to resolve CloudFire DNS") - if e.errno == 10051: # Unreachable Network - pass - if e.errno not in (10051, 11001): # Unknown Error - printer.out(e.errno) - return False - - -def update_check(command=None): - """ - Check for updates pip packages castervoice/dragonfly2 - :param command: str - """ - global update - com = [find_pip(), "search", command] - startupinfo = None - try: - if os.name == 'nt': - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - p = subprocess.Popen(com, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - stdin=subprocess.PIPE, - startupinfo=startupinfo) - out = p.communicate('') - for line in out: - if b"INSTALLED" and b"latest" in line: - printer.out("Caster: {0} is up-to-date".format(command.strip('2'))) - update = False - break - else: - printer.out("Caster: Say 'Update {0}' to update.".format(command.strip('2'))) - update = True - break - except Exception as e: - printer.out("Exception from starting subprocess {0}: " "{1}".format(com, e)) - - -def update_timer(): - """ - Checks for updates every X days on startup - :return: True or False - """ - onlinemode = settings.SETTINGS["online"]["online_mode"] - lastupdate = settings.SETTINGS["online"]["last_update_date"] - updateinterval = settings.SETTINGS["online"]["update_interval"] - if lastupdate == 'None': - lastupdate = str(date.today()) - settings.SETTINGS["online"]["last_update_date"] = lastupdate - if onlinemode: - today = date.today() - lastdate = datetime.strptime(lastupdate, "%Y-%m-%d").date() - diff = today - lastdate - if diff.days >= updateinterval: # int Days - if internet_check(): - settings.SETTINGS["online"]["last_update_date"] = str(date.today()) - printer.out("Searching for updates...") - return True - else: - printer.out("\nCaster: Network off-line check network connection\n") - return False - else: - return False - else: - printer.out("\nCaster: Off-line mode is enabled\n") - return False - - -class UpdateChecker(object): - """ - Initializes Update Checker functions - """ - def initialize(self): - install = install_type() - if update_timer(): - update_check(command="dragonfly2") - if install == "pip": - update_check(command="castervoice") \ No newline at end of file diff --git a/castervoice/lib/dev/__init__.py b/castervoice/lib/dev/__init__.py deleted file mode 100644 index 5257a04e2..000000000 --- a/castervoice/lib/dev/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from castervoice.lib.dev import dev \ No newline at end of file diff --git a/castervoice/lib/dev/dev.py b/castervoice/lib/dev/dev.py deleted file mode 100644 index f0da450b6..000000000 --- a/castervoice/lib/dev/dev.py +++ /dev/null @@ -1,240 +0,0 @@ -import os -import shutil -from subprocess import Popen -import time -import threading -import shlex - -from dragonfly import (Function, BringApp, WaitWindow, Dictation, Choice, Grammar, - MappingRule, Paste, ShortIntegerRef) - -from castervoice.lib import utilities, settings, context, control -from castervoice.lib.dev import devgen -from castervoice.lib.actions import Key, Text - -from castervoice.lib.merge.state.actions import ContextSeeker, AsynchronousAction, \ - RegisteredAction -from castervoice.lib.merge.state.actions2 import NullAction, ConfirmAction, \ - BoxAction -from castervoice.lib.merge.state.short import L, S, R -from castervoice.lib.merge.state.stackitems import StackItemRegisteredAction -# from castervoice.lib.tests import testrunner # Deprecated -# from castervoice.lib.tests.test_complexity import run_tests # Deprecated -# from castervoice.lib.tests.testutils import MockAlternative # Deprecated - -if os.path.isfile(settings.SETTINGS["paths"]["CONFIGDEBUGTXT_PATH"]) is False: - configdebug_default = settings.SETTINGS["paths"][ - "BASE_PATH"] + "/bin/data/configdebug.txt" - configdebug_user = settings.SETTINGS["paths"]["CONFIGDEBUGTXT_PATH"] - shutil.copy(configdebug_default, configdebug_user) - -grammar = Grammar('development') - - -def experiment(): - '''This function is for test''' - - -def run_remote_debugger(): - utilities.remote_debug("dev.py") - - -COUNT = 5 - - -def countdown(): - global COUNT - print(COUNT) - COUNT -= 1 - return COUNT == 0 - - -def grep_this(path, filetype): - c = None - tries = 0 - while c is None: - tries += 1 - results = context.read_selected_without_altering_clipboard() - error_code = results[0] - if error_code == 0: - c = results[1] - break - if tries > 5: - return False - grep = "D:/PROGRAMS/NON_install/AstroGrep/AstroGrep.exe" - Popen([ - grep, "/spath=\"" + str(path) + "\"", "/stypes=\"" + str(filetype) + "\"", - "/stext=\"" + str(c) + "\"", "/s" - ]) - - -def bring_test(): - print(settings.SETTINGS["paths"]["BASE_PATH"].replace("/", "\\")) - try: - BringApp("explorer", settings.SETTINGS["paths"]["BASE_PATH"]).execute() - except Exception: - utilities.simple_log() - - -def launch_url(url): - command = utilities.default_browser_command() - if not command: - threading.Thread(target=os.startfile, args=(url, )).start() # pylint: disable=no-member - else: - path = command.replace('%1', url) - Popen(shlex.split(path)) - - -class DevelopmentHelp(MappingRule): - mapping = { - # castervoice development tools - "(show | open) documentation": - Function(launch_url), - "open natlink folder": - R(BringApp("C:/Windows/explorer.exe", - settings.SETTINGS["paths"]["BASE_PATH"].replace("/", "\\")), - rdescript="Open Natlink Folder"), - "refresh debug file": - R(Function(devgen.refresh), rdescript="Dev: Refreshed Debug File"), - "Agrippa ": - Function(grep_this), -# "run rule complexity test": -# Function(lambda: run_tests()), -# "run unit tests": -# Function(testrunner.run_tests), - "run remote debugger": - Function(run_remote_debugger), - } - extras = [ - Dictation("text"), - Choice("path", { - "natlink": "c:/natlink/natlink", - "sea": "C:/", - }), - Choice("filetype", { - "java": "*.java", - "python": "*.py", - }), - Choice( - "url", { - "caster": "https://dictation-toolbox.github.io/Caster", - "dragonfly": "https://dragonfly2.readthedocs.io/en/latest/", - }), - ] - defaults = {"text": ""} - - -class Experimental(MappingRule): - - mapping = { - # experimental/incomplete commands - "experiment": Function(experiment), - "short talk number ": Text("%(n2)d"), - # "dredge [ ]": Function(dredge), - "test dragonfly paste": Paste("some text"), - } - extras = [Dictation("text"), Dictation("text2"), ShortIntegerRef("n2", 1, 100)] - defaults = {"text": "", "text2": ""} - - -LAST_TIME = 0 - - -def print_time(): - global LAST_TIME - print(str(time.time() - LAST_TIME)[0]) - LAST_TIME = time.time() - - -def close_last_spoken(spoken): - first = spoken[0] - Text("").execute() - - -def close_last_rspec(rspec): - Text("").execute() - - -def _abc(data): - print(data) - - -FINISHER_TEXT = "finisher successful" - - -class StackTest(MappingRule): - '''test battery for the ContextStack''' - - mapping = { - "close last tag": - ContextSeeker([ - L( - S(["cancel"], None), - S(["html spoken"], close_last_spoken, use_spoken=True), - S(["span", "div"], close_last_rspec, use_rspec=True)) - ]), - "html": - R(Text(""), rspec="html spoken"), - "divider": - R(Text("
"), rspec="div"), - "span": - R(Text(""), rspec="span"), - "backward seeker []": - ContextSeeker([ - L( - S(["ashes"], Text("ashes1 [%(text)s] ")), - S(["bravery"], Text("bravery1 [%(text)s] "))), - L( - S(["ashes"], Text("ashes2 [%(text)s] ")), - S(["bravery"], Text("bravery2 [%(text)s] "))) - ]), - "forward seeker []": - ContextSeeker(forward=[ - L( - S(["ashes"], Text("ashes1 [%(text)s] ")), - S(["bravery"], Text("bravery1 [%(text)s] "))), - L( - S(["ashes"], Text("ashes2 [%(text)s] ")), - S(["bravery"], Text("bravery2 [%(text)s] "))) - ]), - "asynchronous test": - AsynchronousAction([ - L( - S(["ashes", "charcoal"], print_time, None), - S(["bravery"], Text, "bravery1")) - ], - time_in_seconds=0.2, - repetitions=20, - finisher=Text(FINISHER_TEXT), - blocking=False), - "ashes": - RegisteredAction(Text("ashes _ "), rspec="ashes"), - "bravery": - RegisteredAction(Text("bravery _ "), rspec="bravery"), - "charcoal []": - R(Text("charcoal _ %(text)s"), rspec="charcoal"), - "test confirm action": - ConfirmAction( - Key("a"), rdescript="Confirm Action Test", - instructions="some words here"), - "test box action": - BoxAction( - lambda data: _abc(data), - rdescript="Test Box Action", - box_type=settings.QTYPE_DEFAULT, - log_failure=True), - } - extras = [Dictation("text"), Dictation("text2"), ShortIntegerRef("n", 1, 5)] - defaults = {"text": "", "text2": ""} - - -#def load(): # ToDo: Migrate to Caster 1.0.0 -# global grammar -# grammar.add_rule(StackTest()) -# grammar.add_rule(DevelopmentHelp()) -# grammar.add_rule(Experimental()) -# grammar.load() - - -#if settings.SETTINGS["miscellaneous"]["dev_commands"]: -# load() diff --git a/castervoice/lib/dev/devgen.py b/castervoice/lib/dev/devgen.py deleted file mode 100644 index a47cc12ee..000000000 --- a/castervoice/lib/dev/devgen.py +++ /dev/null @@ -1,45 +0,0 @@ -from dragonfly import MappingRule, Grammar, Config, Section, Item, Dictation, Mimic -from castervoice.lib import settings, utilities -from castervoice.lib.actions import Text, Key - -_grammar = Grammar("dev gen") - - -class ConfigDev(Config): - def __init__(self, name): - Config.__init__(self, name) - self.cmd = Section("Language section") - self.cmd.map = Item( - { - "mimic ": Mimic(extra="text"), - }, - namespace={ - "Key": Key, - "Text": Text, - }) - self.cmd.extras = Item([Dictation("text")]) - self.cmd.defaults = Item({}) - - -def generate_rule(path): - configuration = ConfigDev("dev") - configuration.load(path) - return MappingRule( - exported=True, - mapping=configuration.cmd.map, - extras=configuration.cmd.extras, - defaults=configuration.cmd.defaults) - - -# Create and load this module's grammar. -def refresh(): - global _grammar - _grammar.unload() - while len(_grammar.rules) > 0: - _grammar.remove_rule(_grammar.rules[0]) - try: - rule = generate_rule(settings.SETTINGS["paths"]["CONFIGDEBUGTXT_PATH"]) - _grammar.add_rule(rule) - _grammar.load() - except Exception: - utilities.simple_log() diff --git a/castervoice/lib/dll/tirg-32.dll b/castervoice/lib/dll/tirg-32.dll deleted file mode 100644 index 9c85309a6..000000000 Binary files a/castervoice/lib/dll/tirg-32.dll and /dev/null differ diff --git a/castervoice/lib/dll/tirg-64.dll b/castervoice/lib/dll/tirg-64.dll deleted file mode 100644 index ebf74d749..000000000 Binary files a/castervoice/lib/dll/tirg-64.dll and /dev/null differ diff --git a/castervoice/lib/github_automation.ahk b/castervoice/lib/github_automation.ahk deleted file mode 100644 index 551ff4d63..000000000 --- a/castervoice/lib/github_automation.ahk +++ /dev/null @@ -1,28 +0,0 @@ -#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. -; #Warn ; Enable warnings to assist with detecting common errors. -SendMode Input ; Recommended for new scripts due to its superior speed and reliability. -SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. - -check = %1% -title = %2% - -SetTitleMatchMode, 2 -if (check == "exists") -{ - if WinExist(title) - { - WinActivate, %title% - FileAppend, %title% activated, * - } - else - { - FileAppend , %title% does not exist, * - } -} -else if (check = "create") -{ - WinWait, %title% - { - FileAppend , %title% ready, * - } -} diff --git a/castervoice/lib/github_automation.py b/castervoice/lib/github_automation.py deleted file mode 100644 index a217c9090..000000000 --- a/castervoice/lib/github_automation.py +++ /dev/null @@ -1,123 +0,0 @@ - -import os -import shutil -from subprocess import Popen, PIPE -import time - -from castervoice.lib.actions import Key, Text -from castervoice.lib.context import read_selected_without_altering_clipboard -from castervoice.lib.utilities import load_toml_file -from castervoice.lib import settings - - -def _copy_path(): - if not os.path.isfile(settings.SETTINGS["paths"]["GIT_REPO_LOCAL_REMOTE_PATH"]): - git_match_default = settings.SETTINGS["paths"]["GIT_REPO_LOCAL_REMOTE_DEFAULT_PATH"] - git_match_user = settings.SETTINGS["paths"]["GIT_REPO_LOCAL_REMOTE_PATH"] - shutil.copy(git_match_default, git_match_user) - - -def _rebuild_local_remote_items(config): - return { - key: (os.path.expandvars(value), header) - for header, section in config.items() for key, value in section.items() - } - - -def github_checkoutupdate_pull_request(new): - _copy_path() - - # Function to fetch a PR - try: - Key("c-l/20").execute() - url = read_selected_without_altering_clipboard() - if url[0] == 0: - split_string = url[1].split("/pull/") - repo_url = split_string[0] - pr_name = split_string[1].split("/")[0] - CONFIG = load_toml_file(settings.SETTINGS["paths"]["GIT_REPO_LOCAL_REMOTE_PATH"]) - if not CONFIG: - # logger.warn("Could not load bringme defaults") - raise Exception("Could not load " + settings.SETTINGS["paths"]["GIT_REPO_LOCAL_REMOTE_PATH"]) - - items = _rebuild_local_remote_items(CONFIG) - if repo_url in items: - local_directory = items[repo_url][0] - local_directory = local_directory.replace("\\", "\\\\") - directory_command = "cd " + local_directory - TERMINAL_PATH = settings.SETTINGS["paths"]["TERMINAL_PATH"] - AHK_PATH = settings.SETTINGS["paths"]["AHK_PATH"] - ahk_installed = os.path.isfile(AHK_PATH) - print("AHK_PATH = " + AHK_PATH) - if TERMINAL_PATH != "": - load_terminal = True # set default value - # ready fetch command string to be appended to - fetch_command = "" - # find the equivalent ahk script with the same name as this one - ahk_script = __file__.replace(".pyc", ".ahk").replace(".py", ".ahk") - pattern_match = "MINGW64" # the string we expect to find in the title of git bash when loaded - # if autohotkey is installed - if ahk_installed: - # open the script which checks that git bash window is open or not - p = Popen([AHK_PATH, ahk_script, "exists", pattern_match], stdout=PIPE) - # retrieve the output from the ahk script - stdout, stderr = p.communicate() - # terminates the ahk script if not already done so - p.terminate() - - # if an existing git bash window has been activated - if stdout == pattern_match + " activated": - # set the first portion of the fetch command - fetch_command += directory_command + " && " - load_terminal = False - print("Msg:" + ahk_script + " has activated window: " + pattern_match) - # if an existing git bash window is not already open - elif stdout == pattern_match + " does not exist": - print("Msg:" + ahk_script + " has found no window: " + pattern_match) - print("Load new instance of: " + pattern_match) - else: - print("Error:" + ahk_script + " neither returned 'activated' nor 'does not exist'") - print("Fallback: load new instance of :" + pattern_match) - if load_terminal: - # open up a new git bash terminal - terminal = Popen(TERMINAL_PATH, cwd=local_directory) - # if autohotkey is installed - if ahk_installed: - # open the script which checks that git bash windoow is ready or not for input - p = Popen([AHK_PATH, ahk_script, "create", pattern_match], stdout=PIPE) - # retrieve the output from the AHK script - stdout, stderr = p.communicate() - # terminates the ahk script if not already done so - p.terminate() - # if the git bash terminal is not ready - if stdout != pattern_match + " ready": - raise Exception("Error: git terminal took too long to load for script:" + ahk_script) - else: # otherwise await the default number of seconds for the terminal to load - time.sleep(settings.SETTINGS["gitbash"]["loading_time"]) - else: - # Remove any text that's there in the existing terminal - Key("end/10, c-u/10").execute() - # adds to the fetch command string that which will fetch from the particular repository in question - fetch_command += "git fetch " + repo_url + ".git pull/" + pr_name + "/head" - # if fetching from a new pull request - if new: - branch_name_base = repo_url.replace("https://github.com/", "") - checkout_command = "git checkout -b " + branch_name_base + "/pull/" + pr_name + " FETCH_HEAD" - # type in the full command into the git bash window - Text(fetch_command + " && " + checkout_command).execute() - else: # otherwise if it is an update to an existing pull request - branch_name_base = repo_url.replace("https://github.com/", "") - checkout_command = "git checkout " + branch_name_base + "/pull/" + pr_name - # type in the full command into the git bash window - Text(fetch_command + " && " + checkout_command).execute() - Key("enter").execute() # checkout is safe enough so will run this - merge_command = "git merge FETCH_HEAD" - # allow time for the fetch commands complete before typing in the next one - time.sleep(settings.SETTINGS["gitbash"]["fetching_time"]) - Text(merge_command).execute() - else: - raise Exception('TERMINAL_PATH in /.caster/data/settings.toml is not set') - else: - raise Exception("Repository URL: " + repo_url + " not found in " + settings.SETTINGS["paths"]["GIT_REPO_LOCAL_REMOTE_PATH"]) - except Exception as e: - print (e) diff --git a/castervoice/lib/merge/__init__.py b/castervoice/lib/merge/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/additions.py b/castervoice/lib/merge/additions.py deleted file mode 100644 index 4b44b742e..000000000 --- a/castervoice/lib/merge/additions.py +++ /dev/null @@ -1,19 +0,0 @@ -from dragonfly import ShortIntegerRef -from dragonfly.grammar.elements import Choice -from castervoice.lib import printer - - -class IntegerRefST(ShortIntegerRef): - """ - Compatibility shim for older grammars that use IntegerRefST. - IntegerRefST and Integer Remap has been removed use dragonfly ShortIntegerRef - """ - - def __init__(self, name, min, max, default=None): - printer.out("\nDetected 'IntegerRefST' import in rules/grammars.\nIntegerRefST and Integer Remap has been removed. \nUpdate your rules to `from dragonfly import ShortIntegerRef` in instead of IntegerRefST\n") - super(IntegerRefST, self).__init__(name, min, max, default) - - -class Boolean(Choice): - def __init__(self, spec): - Choice.__init__(self, spec, {spec: True}) diff --git a/castervoice/lib/merge/ccrmerging2/__init__.py b/castervoice/lib/merge/ccrmerging2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/ccrmerging2/activation_rule_generator.py b/castervoice/lib/merge/ccrmerging2/activation_rule_generator.py deleted file mode 100644 index 48000d50d..000000000 --- a/castervoice/lib/merge/ccrmerging2/activation_rule_generator.py +++ /dev/null @@ -1,9 +0,0 @@ -from castervoice.lib.ctrl.mgr.errors.base_class_error import DontUseBaseClassError - - -class ActivationRuleGenerator(object): - def construct_activation_rule(self): - """ - Returns a rule which has activation commands. - """ - raise DontUseBaseClassError(self) \ No newline at end of file diff --git a/castervoice/lib/merge/ccrmerging2/ccrmerger2.py b/castervoice/lib/merge/ccrmerging2/ccrmerger2.py deleted file mode 100644 index 9f4c07edf..000000000 --- a/castervoice/lib/merge/ccrmerging2/ccrmerger2.py +++ /dev/null @@ -1,224 +0,0 @@ -import traceback - -from dragonfly.grammar.elements import RuleRef, Alternative, Repetition -from dragonfly.grammar.rule_compound import CompoundRule -from dragonfly import FuncContext -from castervoice.lib.const import CCRType -from castervoice.lib.context import AppContext -from castervoice.lib.ctrl.mgr.rules_enabled_diff import RulesEnabledDiff -from castervoice.lib.merge.ccrmerging2.merge_result import MergeResult - - -class CCRMerger2(object): - _ORIGINAL = "original" - _SEQ = "caster_base_sequence" - _TERMINAL = "terminal" - - def __init__(self, transformers_runner, compatibility_checker, merging_strategy, max_repetitions, smr_configurer): - """ - 5-Step Merge Process - ==================== - 1. Run all transformers over all rules. - 2. Use a rule set sorter to sort rules. - 3. Use a compatibility checker to calculate incompatibility. - 4. Pass the transformed/sorted/checked rules to the merging strategy. - 5. Use the old trick from _multiedit.py to turn a MappingRule into a CCR rule. - ==================== - :param transformers_runner: runs Transformers on generated rules - :param compatibility_checker: BaseCompatibilityChecker impl - :param merging_strategy: BaseMergingStrategy impl - :param max_repetitions - :param smr_configurer - """ - self._transformers_runner = transformers_runner - self._compatibility_checker = compatibility_checker - self._merging_strategy = merging_strategy - # - self._sequence = 0 - self._max_repetitions = int(max_repetitions) - self._smr_configurer = smr_configurer - - def merge_rules(self, managed_rules, rule_sorter): - """ - :param managed_rules: list of ManagedRules - :param rule_sorter: BaseRuleSetSorter impl - :return: MergeResult - """ - pre_merge_rcns = [mr.get_rule_class_name() for mr in managed_rules] - rcns_to_details = CCRMerger2._rule_details_dict(managed_rules) - instantiated_rules = self._instantiate_and_configure_rules(managed_rules) - - # 1: run transformers over rules - transformed_rules = self._run_transformers(instantiated_rules, rcns_to_details) - # 2: sort rules into the order they'll be merged in - sorted_rules = rule_sorter.sort_rules(transformed_rules) - # 3: compute compatibility results for all rules vs all rules in O(n) for total specs - compat_results = self._compatibility_checker.compatibility_check(sorted_rules) - # 4: create one merged rule for each context, plus the no-contexts merged rule - app_crs, non_app_crs = self._separate_app_rules(compat_results, rcns_to_details) - merged_rules = self._create_merged_rules(app_crs, non_app_crs) - # 5: turn the merged rules into repeat rules - repeat_rules = [self._create_repeat_rule(merged_rule) for merged_rule in merged_rules] - contexts = CCRMerger2._create_contexts(app_crs, rcns_to_details) - - rules_and_contexts = list(zip(repeat_rules, contexts)) - enabled_ordered_rcns = [cr.rule_class_name() for cr in compat_results] - diff = CCRMerger2._calculate_post_merge_diff(pre_merge_rcns, enabled_ordered_rcns) - return MergeResult(rules_and_contexts, enabled_ordered_rcns, diff) - - @staticmethod - def _calculate_post_merge_diff(pre_merge_rcns, post_merge_rcns): - """ - Given list of pre-merge rcns and post-merge rcns, calculates which rules - were enabled and which were disabled by the merge. - - :param pre_merge_rcns: iterable - :param post_merge_rcns: iterable - :return: RulesEnabledDiff - """ - set_pre = frozenset(pre_merge_rcns) - set_post = frozenset(post_merge_rcns) - newly_enabled = list() # must remain ordered - newly_disabled = set() # order doesn't matter - - for rcn in pre_merge_rcns: - if rcn not in set_post: - newly_disabled.add(rcn) - for rcn in post_merge_rcns: - if rcn not in set_pre: - newly_enabled.append(rcn) - - return RulesEnabledDiff(newly_enabled, newly_disabled) - - def _instantiate_and_configure_rules(self, managed_rules): - instantiated_rules = [] - for mr in managed_rules: - mergerule = mr.get_rule_instance() - # smr configurer only configures selfmodrules, but checks all - self._smr_configurer.configure(mergerule) - instantiated_rules.append(mergerule) - return instantiated_rules - - def _run_transformers(self, instantiated_rules, rcns_to_details): - transformed_rules = [] - for rule in instantiated_rules: - has_exclusion = rcns_to_details[rule.get_rule_class_name()].transformer_exclusion - if not has_exclusion: - rule = self._transformers_runner.transform_rule(rule) - transformed_rules.append(rule) - return transformed_rules - - def _separate_app_rules(self, compat_results, rcns_to_details): - """ - Given M non-app rules and N app rules, we want to produce - N+1 merged rules, where one of them has no app rules and the rest - each have one app rule. - """ - app_crs = [] - non_app_crs = [] - for cr in compat_results: - details = rcns_to_details[cr.rule_class_name()] - if details.declared_ccrtype == CCRType.APP: - app_crs.append(cr) - else: - non_app_crs.append(cr) - return app_crs, non_app_crs - - def _create_merged_rules(self, app_crs, non_app_crs): - merged_rules = [] - merged_non_app_crs_rule = self._merging_strategy.merge_into_single(non_app_crs) - if merged_non_app_crs_rule is not None: - merged_rules.append(merged_non_app_crs_rule) - for app_cr in app_crs: - with_one_app = list(non_app_crs) - with_one_app.append(app_cr) - merged_rules.append(self._merging_strategy.merge_into_single(with_one_app)) - return merged_rules - - @staticmethod - def _create_contexts(app_crs, rcns_to_details): - """ - Returns a list of contexts, AppContexts based on 'executable', FuncContext, one for each - app rule, and if more than zero app rules, the negation context for the - global ccr rule. (Global rule should be active when none of the other - contexts are.) If there are zero app rules, [None] will be returned - so the result can be zipped. - - :param app_crs: list of CompatibilityResult for app rules - :param rcns_to_details: map of {rule class name: rule details} - :return: - """ - contexts = [] - context_evaluations = {} - - def wrap_context(context): - old_matches = context.matches - context_evaluations[context] = (False,False) - def matches(executable,title,handle): - result,valid = context_evaluations[context] - if valid: - context_evaluations[context] = (result,False) - else: - try : - result = old_matches(executable,title,handle) - except : - result = True - traceback.print_exc() - context_evaluations[context] = (result,True) - return result - context.matches = matches - return context - - for cr in app_crs: - details = rcns_to_details[cr.rule_class_name()] - context = AppContext(executable=details.executable, title=details.title) - if details.function_context is not None: - context &= FuncContext(function=details.function_context) - contexts.append(wrap_context(context)) - - negation_context = FuncContext(lambda **kw:[x for x in context_evaluations if x.matches(**kw)]==[]) - - - contexts.insert(0, negation_context) - return contexts - - @staticmethod - def _rule_details_dict(managed_rules): - """ - :param managed_rules: list of ManagedRule - :return: dict of {class name (str): RuleDetails} - """ - result = {} - for managed_rule in managed_rules: - result[managed_rule.get_rule_class_name()] = managed_rule.get_details() - return result - - def _create_repeat_rule(self, merge_rule): - merge_rule = merge_rule.prepare_for_merger() - alts = [RuleRef(rule=merge_rule)] # +[RuleRef(rule=sm) for sm in selfmod] - single_action = Alternative(alts) - sequence = Repetition(single_action, min=1, max=self._max_repetitions, name=CCRMerger2._SEQ) - original = Alternative(alts, name=CCRMerger2._ORIGINAL) - terminal = Alternative(alts, name=CCRMerger2._TERMINAL) - - class RepeatRule(CompoundRule): - spec = "[<" + CCRMerger2._ORIGINAL + "> original] " + \ - "[<" + CCRMerger2._SEQ + ">] " + \ - "[terminal <" + CCRMerger2._TERMINAL + ">]" - extras = [sequence, original, terminal] - - def _process_recognition(self, node, extras): - _original = extras[CCRMerger2._ORIGINAL] if CCRMerger2._ORIGINAL in extras else None - _sequence = extras[CCRMerger2._SEQ] if CCRMerger2._SEQ in extras else None - _terminal = extras[CCRMerger2._TERMINAL] if CCRMerger2._TERMINAL in extras else None - if _original is not None: _original.execute() - if _sequence is not None: - for action in _sequence: - action.execute() - if _terminal is not None: _terminal.execute() - - return RepeatRule(name=self._get_new_rule_name()) - - def _get_new_rule_name(self): - self._sequence += 1 - return "Repeater{}".format(str(self._sequence)) diff --git a/castervoice/lib/merge/ccrmerging2/compatibility/__init__.py b/castervoice/lib/merge/ccrmerging2/compatibility/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/ccrmerging2/compatibility/base_compat_checker.py b/castervoice/lib/merge/ccrmerging2/compatibility/base_compat_checker.py deleted file mode 100644 index d4efca001..000000000 --- a/castervoice/lib/merge/ccrmerging2/compatibility/base_compat_checker.py +++ /dev/null @@ -1,10 +0,0 @@ -from castervoice.lib.ctrl.mgr.errors.base_class_error import DontUseBaseClassError - - -class BaseCompatibilityChecker(object): - """ - Implementors of new compat checkers should override the "compatibility_check" method. - """ - - def compatibility_check(self, mergerules): - raise DontUseBaseClassError(self) diff --git a/castervoice/lib/merge/ccrmerging2/compatibility/compat_result.py b/castervoice/lib/merge/ccrmerging2/compatibility/compat_result.py deleted file mode 100644 index 2b6532c6c..000000000 --- a/castervoice/lib/merge/ccrmerging2/compatibility/compat_result.py +++ /dev/null @@ -1,20 +0,0 @@ -class CompatibilityResult(object): - def __init__(self, mergerule, incompatible_rule_class_names=[]): - """ - :param mergerule: MergeRule - :param incompatible_rule_class_names: list of strings - """ - self._mergerule = mergerule - self._incompatible_rule_class_names = incompatible_rule_class_names - - def rule(self): - return self._mergerule - - def rule_class_name(self): - return self._mergerule.get_rule_class_name() - - def is_compatible(self): - return len(self._incompatible_rule_class_names) > 0 - - def incompatible_rule_class_names(self): - return set(self._incompatible_rule_class_names) diff --git a/castervoice/lib/merge/ccrmerging2/compatibility/detail_compat_checker.py b/castervoice/lib/merge/ccrmerging2/compatibility/detail_compat_checker.py deleted file mode 100644 index c4e6b3416..000000000 --- a/castervoice/lib/merge/ccrmerging2/compatibility/detail_compat_checker.py +++ /dev/null @@ -1,81 +0,0 @@ -from castervoice.lib.merge.ccrmerging2.compatibility.base_compat_checker import BaseCompatibilityChecker -from castervoice.lib.merge.ccrmerging2.compatibility.compat_result import CompatibilityResult -from castervoice.lib.util.bidi_graph import BiDiGraph -from castervoice.lib.util.hashable_list import HashableList - - -class DetailCompatibilityChecker(BaseCompatibilityChecker): - def compatibility_check(self, mergerules): - """ - DetailCompatibilityChecker computes incompatibilities - but eliminates nothing. This may be useful for certain - kinds of advanced merge strategies. - - :param mergerules: collection of MergeRule - :return: collection of CompatibilityResult - """ - - ''' - "RCN" = rule class name - - 1. Invert the mapping. Rules are usually one to many with specs. - Here, we want to get a mapping of spec to RCNs, where the - attached RCNs are all the rules which include that spec. - This is O(n) for total specs processed. - ''' - specs_to_lists_of_rcns = {} - rcns_to_rules = {} - for rule in mergerules: - DetailCompatibilityChecker._invert_mapping( - rule, - rule.get_mapping().keys(), - specs_to_lists_of_rcns) - rcns_to_rules[rule.get_rule_class_name()] = rule - - ''' - 2. Now we take the dict of spec to RCNs and discard the specs. - Any list of RCNs larger than size 1 represents an incompatibility. - However, the RCN lists need further grouping. At this point, they - are grouped by spec. What we want is a graph, with each RCN - pointing to its incompatible RCNs. - - Still O(n) for the total number of specs. - ''' - previously_computed_groups = set() - graph = BiDiGraph() - # gomir = "group of mutually incompatible rules" - for gomir in specs_to_lists_of_rcns.values(): - if len(gomir) == 1: - continue - - if gomir.get_string() in previously_computed_groups: - continue - previously_computed_groups.add(gomir.get_string()) - - graph.add(*gomir.get_list()) - - ''' - 3. Convert the incompatibility graph to a list of compat results. - ''' - results = [] - for rcn in rcns_to_rules: - rule = rcns_to_rules[rcn] - incompats = graph.get_node(rcn) - results.append(CompatibilityResult(rule, incompats)) - return results - - @staticmethod - def _invert_mapping(rule, rule_specs, specs_to_rules): - """ - Given a rule and its specs, associates each spec with its rule in - 'specs_to_rules'. This (A) groups incompatible rules together for - further processing and (B) preserves which specs are responsible, - in case we want a hook in here or something like that. - - Format is a space delimited string with a leading space - """ - - for spec in rule_specs: - if spec not in specs_to_rules: - specs_to_rules[spec] = HashableList() - specs_to_rules[spec].add(rule.get_rule_class_name()) diff --git a/castervoice/lib/merge/ccrmerging2/compatibility/simple_compat_checker.py b/castervoice/lib/merge/ccrmerging2/compatibility/simple_compat_checker.py deleted file mode 100644 index 5a49cd9dd..000000000 --- a/castervoice/lib/merge/ccrmerging2/compatibility/simple_compat_checker.py +++ /dev/null @@ -1,33 +0,0 @@ -from castervoice.lib.merge.ccrmerging2.compatibility.base_compat_checker import BaseCompatibilityChecker -from castervoice.lib.merge.ccrmerging2.compatibility.compat_result import CompatibilityResult - - -class SimpleCompatibilityChecker(BaseCompatibilityChecker): - """ - Does a simple compatibility computation, - eliminates incompatible rules using the - provided order. - """ - - def compatibility_check(self, mergerules): - all_specs = set() - results = [] - - for rule in reversed(list(mergerules)): - rule_specs = frozenset(rule.get_mapping().keys()) - if SimpleCompatibilityChecker._intersection_exists(rule_specs, all_specs): - continue - all_specs.update(rule_specs) - results.append(CompatibilityResult(rule, frozenset())) - - return list(reversed(results)) - - @staticmethod - def _intersection_exists(set_a, set_b): - """ - Lazy/fast intersection. - """ - for a in set_a: - if a in set_b: - return True - return False diff --git a/castervoice/lib/merge/ccrmerging2/hooks/__init__.py b/castervoice/lib/merge/ccrmerging2/hooks/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/ccrmerging2/hooks/base_hook.py b/castervoice/lib/merge/ccrmerging2/hooks/base_hook.py deleted file mode 100644 index 2dfb014b8..000000000 --- a/castervoice/lib/merge/ccrmerging2/hooks/base_hook.py +++ /dev/null @@ -1,56 +0,0 @@ -from castervoice.lib import printer -from castervoice.lib.ctrl.mgr.errors.base_class_error import DontUseBaseClassError -from castervoice.lib.merge.ccrmerging2.pronounceable import Pronounceable - - -class BaseHook(Pronounceable): - """ - Authors of new hooks should override the "run_on_event" and "get_pronunciation" methods. - Optional override "run_on_enable", "run_on_disable" methods - """ - - hook_state = True - - def __init__(self, event_type): - self._type = event_type - - def run(self): - raise DontUseBaseClassError(self) - - def run_on_enable(self): - # Method to override. - pass - - def _run_on_enable(self): - # Manages run_on_enable hook state - try: - if not self.hook_state: - self.hook_state = True - self.run_on_enable() - else: - printer.out("{} is already enabled.".format(self.get_class_name())) - except Exception as err: - message = "{}: Error with `enable` hook function.\n {}" - printer.out(message.format(self.get_class_name(), err)) - - def run_on_disable(self): - # Method to override. - pass - - def _run_on_disable(self): - # Manages run_on_disable hook state - try: - if self.hook_state: - self.hook_state = False - self.run_on_disable() - else: - printer.out("{} is already disabled.".format(self.get_class_name())) - except Exception as err: - message = "{}: Error with `disable` hook function.\n {}" - printer.out(message.format(self.get_class_name(), err)) - - def match(self, event_type): - return self._type == event_type - - def get_class_name(self): - return self.__class__.__name__ diff --git a/castervoice/lib/merge/ccrmerging2/hooks/events/__init__.py b/castervoice/lib/merge/ccrmerging2/hooks/events/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/ccrmerging2/hooks/events/activation_event.py b/castervoice/lib/merge/ccrmerging2/hooks/events/activation_event.py deleted file mode 100644 index 105d89f01..000000000 --- a/castervoice/lib/merge/ccrmerging2/hooks/events/activation_event.py +++ /dev/null @@ -1,9 +0,0 @@ -from castervoice.lib.merge.ccrmerging2.hooks.events.base_event import BaseHookEvent -from castervoice.lib.merge.ccrmerging2.hooks.events.event_types import EventType - - -class RuleActivationEvent(BaseHookEvent): - def __init__(self, rule_class_name, active): - super(RuleActivationEvent, self).__init__(EventType.ACTIVATION) - self.rule_class_name = rule_class_name - self.active = active diff --git a/castervoice/lib/merge/ccrmerging2/hooks/events/base_event.py b/castervoice/lib/merge/ccrmerging2/hooks/events/base_event.py deleted file mode 100644 index d42cfa5df..000000000 --- a/castervoice/lib/merge/ccrmerging2/hooks/events/base_event.py +++ /dev/null @@ -1,10 +0,0 @@ -class BaseHookEvent(object): - """ - Hook events provide information to examples. - """ - - def __init__(self, event_type): - self._type = event_type - - def get_type(self): - return self._type diff --git a/castervoice/lib/merge/ccrmerging2/hooks/events/event_types.py b/castervoice/lib/merge/ccrmerging2/hooks/events/event_types.py deleted file mode 100644 index b00acb8ba..000000000 --- a/castervoice/lib/merge/ccrmerging2/hooks/events/event_types.py +++ /dev/null @@ -1,5 +0,0 @@ -class EventType(object): - ACTIVATION = "activation" - NODE_CHANGE = "node change" - ON_ERROR = "on error" - RULES_LOADED = "rules loaded" diff --git a/castervoice/lib/merge/ccrmerging2/hooks/events/node_change_event.py b/castervoice/lib/merge/ccrmerging2/hooks/events/node_change_event.py deleted file mode 100644 index 06d00ff1e..000000000 --- a/castervoice/lib/merge/ccrmerging2/hooks/events/node_change_event.py +++ /dev/null @@ -1,10 +0,0 @@ -from castervoice.lib.merge.ccrmerging2.hooks.events.base_event import BaseHookEvent -from castervoice.lib.merge.ccrmerging2.hooks.events.event_types import EventType - - -class NodeChangeEvent(BaseHookEvent): - def __init__(self, tree_name, active_path, new_specs): - super(NodeChangeEvent, self).__init__(EventType.NODE_CHANGE) - self.tree_name = tree_name - self.active_path = active_path - self.new_specs = new_specs diff --git a/castervoice/lib/merge/ccrmerging2/hooks/events/on_error_event.py b/castervoice/lib/merge/ccrmerging2/hooks/events/on_error_event.py deleted file mode 100644 index a412b9a2d..000000000 --- a/castervoice/lib/merge/ccrmerging2/hooks/events/on_error_event.py +++ /dev/null @@ -1,8 +0,0 @@ -from castervoice.lib.merge.ccrmerging2.hooks.events.base_event import BaseHookEvent -from castervoice.lib.merge.ccrmerging2.hooks.events.event_types import EventType - - -class OnErrorEvent(BaseHookEvent): - def __init__(self): - super(OnErrorEvent, self).__init__(EventType.ON_ERROR) - \ No newline at end of file diff --git a/castervoice/lib/merge/ccrmerging2/hooks/events/rules_loaded_event.py b/castervoice/lib/merge/ccrmerging2/hooks/events/rules_loaded_event.py deleted file mode 100644 index 3379accde..000000000 --- a/castervoice/lib/merge/ccrmerging2/hooks/events/rules_loaded_event.py +++ /dev/null @@ -1,8 +0,0 @@ -from castervoice.lib.merge.ccrmerging2.hooks.events.base_event import BaseHookEvent -from castervoice.lib.merge.ccrmerging2.hooks.events.event_types import EventType - - -class RulesLoadedEvent(BaseHookEvent): - def __init__(self, rules=None): - super(RulesLoadedEvent, self).__init__(EventType.RULES_LOADED) - self.rules = rules diff --git a/castervoice/lib/merge/ccrmerging2/hooks/examples/__init__.py b/castervoice/lib/merge/ccrmerging2/hooks/examples/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/ccrmerging2/hooks/examples/printer_hook.py b/castervoice/lib/merge/ccrmerging2/hooks/examples/printer_hook.py deleted file mode 100644 index 2dd841843..000000000 --- a/castervoice/lib/merge/ccrmerging2/hooks/examples/printer_hook.py +++ /dev/null @@ -1,20 +0,0 @@ -from castervoice.lib import printer -from castervoice.lib.merge.ccrmerging2.hooks.base_hook import BaseHook -from castervoice.lib.merge.ccrmerging2.hooks.events.event_types import EventType - - -class PrinterHook(BaseHook): - - def __init__(self): - super(PrinterHook, self).__init__(EventType.ACTIVATION) - - def get_pronunciation(self): - return "printer" - - def run(self, event): - state = "active" if event.active else "inactive" - printer.out("The rule {} was set to {}.".format(event.rule_class_name, state)) - - -def get_hook(): - return PrinterHook diff --git a/castervoice/lib/merge/ccrmerging2/hooks/hooks_config.py b/castervoice/lib/merge/ccrmerging2/hooks/hooks_config.py deleted file mode 100644 index bcc5b75f2..000000000 --- a/castervoice/lib/merge/ccrmerging2/hooks/hooks_config.py +++ /dev/null @@ -1,18 +0,0 @@ -from castervoice.lib import settings -from castervoice.lib.config.config_toml import TomlConfig - - -class HooksConfig(TomlConfig): - - def __init__(self): - super(HooksConfig, self).__init__(settings.SETTINGS["paths"]["HOOKS_CONFIG_PATH"]) - self.load() - - def set_hook_active(self, hcn, active): - self._config[hcn] = active - - def is_hook_active(self, hcn): - return self._config[hcn] - - def __contains__(self, hcn): - return hcn in self._config diff --git a/castervoice/lib/merge/ccrmerging2/hooks/hooks_runner.py b/castervoice/lib/merge/ccrmerging2/hooks/hooks_runner.py deleted file mode 100644 index 663a6412b..000000000 --- a/castervoice/lib/merge/ccrmerging2/hooks/hooks_runner.py +++ /dev/null @@ -1,65 +0,0 @@ -from dragonfly import Function, MappingRule -import traceback - -from castervoice.lib import printer -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.ccrmerging2.activation_rule_generator import ActivationRuleGenerator -from castervoice.lib import settings -from castervoice.lib.merge.state.short import R - - -class HooksRunner(ActivationRuleGenerator): - def __init__(self, config): - self._hooks = [] - self._hooks_config = config - - def add_hook(self, hook_class): - hook = None - - # test instantiation - try: - hook = hook_class() - self._hooks.append(hook) - except: - err = "Error instantiating {}.".format(hook_class.__name__) - traceback.print_exc() - printer.out(err) - return - - # register new hook and enables default hooks - default_hooks = settings.SETTINGS["hooks"]["default_hooks"] - if hook.get_class_name() not in self._hooks_config: - if hook.get_class_name() in default_hooks: - self._hooks_config.set_hook_active(hook.get_class_name(), True) - printer.out("Default hook added and enabled: {}".format(hook.get_class_name())) - else: - self._hooks_config.set_hook_active(hook.get_class_name(), False) - printer.out("New hook added: {}".format(hook.get_class_name())) - self._hooks_config.save() - - def construct_activation_rule(self): - m = {} - for hook in self._hooks: - enable_action = R(Function(lambda: self._hooks_config.set_hook_active(hook.get_class_name(), True)) + Function(hook._run_on_enable)) - disable_action = R(Function(lambda: self._hooks_config.set_hook_active(hook.get_class_name(), False)) + Function(hook._run_on_disable)) - m["enable {} hook".format(hook.get_pronunciation())] = enable_action - m["disable {} hook".format(hook.get_pronunciation())] = disable_action - - class HooksActivationRule(MappingRule): - mapping = m - details = RuleDetails(name="hooks runner hooks activator rule", - watch_exclusion=True) - - return HooksActivationRule, details - - def execute(self, event): - for hook in self._hooks: - if not self._hooks_config.is_hook_active(hook.get_class_name()): - continue - if hook.match(event.get_type()): - try: - hook.run(event) - except: - err = "Error while running hook {} with {} event.\n" - printer.out(err.format(hook, event.get_type())) - traceback.print_exc() \ No newline at end of file diff --git a/castervoice/lib/merge/ccrmerging2/hooks/standard_hooks/__init__.py b/castervoice/lib/merge/ccrmerging2/hooks/standard_hooks/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/ccrmerging2/hooks/standard_hooks/format_hook.py b/castervoice/lib/merge/ccrmerging2/hooks/standard_hooks/format_hook.py deleted file mode 100644 index 776c2e038..000000000 --- a/castervoice/lib/merge/ccrmerging2/hooks/standard_hooks/format_hook.py +++ /dev/null @@ -1,40 +0,0 @@ -from castervoice.lib import settings, textformat -from castervoice.lib.merge.ccrmerging2.hooks.base_hook import BaseHook -from castervoice.lib.merge.ccrmerging2.hooks.events.event_types import EventType - - -def _apply_format(rule_pronunciation): - if rule_pronunciation in settings.SETTINGS["formats"]: - if 'text_format' in settings.SETTINGS["formats"][rule_pronunciation]: - cap, spacing = settings.SETTINGS["formats"][rule_pronunciation]['text_format'] - textformat.format.set_text_format(cap, spacing) - else: - textformat.format.clear_text_format() - if 'secondary_format' in settings.SETTINGS["formats"][rule_pronunciation]: - cap, spacing = settings.SETTINGS["formats"][rule_pronunciation]['secondary_format'] - textformat.secondary_format.set_text_format(cap, spacing) - else: - textformat.secondary_format.clear_text_format() - else: - textformat.format.clear_text_format() - textformat.secondary_format.clear_text_format() - - -class FormattingHook(BaseHook): - - def __init__(self): - super(FormattingHook, self).__init__(EventType.ACTIVATION) - - def get_pronunciation(self): - return "formatting" - - def run(self, event): - if event.active: - _apply_format(event.rule_class_name) - else: - textformat.format.clear_text_format() - textformat.secondary_format.clear_text_format() - - -def get_hook(): - return FormattingHook diff --git a/castervoice/lib/merge/ccrmerging2/hooks/standard_hooks/rules_loaded_hook.py b/castervoice/lib/merge/ccrmerging2/hooks/standard_hooks/rules_loaded_hook.py deleted file mode 100644 index 35096f12d..000000000 --- a/castervoice/lib/merge/ccrmerging2/hooks/standard_hooks/rules_loaded_hook.py +++ /dev/null @@ -1,18 +0,0 @@ -import castervoice.lib.rules_collection -from castervoice.lib.merge.ccrmerging2.hooks.base_hook import BaseHook -from castervoice.lib.merge.ccrmerging2.hooks.events.event_types import EventType - - -class RulesLoadedHook(BaseHook): - def __init__(self): - super(RulesLoadedHook, self).__init__(EventType.RULES_LOADED) - - def get_pronunciation(self): - return "rules loaded" - - def run(self, event_data): - castervoice.lib.rules_collection.get_instance().update(event_data.rules) - - -def get_hook(): - return RulesLoadedHook diff --git a/castervoice/lib/merge/ccrmerging2/hooks/standard_hooks/show_window_on_error_hook.py b/castervoice/lib/merge/ccrmerging2/hooks/standard_hooks/show_window_on_error_hook.py deleted file mode 100644 index 759a4e21c..000000000 --- a/castervoice/lib/merge/ccrmerging2/hooks/standard_hooks/show_window_on_error_hook.py +++ /dev/null @@ -1,37 +0,0 @@ -from castervoice.lib import settings, textformat -from castervoice.lib.merge.ccrmerging2.hooks.base_hook import BaseHook -from castervoice.lib.merge.ccrmerging2.hooks.events.event_types import EventType -from castervoice.lib import printer - -from dragonfly import get_current_engine -from dragonfly.windows.window import Window - -def show_window(): - title = None - engine = get_current_engine().name - if engine == 'natlink': - from natlinkcore import natlinkstatus # pylint: disable=import-error - status = natlinkstatus.NatlinkStatus() - if status.NatlinkIsEnabled() == 1: - title= "Messages from Natlink" - else: - title = "Caster: Status Window" - if engine != 'natlink': - title = "Caster: Status Window" - windows = Window.get_matching_windows(title=title) - if windows: - windows[0].set_foreground() - - -class ShowStatusWindowOnErrorHook(BaseHook): - def __init__(self): - super(ShowStatusWindowOnErrorHook, self).__init__(EventType.ON_ERROR) - - def get_pronunciation(self): - return "show status error" - - def run(self, event_data): - show_window() - -def get_hook(): - return ShowStatusWindowOnErrorHook diff --git a/castervoice/lib/merge/ccrmerging2/merge_result.py b/castervoice/lib/merge/ccrmerging2/merge_result.py deleted file mode 100644 index b8edecd1b..000000000 --- a/castervoice/lib/merge/ccrmerging2/merge_result.py +++ /dev/null @@ -1,11 +0,0 @@ -class MergeResult(object): - - def __init__(self, ccr_rules_and_contexts, all_rule_class_names, rules_enabled_diff): - """ - :param ccr_rules_and_contexts: 1-n RepeatRules and 0-n AppContexts - :param all_rule_class_names: list of str - :param rules_enabled_diff: RulesEnabledDiff - """ - self.ccr_rules_and_contexts = ccr_rules_and_contexts - self.all_rule_class_names = all_rule_class_names - self.rules_enabled_diff = rules_enabled_diff diff --git a/castervoice/lib/merge/ccrmerging2/merging/__init__.py b/castervoice/lib/merge/ccrmerging2/merging/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/ccrmerging2/merging/base_merging_strategy.py b/castervoice/lib/merge/ccrmerging2/merging/base_merging_strategy.py deleted file mode 100644 index 8bd0f606f..000000000 --- a/castervoice/lib/merge/ccrmerging2/merging/base_merging_strategy.py +++ /dev/null @@ -1,11 +0,0 @@ -from castervoice.lib.ctrl.mgr.errors.base_class_error import DontUseBaseClassError - - -class BaseMergingStrategy(object): - """ - Merging strategies define how the transformed, sorter, compat-checked - rules become one or more merged CCR rules. - """ - - def merge_into_single(self, sorted_checked_rules): - raise DontUseBaseClassError() # pylint: disable=no-value-for-parameter diff --git a/castervoice/lib/merge/ccrmerging2/merging/classic_merging_strategy.py b/castervoice/lib/merge/ccrmerging2/merging/classic_merging_strategy.py deleted file mode 100644 index da536526b..000000000 --- a/castervoice/lib/merge/ccrmerging2/merging/classic_merging_strategy.py +++ /dev/null @@ -1,44 +0,0 @@ -from castervoice.lib.merge.ccrmerging2.merging.base_merging_strategy import BaseMergingStrategy - - -class ClassicMergingStrategy(BaseMergingStrategy): - """ - This strategy KOs any incompatible rules. - """ - - def merge_into_single(self, sorted_checked_rules): - """ - Merge any rules which aren't KO'd by their peers. - Done in O(n) for the total number of specs. - - :param sorted_checked_rules: list of CompatibilityResult - :return: MergeRule - """ - - length = len(sorted_checked_rules) - rule_range = range(0, length) - - # set up O(1) access to indices for the second loop in O(n) for # of rules - indices_map = {} - for index in rule_range: - compat_result = sorted_checked_rules[index] - indices_map[compat_result.rule_class_name()] = index - - # rules with higher indices (activated "later") get priority - merged_rule = None - for index in rule_range: - compat_result = sorted_checked_rules[index] - ko = False - rule_index = indices_map[compat_result.rule_class_name()] - # this looks like O(n^2), and it is for the rule graph, but it's O(n) for specs: - for incompat_rcn in compat_result.incompatible_rule_class_names(): - incompat_index = indices_map[incompat_rcn] - if incompat_index > rule_index: - ko = True - break - if not ko: - if merged_rule is None: - merged_rule = compat_result.rule() - else: - merged_rule = merged_rule.merge(compat_result.rule()) - return merged_rule diff --git a/castervoice/lib/merge/ccrmerging2/pronounceable.py b/castervoice/lib/merge/ccrmerging2/pronounceable.py deleted file mode 100644 index 2cb3c8721..000000000 --- a/castervoice/lib/merge/ccrmerging2/pronounceable.py +++ /dev/null @@ -1,11 +0,0 @@ -from castervoice.lib.ctrl.mgr.errors.base_class_error import DontUseBaseClassError - - -class Pronounceable(object): - - def get_pronunciation(self): - """ - Child classes should implement this, - returning string pronunciation. - """ - raise DontUseBaseClassError(self) diff --git a/castervoice/lib/merge/ccrmerging2/sorting/__init__.py b/castervoice/lib/merge/ccrmerging2/sorting/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/ccrmerging2/sorting/alpha_ruleset_sorter.py b/castervoice/lib/merge/ccrmerging2/sorting/alpha_ruleset_sorter.py deleted file mode 100644 index da97cbc11..000000000 --- a/castervoice/lib/merge/ccrmerging2/sorting/alpha_ruleset_sorter.py +++ /dev/null @@ -1,12 +0,0 @@ -from castervoice.lib.merge.ccrmerging2.sorting.base_ruleset_sorter import BaseRuleSetSorter - - -class AlphaRuleSetSorter(BaseRuleSetSorter): - def sort_rules(self, rules): - return sorted(rules, key=AlphaRuleSetSorter._pronunciation_or_name) - - @staticmethod - def _pronunciation_or_name(rule): - if hasattr(rule, "get_pronunciation"): - return rule.get_pronunciation().lower() - return rule.name.lower() diff --git a/castervoice/lib/merge/ccrmerging2/sorting/base_ruleset_sorter.py b/castervoice/lib/merge/ccrmerging2/sorting/base_ruleset_sorter.py deleted file mode 100644 index 9f8a91841..000000000 --- a/castervoice/lib/merge/ccrmerging2/sorting/base_ruleset_sorter.py +++ /dev/null @@ -1,12 +0,0 @@ -class BaseRuleSetSorter(object): - """ - When multiple active rules get edited at the same time and - reloaded, there is no such thing anymore as the - "currently active rules" and the "new rule". It's a set of - active rules which need to be merged together in some kind - of deterministic order. This behavior should be customizable. - Hence ruleset sorters. - """ - - def sort_rules(self, rules): - return list(rules) diff --git a/castervoice/lib/merge/ccrmerging2/sorting/config_ruleset_sorter.py b/castervoice/lib/merge/ccrmerging2/sorting/config_ruleset_sorter.py deleted file mode 100644 index 145afdddd..000000000 --- a/castervoice/lib/merge/ccrmerging2/sorting/config_ruleset_sorter.py +++ /dev/null @@ -1,27 +0,0 @@ -from castervoice.lib.merge.ccrmerging2.sorting.base_ruleset_sorter import BaseRuleSetSorter - - -class _IndexedRule(object): - def __init__(self, rule, index): - self.rule = rule - self.index = index - - -class ConfigBasedRuleSetSorter(BaseRuleSetSorter): - """ - Uses a function borrowed from somewhere else to - determine rule merging order. - """ - - def __init__(self, ordered_rcns): - self._ordered_rcns = list(ordered_rcns) - - def sort_rules(self, rules): - indexed_rules = [_IndexedRule(r, self._ordered_rcns.index(ConfigBasedRuleSetSorter._get_class_name(r))) - for r in rules] - sorted_indexed_rules = sorted(indexed_rules, key=lambda ir: ir.index) - return [i.rule for i in sorted_indexed_rules] - - @staticmethod - def _get_class_name(rule): - return rule.__class__.__name__ diff --git a/castervoice/lib/merge/ccrmerging2/transformers/__init__.py b/castervoice/lib/merge/ccrmerging2/transformers/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/ccrmerging2/transformers/base_transformer.py b/castervoice/lib/merge/ccrmerging2/transformers/base_transformer.py deleted file mode 100644 index 7b3f56788..000000000 --- a/castervoice/lib/merge/ccrmerging2/transformers/base_transformer.py +++ /dev/null @@ -1,34 +0,0 @@ -''' -Transformers are the successor to legacy Caster's -"filter functions". The main differences between -them are that: -1. transformers operate on single rules instead of rule pairs -2. transformers assume that the rules passed to them are non-null -3. transformers enforce immutability -4. transformers have no concept of "time" or "order" -''' -from castervoice.lib.ctrl.mgr.errors.base_class_error import DontUseBaseClassError -from castervoice.lib.merge.ccrmerging2.pronounceable import Pronounceable - - -class BaseRuleTransformer(Pronounceable): - """ - Authors of new transformers should override the following methods: - - _transform - _is_applicable methods - get_pronunciation - - """ - - def get_transformed_rule(self, rule): - return rule if not self._is_applicable(rule) else self._transform(rule) - - def _transform(self, rule): - raise DontUseBaseClassError(self) - - def _is_applicable(self, rule): - raise DontUseBaseClassError(self) - - def get_class_name(self): - return self.__class__.__name__ diff --git a/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/__init__.py b/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/text_replacer.py b/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/text_replacer.py deleted file mode 100644 index 7dd2b60c1..000000000 --- a/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/text_replacer.py +++ /dev/null @@ -1,163 +0,0 @@ -from dragonfly.grammar.elements import Choice - -from castervoice.lib import printer -from castervoice.lib.merge.ccrmerging2.transformers.base_transformer import BaseRuleTransformer -from castervoice.lib.merge.ccrmerging2.transformers.text_replacer.tr_extra_data import TextReplacementExtraData -from castervoice.lib.merge.ccrmerging2.transformers.text_replacer.tr_parser import TRParser - - -def _analyze_extras(spec): - """ - Takes a spec and returns a list of extras and whether they're required or not. - """ - extras_data = [] - - angles_mode = False - brackets_mode = False - current_extra_name = "" - for character in spec: - if character == '[': - brackets_mode = True - continue - if character == ']': - brackets_mode = False - continue - if character == '<': - angles_mode = True - continue - if character == '>': - angles_mode = False - extras_data.append(TextReplacementExtraData(current_extra_name, not brackets_mode)) - current_extra_name = "" # reset for next - continue - if angles_mode: - current_extra_name += character - - return extras_data - - -def _detect_illegal_spec_alteration(extra_analyses, new_spec): - for extra_data in extra_analyses: - if extra_data.required and "<{}>".format(extra_data.name) not in new_spec: - return extra_data - return None - - -def _spec_override_from_config(rule, definitions): - '''redundant safety check''' - if len(definitions) == 0: - return rule - - '''SPECS''' - mapping = rule._mapping.copy() - specs_changed = False - for spec in list(mapping.keys()): - action = mapping[spec] - - extra_analyses = _analyze_extras(spec) - - new_spec = spec - for token_to_replace in definitions.specs.keys(): - if token_to_replace in new_spec: - replacement = definitions.specs[token_to_replace] - new_spec = new_spec.replace(token_to_replace, replacement) - - if spec == new_spec: - continue - - ''' - We want to protect the user from: - - removing required extras from specs - - accidentally renaming required extras - But we still want the user to be able to: - - move required extras - - remove optional extras - ''' - violation = _detect_illegal_spec_alteration(extra_analyses, new_spec) - if violation is not None: - printer.out("Illegal spec modification: cannot alter required extras. " + - "Cannot modify <{}> in \"{}\".".format(violation.name, spec)) - continue - - del mapping[spec] - mapping[new_spec] = action - specs_changed = True - - '''EXTRAS''' - extras_list = list(rule._extras.values()) - resulting_extras_list = list(extras_list) - extras_changed = False - for extra in extras_list: - # only choices; no need to bother with dictation or integers - if isinstance(extra, Choice): - choices_dict_copy = extra._choices.copy() # operate on this copy of the choices dict - choices_dict_copy_keys = set(choices_dict_copy.keys()) - replaced_a_choice_key = False - for choices_key in choices_dict_copy_keys: # ex: "dunce make" = key, something else = value - for replaceable_text in definitions.extras.keys(): # ex: "dunce" is key, "down" is the value - if replaceable_text in choices_key: # ex: "dunce" is in "dunce make" - replaced_a_choice_key = True - value = choices_dict_copy[choices_key] - del choices_dict_copy[choices_key] - replacement = definitions.extras[replaceable_text] - choices_key = choices_key.replace(replaceable_text, replacement) - choices_dict_copy[choices_key] = value - if replaced_a_choice_key: - extras_changed = True - new_choice = Choice(extra.name, choices_dict_copy) - resulting_extras_list.remove(extra) - resulting_extras_list.append(new_choice) - - '''DEFAULTS''' - defaults = rule._defaults.copy() - defaults_changed = False - if len(defaults) > 0: - for default_key in list(defaults.keys()): # - value = defaults[default_key] - if isinstance(value, str): - '''only replace strings; also, - only replace values, not keys: - default_key should not be changed - it will never be spoken''' - nvalue = value # new value - replaced_a_choice_key = False - for old in definitions.defaults.keys(): # 'old' is the target word(s) in the old 'value' - new = definitions.defaults[old] - if old in nvalue: - nvalue = nvalue.replace(old, new) - replaced_a_choice_key = True - if replaced_a_choice_key: - defaults[default_key] = nvalue - defaults_changed = True - - if specs_changed or extras_changed or defaults_changed: - # rule_class = rule.__class__ - rule.__init__(name=rule.name, - mapping=mapping, - extras=resulting_extras_list, - defaults=defaults) - return rule - - -class TextReplacerTransformer(BaseRuleTransformer): - - def __init__(self, parser=TRParser): - try: - parser_instance = parser() - self._definitions = parser_instance.create_definitions() - if len(self._definitions) > 0: - printer.out("Text replacing transformer from file 'words.txt' activated ...") - except Exception: - printer.out("Unable to parse words.txt") - - def get_pronunciation(self): - return "text replacer" - - def _transform(self, rule): - return _spec_override_from_config(rule, self._definitions) - - def _is_applicable(self, rule): - return True - - -def get_transformer(): - return TextReplacerTransformer diff --git a/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/tr_definitions.py b/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/tr_definitions.py deleted file mode 100644 index dbb89e644..000000000 --- a/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/tr_definitions.py +++ /dev/null @@ -1,8 +0,0 @@ -class TRDefinitions(object): - def __init__(self, specs, extras, defaults): - self.specs = specs - self.extras = extras - self.defaults = defaults - - def __len__(self): - return len(self.specs) + len(self.extras) + len(self.defaults) diff --git a/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/tr_extra_data.py b/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/tr_extra_data.py deleted file mode 100644 index 04b0a8c73..000000000 --- a/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/tr_extra_data.py +++ /dev/null @@ -1,4 +0,0 @@ -class TextReplacementExtraData(object): - def __init__(self, name, required): - self.name = name # the name of the extra: what's inside - self.required = required # indicates whether this is a required extra diff --git a/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/tr_parse_mode.py b/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/tr_parse_mode.py deleted file mode 100644 index b6d9b59c3..000000000 --- a/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/tr_parse_mode.py +++ /dev/null @@ -1,15 +0,0 @@ -class TRParseMode(object): - """ - type | replacement location - ------------------------------------------------------ - ANY | specs, extras, or defaults - SPEC | specs only - EXTRA | extras only - DEFAULT | defaults only - NOT_SPECS | extras and defaults but not specs - """ - ANY = "<<>>" - SPEC = "<<>>" - EXTRA = "<<>>" - DEFAULT = "<<>>" - NOT_SPECS = "<<>>" diff --git a/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/tr_parser.py b/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/tr_parser.py deleted file mode 100644 index efeaab9cf..000000000 --- a/castervoice/lib/merge/ccrmerging2/transformers/text_replacer/tr_parser.py +++ /dev/null @@ -1,83 +0,0 @@ -import io -import os - -from castervoice.lib import settings -from castervoice.lib.merge.ccrmerging2.transformers.text_replacer.tr_definitions import TRDefinitions -from castervoice.lib.merge.ccrmerging2.transformers.text_replacer.tr_parse_mode import TRParseMode - - -class TRParser(object): - """ - Reads text replacement definitions from words.txt. - """ - - def create_definitions(self): - lines = self._get_lines() - return self._parse_lines(lines) - - def _get_lines(self): - words_txt_path = settings.settings(["paths", "GDEF_FILE"]) - words_txt_lines = [] - if os.path.isfile(words_txt_path): - with io.open(words_txt_path, "rt", encoding="utf-8") as f: - words_txt_lines = f.readlines() - return words_txt_lines - - def _parse_lines(self, lines): - """ - :param lines: list of str; lines from words.txt - - these lines indicate either mode changes or transformations - - this method parses the lines and returns a data structure which - informs the transformer of how to behave - :return: TRDefinitions - """ - all_modes = frozenset([TRParseMode.ANY, - TRParseMode.SPEC, - TRParseMode.EXTRA, - TRParseMode.DEFAULT, - TRParseMode.NOT_SPECS]) - specs = {} - extras = {} - defaults = {} - mode = TRParseMode.ANY - - for line in lines: - line = line.strip() - # ignore comments and empty lines - if line.startswith("#") or line.isspace(): - continue - # handle mode changes - if line in all_modes: - mode = line - continue - # ignore invalid lines (not a mode, not a transformation) - if "->" not in line: - continue - - # extract source and target - source_and_target = line.split("->") - source = source_and_target[0].strip() - # allow for inline comments on the right side of the line - target = "#".join(source_and_target[1].split("#")[:1]) - target = target.strip() - - """ - See TRParseMode notes for what the different modes mean. - These three dicts represent locations to replace text in - a rule. - """ - if mode == TRParseMode.ANY: - specs[source] = target - extras[source] = target - defaults[source] = target - elif mode == TRParseMode.SPEC: - specs[source] = target - elif mode == TRParseMode.EXTRA: - extras[source] = target - elif mode == TRParseMode.DEFAULT: - defaults[source] = target - elif mode == TRParseMode.NOT_SPECS: - extras[source] = target - defaults[source] = target - - return TRDefinitions(specs, extras, defaults) diff --git a/castervoice/lib/merge/ccrmerging2/transformers/transformers_config.py b/castervoice/lib/merge/ccrmerging2/transformers/transformers_config.py deleted file mode 100644 index 9b8181748..000000000 --- a/castervoice/lib/merge/ccrmerging2/transformers/transformers_config.py +++ /dev/null @@ -1,18 +0,0 @@ -from castervoice.lib import settings -from castervoice.lib.config.config_toml import TomlConfig - - -class TransformersConfig(TomlConfig): - - def __init__(self): - super(TransformersConfig, self).__init__(settings.SETTINGS["paths"]["TRANSFORMERS_CONFIG_PATH"]) - self.load() - - def set_transformer_active(self, hcn, active): - self._config[hcn] = active - - def is_transformer_active(self, hcn): - return self._config[hcn] - - def __contains__(self, hcn): - return hcn in self._config diff --git a/castervoice/lib/merge/ccrmerging2/transformers/transformers_runner.py b/castervoice/lib/merge/ccrmerging2/transformers/transformers_runner.py deleted file mode 100644 index 63b2bf6db..000000000 --- a/castervoice/lib/merge/ccrmerging2/transformers/transformers_runner.py +++ /dev/null @@ -1,90 +0,0 @@ -import traceback - -from dragonfly import Function, MappingRule - -from castervoice.lib import printer -from castervoice.lib.ctrl.mgr.errors.invalid_transformation_error import InvalidTransformationError, ITMessage -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.ccrmerging2.activation_rule_generator import ActivationRuleGenerator -from castervoice.lib.merge.mergerule import MergeRule - - -class TransformersRunner(ActivationRuleGenerator): - - def __init__(self, config): - self._transformers_config = config - self._transformers = [] - - def add_transformer(self, transformer_class): - transformer = None - - # test instantiation - try: - transformer = transformer_class() - except: - err = "Error instantiating {}.".format(transformer_class.__name__) - printer.out(err) - return - - # register it - if transformer.get_class_name() not in self._transformers_config: - self._transformers_config.set_transformer_active(transformer.get_class_name(), False) - self._transformers_config.save() - printer.out("New transformer added: {}".format(transformer.get_class_name())) - - if self._transformers_config.is_transformer_active(transformer.get_class_name()): - self._transformers.append(transformer) - - def construct_activation_rule(self): - m = {} - for t in self._transformers: - enable_action = \ - Function(lambda: self._transformers_config.set_transformer_active(t.get_class_name(), True)) - disable_action = \ - Function(lambda: self._transformers_config.set_transformer_active(t.get_class_name(), False)) - m["enable {} transformer".format(t.get_pronunciation())] = enable_action - m["disable {} transformer".format(t.get_pronunciation())] = disable_action - - class TransformersActivationRule(MappingRule): - mapping = m - details = RuleDetails(name="transformers runner transformers activator rule", - watch_exclusion=True) - - return TransformersActivationRule, details - - def transform_rule(self, rule_instance): - r = rule_instance - orig_class = TransformersRunner._get_rule_class(r) - for transformer in self._transformers: - try: - r = transformer.get_transformed_rule(r) - TransformersRunner._post_transform_validate(orig_class, r) - except: - err = "Error while running transformer {} with {} rule." - printer.out(err.format(transformer, r)) - traceback.print_exc() - return r - - @staticmethod - def _get_rule_class(rule): - return rule.__class__ - - @staticmethod - def _post_transform_validate(orig_class, rule): - """ - There are only two changes you're not allowed to make to a rule. - 1. You're not allowed to change it into something which is not still its original class - or a child class of its original class. - 2. You're not allowed to change the name of its class. - """ - orig_rcn = orig_class.__name__ - current_class = TransformersRunner._get_rule_class(rule) - - no_class_change = orig_class == current_class - maintains_mapping_rule = issubclass(orig_class, MappingRule) and issubclass(current_class, MappingRule) - maintains_merge_rule = issubclass(orig_class, MergeRule) and issubclass(current_class, MergeRule) - maintains = no_class_change or maintains_mapping_rule or maintains_merge_rule - if not maintains: - raise InvalidTransformationError(ITMessage.BAD_TYPE, orig_rcn) - if orig_rcn != current_class.__name__: - raise InvalidTransformationError(ITMessage.CLASS_KEY, orig_rcn) diff --git a/castervoice/lib/merge/communication.py b/castervoice/lib/merge/communication.py deleted file mode 100644 index 74f8cf2b3..000000000 --- a/castervoice/lib/merge/communication.py +++ /dev/null @@ -1,22 +0,0 @@ -import xmlrpc.client as xmlrpclib - -class Communicator: - LOCALHOST = "127.0.0.1" - - def __init__(self): - self.coms = {} - self.com_registry = { - "hmc": 8337, - "hud": 8338, - "grids": 8339, - "sikuli": 8340 - } - - def get_com(self, name): - try: # try a ping - return self.coms[name] - except Exception: - com = xmlrpclib.ServerProxy( - "http://" + Communicator.LOCALHOST + ":" + str(self.com_registry[name])) - self.coms[name] = com - return com diff --git a/castervoice/lib/merge/mergerule.py b/castervoice/lib/merge/mergerule.py deleted file mode 100644 index 3d6818a2b..000000000 --- a/castervoice/lib/merge/mergerule.py +++ /dev/null @@ -1,105 +0,0 @@ -import collections - -from dragonfly import Function, MappingRule - -from castervoice.lib import available_commands_tracker, printer -from castervoice.lib.ctrl.mgr.rule_formatter import _set_rdescripts -from castervoice.lib.merge.ccrmerging2.pronounceable import Pronounceable - - -class MergeRule(MappingRule, Pronounceable): - - mapping = {} - extras = [] - defaults = {} - - '''MergeRules which define `pronunciation` will use - the pronunciation string rather than their class name - for their respective enable/disable commands''' - pronunciation = None - - def __init__(self, name=None, mapping=None, extras=None, defaults=None): - _name = name or self.get_rule_class_name() - _mapping = mapping or self.mapping.copy() - _extras = extras or self.extras[:] - _defaults = defaults or self.defaults.copy() - _set_rdescripts(_mapping, _name) - # - super(MergeRule, self).__init__(name=_name, - mapping=_mapping, - extras=_extras, - defaults=_defaults) - - def merge(self, other): - new_mapping = self.get_mapping() - new_mapping.update(other.get_mapping()) - - new_extras = self.get_extras() - new_extras.extend(other.get_extras()) - - new_defaults = self.get_defaults() - new_defaults.update(other.get_defaults()) - - return MergeRule(mapping=new_mapping, - extras=new_extras, - defaults=new_defaults) - - def to_mapping_rule(self): - return MappingRule(mapping=self.get_mapping(), - extras=self.get_extras(), - defaults=self.get_defaults()) - - def get_mapping(self): - return self._mapping.copy() - - def get_extras(self): - return list(self._extras.values()) - - def get_defaults(self): - return self._defaults.copy() - - def get_pronunciation(self): - return self.pronunciation if self.pronunciation is not None else self._name - - def prepare_for_merger(self): - """ - The OrderedDict is an optimization for Kaldi engine, - won't make a difference to other engines. - - This is also the appropriate place to add the "list available commands" - command, since this happens post-merge. - - :return: MergeRule - """ - - unordered_specs = set(self._mapping.keys()) - ordered_specs = sorted(unordered_specs) - - ordered_dict = collections.OrderedDict() - for spec in ordered_specs: - ordered_dict[spec] = self._mapping[spec] - - act = available_commands_tracker.get_instance() - act.set_available_commands("\n".join(ordered_specs)) - # TODO: bring back metarule - ordered_dict["list available commands"] = Function(lambda: printer.out(act.get_available_commands())) - - extras_copy = self.get_extras() - defaults_copy = self.get_defaults() - - class PreparedRule(MappingRule): - mapping = ordered_dict - extras = extras_copy - defaults = defaults_copy - - return PreparedRule() - - def get_rule_class_name(self): - return self.__class__.__name__ - - @staticmethod - def _get_next_id(): - if not hasattr(MergeRule._get_next_id, "id"): - MergeRule._get_next_id.id = 0 - MergeRule._get_next_id.id += 1 - return MergeRule._get_next_id.id diff --git a/castervoice/lib/merge/selfmod/__init__.py b/castervoice/lib/merge/selfmod/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/selfmod/selfmodrule.py b/castervoice/lib/merge/selfmod/selfmodrule.py deleted file mode 100644 index ee0d13594..000000000 --- a/castervoice/lib/merge/selfmod/selfmodrule.py +++ /dev/null @@ -1,83 +0,0 @@ -from dragonfly import Dictation, IntegerRef, ShortIntegerRef - -from castervoice.lib import printer -from castervoice.lib.ctrl.mgr.errors.base_class_error import DontUseBaseClassError -from castervoice.lib.merge.mergerule import MergeRule -from castervoice.lib.merge.selfmod.sm_config import SelfModStateSavingConfig -from castervoice.lib.merge.state.actions2 import NullAction - - -class BaseSelfModifyingRule(MergeRule): - - def __init__(self, config_path, name=None): - """ - SelfModifyingRule is a kind of rule which gets its command set changed - on-the-fly based on some kind of user interaction. Child classes - must implement their own version of the _refresh and - _deserialize methods. - - :param name: str - """ - self._reload_shim = None - self._hooks_runner = None - - default_smr_mapping = {"spec which gets replaced": NullAction()} - self._smr_mapping = default_smr_mapping - # extras and defaults may not get replaced: - self._smr_extras = [ShortIntegerRef("n", 1, 50), Dictation("s")] - self._smr_defaults = {"n": 1, "s": ""} - - self._config = SelfModStateSavingConfig(config_path) - self._config.load() - self._deserialize() - - MergeRule.__init__(self, name, self._smr_mapping, self._smr_extras, self._smr_defaults) - - def set_reload_shim(self, reload_shim): - """ - The reload shim has the ability to tell the GrammarManager - (or other manager class) to attempt to discard the current - in-memory instance of the selfmod rule and attempt to reload - from disk. - - :param reload_shim: SelfModReloadingShim - """ - self._reload_shim = reload_shim - - def set_hooks_runner(self, hooks_runner): - """ - The hooks runner can run selfmod reset-time hooks if this is set. - - :param hooks_runner: HooksRunner - """ - self._hooks_runner = hooks_runner - - def reset(self): - class_name = self.__class__.__name__ - if self._reload_shim is None: - printer.out("Reload shim is not set for {}. Rule cannot hot-reset, will only reset with engine.".format( - class_name)) - return - self._reload_shim.signal_reload(class_name) - - def _deserialize(self): - """ - This should ONLY be called by the constructor, nowhere else. - - Deserialize ALL state loaded from self._config into self._smr_mapping, - self._smr_extras, and self._smr_defaults. - - Child classes should implement this. - """ - raise DontUseBaseClassError(self) - - def _refresh(self, *args): - """ - Modifies state in some way, then calls self.reset(). - - Child classes should implement this. - - :param args: any - :return: - """ - raise DontUseBaseClassError(self) diff --git a/castervoice/lib/merge/selfmod/sm_config.py b/castervoice/lib/merge/selfmod/sm_config.py deleted file mode 100644 index 5e5c982c1..000000000 --- a/castervoice/lib/merge/selfmod/sm_config.py +++ /dev/null @@ -1,15 +0,0 @@ -import copy -from castervoice.lib.config.config_toml import TomlConfig - - -class SelfModStateSavingConfig(TomlConfig): - - def __init__(self, config_path): - super(SelfModStateSavingConfig, self).__init__(config_path) - - def replace(self, config): - self._config = config - self.save() - - def get_copy(self): - return copy.deepcopy(self._config.copy()) diff --git a/castervoice/lib/merge/selfmod/smr_configurer.py b/castervoice/lib/merge/selfmod/smr_configurer.py deleted file mode 100644 index 26e0bbacf..000000000 --- a/castervoice/lib/merge/selfmod/smr_configurer.py +++ /dev/null @@ -1,24 +0,0 @@ -from castervoice.lib.merge.selfmod.selfmodrule import BaseSelfModifyingRule -from castervoice.lib.merge.selfmod.smr_shim import SelfModReloadingShim - - -class SelfModRuleConfigurer(object): - """ - Configures a self modifying rule both for - hot-reset and hook events execution. - """ - - def __init__(self): - self._smr_shim = None - self._hooks_runner = None - - def set_reload_fn(self, reload_fn): - self._smr_shim = SelfModReloadingShim(reload_fn) - - def set_hooks_runner(self, hooks_runner): - self._hooks_runner = hooks_runner - - def configure(self, selfmodrule): - if isinstance(selfmodrule, BaseSelfModifyingRule): - selfmodrule.set_reload_shim(self._smr_shim) - selfmodrule.set_hooks_runner(self._hooks_runner) diff --git a/castervoice/lib/merge/selfmod/smr_shim.py b/castervoice/lib/merge/selfmod/smr_shim.py deleted file mode 100644 index 54e84aa06..000000000 --- a/castervoice/lib/merge/selfmod/smr_shim.py +++ /dev/null @@ -1,21 +0,0 @@ -from castervoice.lib import printer -from castervoice.lib.merge.selfmod.tree_rule.invalid_tree_node_path_error import InvalidTreeNodePathError - - -class SelfModReloadingShim(object): - """ - SelfModReloadingShim adds a safety net around reloading selfmodrules - from disk, as well as limiting access to the nexus / gm functionality. - """ - - def __init__(self, reload_fn): - self._reload_fn = reload_fn - - def signal_reload(self, rule_class_name): - printer.out("Reloading {}...".format(rule_class_name)) - try: - self._reload_fn(rule_class_name) - except InvalidTreeNodePathError: - printer.out("{} reload failed: tree path was invalidated.".format(rule_class_name)) - return - printer.out("{} reloaded.".format(rule_class_name)) diff --git a/castervoice/lib/merge/selfmod/tree_rule/__init__.py b/castervoice/lib/merge/selfmod/tree_rule/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/selfmod/tree_rule/invalid_tree_node_path_error.py b/castervoice/lib/merge/selfmod/tree_rule/invalid_tree_node_path_error.py deleted file mode 100644 index 7f44201fb..000000000 --- a/castervoice/lib/merge/selfmod/tree_rule/invalid_tree_node_path_error.py +++ /dev/null @@ -1,3 +0,0 @@ -class InvalidTreeNodePathError(Exception): - def __init__(self, active_path): - super(InvalidTreeNodePathError, self).__init__("Broken TreeNode path: {}".format(str(active_path))) \ No newline at end of file diff --git a/castervoice/lib/merge/selfmod/tree_rule/tree_node.py b/castervoice/lib/merge/selfmod/tree_rule/tree_node.py deleted file mode 100644 index 02bba142f..000000000 --- a/castervoice/lib/merge/selfmod/tree_rule/tree_node.py +++ /dev/null @@ -1,50 +0,0 @@ -from castervoice.lib.merge.selfmod.tree_rule.invalid_tree_node_path_error import InvalidTreeNodePathError - - -class TreeNode(object): - def __init__(self, spec, action, children=[], extras=[], defaults={}): - """ - An action with child actions. These child actions can form a tree - structure with this node and their child nodes. - - :param spec: (str) the spec for this node - :param action: (ActionBase) the action for this node - :param extras: extras for this node's action - :param defaults: defaults for this node's action - :param children: (list) child nodes of this node - """ - self._spec = spec - self._action = action - self._extras = extras - self._defaults = defaults - self._children = {} - for child in children: - self._children[child.get_spec()] = child - - def get_spec(self): - return self._spec - - def get_action(self): - return self._action - - def get_extras(self): - return list(self._extras) - - def get_defaults(self): - return self._defaults.copy() - - def get_children(self): - return self._children.copy() - - @staticmethod - def get_nodes_along_path(nodes, active_path): - - if len(active_path) == 0: - return nodes - - active_path = list(active_path) - selecting_spec = active_path.pop(0) - for node in nodes: - if selecting_spec == node.get_spec(): - return TreeNode.get_nodes_along_path(node.get_children().values(), active_path) - raise InvalidTreeNodePathError(active_path + [selecting_spec]) diff --git a/castervoice/lib/merge/selfmod/tree_rule/tree_rule.py b/castervoice/lib/merge/selfmod/tree_rule/tree_rule.py deleted file mode 100644 index ad952c87e..000000000 --- a/castervoice/lib/merge/selfmod/tree_rule/tree_rule.py +++ /dev/null @@ -1,92 +0,0 @@ -import os - -from dragonfly import Function -from castervoice.lib import settings -from castervoice.lib.ctrl.mgr.errors.tree_rule_config_error import TreeRuleConfigurationError -from castervoice.lib.ctrl.mgr.rule_formatter import _set_the_rdescript -from castervoice.lib.merge.ccrmerging2.hooks.events.node_change_event import NodeChangeEvent -from castervoice.lib.merge.selfmod.selfmodrule import BaseSelfModifyingRule -from castervoice.lib.merge.selfmod.tree_rule.tree_node import TreeNode - - -class TreeRule(BaseSelfModifyingRule): - - _PATH = "path" - - def __init__(self, tree_name, tree_root): - self._root_node = tree_root - self._tree_name = tree_name - super(TreeRule, self).__init__(TreeRule._get_tree_rule_config_path(tree_name)) - - @staticmethod - def _get_tree_rule_config_path(tree_name): - formatted_path_name = "SM_{}_TREE_PATH".format(tree_name.upper().replace(" ", "_")) - if formatted_path_name not in settings.SETTINGS["Tree_Node_Path"]: - msg = "Path '{}' was not found in the 'Tree_Node_Path' section of settings.toml. Did you add it?" - raise TreeRuleConfigurationError(msg.format(formatted_path_name)) - config_path = settings.settings(["Tree_Node_Path", formatted_path_name]) - return config_path - - def _deserialize(self): - # get active path from config - config_copy = self._config.get_copy() - active_path = [] - if TreeRule._PATH in config_copy: - active_path = list(config_copy[TreeRule._PATH]) - - # get speakable nodes along path of tree's branches - active_nodes = TreeNode.get_nodes_along_path([self._root_node], active_path) - - # create mapping/etc. from active nodes - self._smr_mapping = {} - self._smr_extras = [] - self._smr_defaults = {} - - for tree_node in active_nodes: - spec = tree_node.get_spec() - action = tree_node.get_action() - _set_the_rdescript(action, spec, self.__class__.__name__) - action_and_node_change = action + Function(TreeRule._create_spec_fn(self._refresh, spec)) - self._smr_mapping[spec] = action_and_node_change - self._smr_extras.extend(tree_node.get_extras()) - self._smr_defaults.update(tree_node.get_defaults()) - # cancel by TreeRule name: resets tree to root node - self._smr_mapping["cancel {}".format(self._tree_name)] = Function(lambda: self._refresh()) - - # run node change hooks, if configured - if self._hooks_runner is not None: - event = NodeChangeEvent(self._tree_name, active_path, [n.get_spec() for n in active_nodes]) - self._hooks_runner.execute(event) - - @staticmethod - def _create_spec_fn(fn, spec): - return lambda: fn(spec) - - def _refresh(self, *args): - config_copy = self._config.get_copy() - active_path = [] - if TreeRule._PATH in config_copy: - active_path = list(config_copy[TreeRule._PATH]) - - if len(args) > 0: - active_path.append(args[0]) - else: - active_path = [] - - self._detect_leaf_node_reached(active_path) - self._config.replace({TreeRule._PATH: active_path}) - self.reset() - - def _detect_leaf_node_reached(self, active_path): - """ - Detects if a leaf node's spec has been spoken. - If it has, resets the tree back to the root node. - """ - current_node = self._root_node - for node_spec in active_path: - children = current_node.get_children() - if node_spec in children: - current_node = children[node_spec] - - if len(current_node.get_children()) == 0: - del active_path[:] diff --git a/castervoice/lib/merge/selfmod/tree_rule/trees/__init__.py b/castervoice/lib/merge/selfmod/tree_rule/trees/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/selfmod/tree_rule/trees/css.py b/castervoice/lib/merge/selfmod/tree_rule/trees/css.py deleted file mode 100644 index 60a70ffdb..000000000 --- a/castervoice/lib/merge/selfmod/tree_rule/trees/css.py +++ /dev/null @@ -1,558 +0,0 @@ -from castervoice.lib.actions import Text -from castervoice.lib.const import CCRType -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.selfmod.tree_rule.tree_node import TreeNode -from castervoice.lib.merge.selfmod.tree_rule.tree_rule import TreeRule -from castervoice.lib.merge.state.actions2 import NullAction - -H = TreeNode -_style = H("style", Text("-style: "), [ - H("none", Text("none")), - H("hidden", Text("hidden")), - H("dotted", Text("dotted")), - H("dashed", Text("dashed")), - H("solid", Text("solid")), - H("double", Text("double")), - H("groove", Text("groove")), - H("ridge", Text("ridge")), - H("inset", Text("inset")), - H("outset", Text("outset")), -]) - - -def get_css_node(): - H = TreeNode - css_sections = [] - css_sections.append(_get_background()) - css_sections.append(_get_border()) - css_sections.append(_get_box()) - css_sections.append(_get_font()) - css_sections.append(_get_box_model()) - css_sections.append(_get_text()) - css_sections.append(_get_column()) - css_sections.append(_get_speech()) - css_sections += _get_miscellaneous() - - return H("css", NullAction(), css_sections) - - -def _get_speech(): - _volume = [ - H("uri", Text("uri")), - H("silent", Text("silent")), - H("extra soft", Text("x-soft")), - H("soft", Text("soft")), - H("medium", Text("medium")), - H("loud", Text("loud")), - H("extra loud", Text("x-loud")), - H("none", Text("none")), - H("inherit", Text("inherit")) - ] - _pause_rest = [ - H("none", Text("none")), - H("extra weak", Text("x-weak")), - H("weak", Text("weak")), - H("medium", Text("medium")), - H("strong", Text("strong")), - H("extra strong", Text("x-strong")), - H("inherit", Text("inherit")) - ] - _pitch = [ - H("extra low", Text("x-low")), - H("low", Text("low")), - H("medium", Text("medium")), - H("high", Text("high")), - H("extra high", Text("x-high")), - H("inherit", Text("inherit")) - ] - return H("speech", NullAction(), [ - H("cue", Text("cue"), [ - H("before", Text("-before: "), _volume), - H("after", Text("-after: "), _volume) - ]), - H("mark", Text("mark"), - [H("before", Text("-before: ")), - H("after", Text("-after"))]), - H("pause", Text("pause"), [ - H("before", Text("-before: "), _pause_rest), - H("after", Text("-after: "), _pause_rest) - ]), - H("rest", Text("rest"), [ - H("before", Text("-before: "), _pause_rest), - H("after", Text("-after: "), _pause_rest) - ]), - H("speak", Text("speak: "), [ - H("none", Text("none")), - H("normal", Text("normal")), - H("spell out", Text("spell-out")), - H("digits", Text("digits")), - H("literal punctuation", Text("literal-punctuation")), - H("no punctuation", Text("no-punctuation")), - H("inherit", Text("inherit")) - ]), - H("voice", Text("voice"), [ - H("balance", Text("-balance: "), [ - H("left", Text("left")), - H("center", Text("center")), - H("right", Text("right")), - H("leftwards", Text("leftwards")), - H("rightwards", Text("rightwards")), - H("inherit", Text("inherit")) - ]), - H("duration", Text("-duration: ")), - H("family", Text("-family: "), [H("inherit", Text("inherit"))]), - H("rate", Text("-rate: "), [ - H("extra low", Text("x-low")), - H("low", Text("low")), - H("medium", Text("medium")), - H("fast", Text("fast")), - H("next for fast", Text("x-fast")), - H("inherit", Text("inherit")), - ]), - H("pitch", Text("-pitch: "), _pitch), - H("pitch range", Text("-pitch-range: "), _pitch), - H("stress", Text("-stress: "), [ - H("strong", Text("strong")), - H("moderate", Text("moderate")), - H("none", Text("none")), - H("reduced", Text("reduced")), - H("inherit", Text("inherit")) - ]), - H("volume", Text("-volume: "), _volume) - ]), - ]) - - -def _get_column(): - H = TreeNode - global _style - return H("column", Text("column"), [ - H("count", Text("-count: "), [H("auto", Text("auto"))]), - H("fill", Text("-fill: "), - [H("auto", Text("auto")), - H("balance", Text("balance"))]), - H("gap", Text("-gap: "), [H("normal", Text("normal"))]), - H("rule", Text("-rule"), [ - H("color", Text("-color: "), [H("color", Text("COLOR"))]), - _style, - H("width", Text("-width: "), [ - H("thin", Text("thin")), - H("medium", Text("medium")), - H("thick", Text("thick")) - ]), - ]), - H("width", Text("-width: "), [H("auto", Text("auto"))]), - H("span", Text("-span: "), - [H("one", Text("1")), H("all", Text("all"))]) - ]) - - -def _get_text(): - H = TreeNode - _align = [ - H("start", Text("start")), - H("end", Text("end")), - H("left", Text("left")), - H("right", Text("right")), - H("center", Text("center")), - H("justify", Text("justify")) - ] - return H("text", Text("text"), [ - H("align", Text("-align: "), _align), - H("align last", Text("-align-last: "), _align), - H("decoration", Text("-decoration: "), [ - H("none", Text("none")), - H("underline", Text("underline")), - H("overline", Text("overline")), - H("line through", Text("line-through")), - H("blink", Text("blink")) - ]), - H("emphasis", Text("-emphasis: "), [ - H("none", Text("none")), - H("accent", Text("accent")), - H("dot", Text("dot")), - H("circle", Text("circle")), - H("disc", Text("disc")), - H("before", Text("before")), - H("after", Text("after")) - ]), - H("indent", Text("-indent: ")), - H("justify", Text("-justify: "), [ - H("auto", Text("auto")), - H("inter word", Text("inter-word")), - H("inter ideograph", Text("inter-ideograph")), - H("distribute", Text("distribute")), - H("kashida", Text("kashida")), - H("tibetan", Text("tibetan")) - ]), - H("outline", Text("-outline: "), [H("none", Text("none"))]), - H("shadow", Text("-shadow: "), - [H("none", Text("none")), H("color", Text("COLOR"))]), - H("transform", Text("-transform: "), [ - H("none", Text("none")), - H("capitalize", Text("capitalize")), - H("uppercase", Text("uppercase")), - H("lowercase", Text("lowercase")) - ]), - H("wrap", Text("-wrap: "), [ - H("normal", Text("normal")), - H("unrestricted", Text("unrestricted")), - H("none", Text("none")), - H("override", Text("override")) - ]) - ]) - - -def _get_miscellaneous(): - H = TreeNode - _sides = [ - H("top", Text("top")), - H("bottom", Text("bottom")), - H("left", Text("left")), - H("right", Text("right")) - ] - return [ - H("direction", Text("direction: "), [ - H("left to right", Text("ltr")), - H("right to left", Text("rtl")), - H("inherit", Text("inherit")) - ]), - H("hanging punctuation", Text("hanging-punctuation: "), [ - H("none", Text("none")), - H("start", Text("start")), - H("end", Text("end")), - H("end edge", Text("end-edge")) - ]), - H("letterspacing", Text("letter-spacing: "), [H("normal", Text("normal"))]), - H("unicode bidi", Text("unicode-bidi: "), [ - H("normal", Text("normal")), - H("embed", Text("embed")), - H("bidi override", Text("bidi-override")) - ]), - H("whitespace", Text("white-space: "), [ - H("normal", Text("normal")), - H("pre", Text("pre")), - H("no wrap", Text("nowrap")), - H("pre wrap", Text("pre-wrap")), - H("pre line", Text("pre-line")) - ]), - H("white space collapse", Text("white-space-collapse: "), [ - H("preserve", Text("preserve")), - H("collapse", Text("collapse")), - H("preserve breaks", Text("preserve-breaks")), - H("discard", Text("discard")) - ]), - H("word", Text("word"), [ - H("break", Text("-break: "), [ - H("normal", Text("normal")), - H("keep all", Text("keep-all")), - H("loose", Text("loose")), - H("break strict", Text("break-strict")), - H("break all", Text("break-all")), - ]), - H("spacing", Text("-spacing: "), [H("normal", Text("normal"))]), - H("wrap", Text("-wrap: "), - [H("normal", Text("normal")), - H("break word", Text("break-word"))]) - ]), - H("color", Text("color: "), - [H("inherit", Text("inherit")), - H("color", Text("COLOR"))]), - H("opacity", Text("opacity: "), [H("inherit", Text("inherit"))]), - H("tab side", Text("tab-side: "), _sides), - H("caption side", Text("caption-side: "), _sides), - H("empty cells", Text("empty-cells: "), - [H("show", Text("show")), H("hide", Text("hide"))]), - H("table layout", Text("table-layout"), - [H("auto", Text("auto")), H("fixed", Text("fixed"))]) - ] - - -def _get_box_model( -): # display can be optimized by doing more nesting, this whole section is to be moved somewhere else - H = TreeNode - _auto = [H("auto", Text("auto"))] - _height = H("height", Text("height: "), _auto) - _width = H("width", Text("width: "), _auto) - _sides = [ - H("top", Text("-top: "), _auto), - H("bottom", Text("-bottom: "), _auto), - H("left", Text("-left: "), _auto), - H("right", Text("-right: "), _auto) - ] - _overflow = [ - H("visible", Text("visible")), - H("hidden", Text("hidden")), - H("scroll", Text("scroll")), - H("auto", Text("auto")), - H("no display", Text("no-display")), - H("no content", Text("no-content")), - ] - return H("box model", NullAction(), [ - H("clear", Text("clear: "), [ - H("left", Text("left")), - H("right", Text("right")), - H("both", Text("both")), - H("none", Text("none")) - ]), - H("display", Text("display: "), [ - H("none", Text("none")), - H("block", Text("block")), - H("compact", Text("compact")), - H("table", Text("table")), - H("inline", Text("inline"), - [H("block", Text("-block")), - H("table", Text("-table"))]), - H("run in", Text("run-in")), - H("list item", Text("list-item")), - H("table", Text("table"), [ - H("row", Text("-row"), [H("group", Text("-group"))]), - H("footer", Text("-footer"), [H("group", Text("-group"))]), - H("column", Text("-column"), [H("group", Text("-group"))]), - H("cell", Text("-cell")), - H("caption", Text("-caption")) - ]), - H("ruby", Text("ruby"), [ - H("base", Text("-base"), [H("group", Text("-group"))]), - H("text", Text("-text"), [H("group", Text("-group"))]) - ]) - ]), - H("float", Text("float: "), - [H("left", Text("left")), - H("right", Text("right")), - H("none", Text("none"))]), _height, _width, - H("max", Text("max-"), [_height, _width]), - H("min", Text("min-"), [_height, _width]), - H("margin", Text("margin"), _sides), - H("padding", Text("padding"), _sides), - H("marquee", Text("marquee"), [ - H("direction", Text("-direction: "), - [H("forward", Text("forward")), - H("reverse", Text("reverse"))]), - H("loop", Text("-loop: "), [H("infinite", Text("infinite"))]), - H("play count", Text("-play-count: "), [H("infinite", Text("infinite"))]), - H("speed", Text("-speed: "), [ - H("slow", Text("slow")), - H("normal", Text("normal")), - H("fast", Text("fast")) - ]), - H("style", Text("-style: "), [ - H("scroll", Text("scroll")), - H("slide", Text("slide")), - H("alternate", Text("alternate")) - ]) - ]), - H("overflow", Text("overflow: "), _overflow), - H("overflow X", Text("overflow-x: "), _overflow), - H("overflow Y", Text("overflow-y: "), _overflow), - H("overflow style", Text("overflow-style: "), [ - H("auto", Text("auto")), - H("marquee line", Text("marquee-line")), - H("marquee block", Text("marquee-block")) - ]), - H("rotation", Text("rotation: "), [H("angle", Text("ANGLE"))]), - H("rotation point", Text("rotation-point: ")), - H("visibility", Text("visibility: "), [ - H("visible", Text("visible")), - H("hidden", Text("hidden")), - H("collapse", Text("collapse")) - ]) - ]) - - -def _get_font(): - H = TreeNode - return H("font", Text("font"), [ - H("family", Text("-family: "), [H("inherit", Text("inherit"))]), - H("size", Text("-size: "), [ - H("extra extra small", Text("xx-small")), - H("extra small", Text("x-small")), - H("small", Text("small")), - H("medium", Text("medium")), - H("large", Text("large")), - H("extra large", Text("x-large")), - H("extra extra large", Text("xx-large")), - H("smaller", Text("smaller")), - H("larger", Text("larger")), - H("inherit", Text("inherit")) - ]), - H("size adjust", Text("-size-adjust: "), - [H("none", Text("none")), - H("inherit", Text("inherit"))]), - H("stretch", Text("-stretch: "), [ - H("normal", Text("normal")), - H("wider", Text("wider")), - H("narrower", Text("narrower")), - H("ultra condensed", Text("ultra-condensed")), - H("extra condensed", Text("extra-condensed")), - H("condensed", Text("condensed")), - H("semi condensed", Text("semi-condensed")), - H("semi expanded", Text("semi-expanded")), - H("expanded", Text("expanded")), - H("extra expanded", Text("extra-expanded")), - H("ultra expanded", Text("ultra-expanded")), - H("inherit", Text("inherit")) - ]), - H("style", Text("-style: "), [ - H("normal", Text("normal")), - H("italic", Text("italic")), - H("oblique", Text("oblique")), - H("inherit", Text("inherit")) - ]), - H("variant", Text("-variant: "), [ - H("normal", Text("normal")), - H("small caps", Text("small-caps")), - H("inherit", Text("inherit")) - ]), - H("weight", Text("-weight: "), [ - H("normal", Text("normal")), - H("bold", Text("bold")), - H("bolder", Text("bolder")), - H("lighter", Text("lighter")), - H("inherit", Text("inherit")), - H("one hundred", Text("100")), - H("nine hundred", Text("900")) - ]) - ]) - - -def _get_box(): - H = TreeNode - return H("box", Text("box"), [ - H("shadow", Text("-shadow: "), - [H("inset", Text("inset")), - H("none", Text("none")), - H("color", Text("COLOR"))]), - H("align", Text("-align: "), - [H("start", Text("start")), - H("end", Text("end")), - H("center", Text("center"))]), - H("direction", Text("-direction: "), - [H("normal", Text("normal")), - H("reverse", Text("reverse"))]), - H("flex", Text("-flex: ")), - H("flex group", Text("-flex-group: ")), - H("lines", Text("-lines: "), - [H("single", Text("single")), - H("multiple", Text("multiple"))]), - H("orient", Text("-orient: "), [ - H("horizontal", Text("horizontal")), - H("vertical", Text("vertical")), - H("inline axis", Text("inline-axis")), - H("block axis", Text("block-axis")) - ]), - H("pack", Text("-pack: "), [ - H("start", Text("start")), - H("end", Text("end")), - H("center", Text("center")), - H("justify", Text("justify")) - ]), - H("sizing", Text("-sizing: "), [ - H("content box", Text("content-box")), - H("padding box", Text("padding-box")), - H("border box", Text("border-box")), - H("margin box", Text("margin-box")) - ]) - ]) - - -def _get_border(): - H = TreeNode - _width = H( - "width", Text("-width: "), - [H("thin", Text("thin")), - H("medium", Text("medium")), - H("thick", Text("thick"))]) - global _style - _color = H("color", Text("-color: "), [H("color", Text("COLOR"))]) - _radius = H("radius", Text("-radius: ")) - return H("border", Text("border"), [ - _width, _style, _color, - H("top", Text("-top"), [ - _width, _style, _color, - H("left", Text("-left"), [_radius]), - H("right", Text("-right"), [_radius]) - ]), - H("bottom", Text("-bottom"), [ - _width, _style, _color, - H("left", Text("-left"), [_radius]), - H("right", Text("-right"), [_radius]) - ]), - H("left", Text("-left"), [_width, _style, _color]), - H("right", Text("-right"), [_width, _style, _color]), - H("break", Text("-break"), - [_width, _style, _color, H("close", Text("close"))]), - H("collapse", Text("-collapse: "), - [H("collapse", Text("collapse")), - H("separate", Text("separate"))]), - H("spacing", Text("-spacing: ")) - ]) - - -def _get_background(): - H = TreeNode - halign = [ - H("left", Text("left")), - H("center", Text("center")), - H("right", Text("right")) - ] - background_position = halign + [ - H("X position", Text("xpos")), - H("Y position", Text("ypos")), - H("initial", Text("initial")), - H("inherit", Text("inherit")) - ] - background_box = [ - H("border box", Text("border-box")), - H("padding box", Text("padding-box")), - H("border box", Text("border-box")), - ] - return H("background", Text("background"), [ - H("image", Text("-image: "), [ - H("(Earl | URL)", Text("url")), - H("none", Text("none")), - ]), - H("position", Text("-position: "), [ - H("top", Text("top "), halign), - H("center", Text("center "), halign), - H("bottom", Text("bottom "), halign), - ] + background_position), - H("size", Text("-size: "), [ - H("auto", Text("auto")), - H("cover", Text("cover")), - H("contain", Text("contain")) - ]), - H("repeat", Text("-repeat: "), [ - H("repeat", Text("repeat")), - H("repeat X", Text("repeat-x")), - H("repeat Y", Text("repeat-y")), - H("no repeat", Text("no-repeat")), - ]), - H("attachment", Text("-attachment: "), - [H("scroll", Text("scroll")), - H("fixed", Text("fixed"))]), - H("origin", Text("-origin: "), background_box), - H("clip", Text("-clip: "), background_box + [H("no clip", Text("no-clip"))]), - H("color", Text("-color: "), [ - H("color", Text("COLOR")), - H("transparent", Text("transparent")), - ]), - H("break", Text("-break: "), [ - H("bounding box", Text("bounding-box")), - H("each box", Text("each-box")), - H("continuous", Text("continuous")), - ]) - ]) - - -class CSSTreeRule(TreeRule): - - pronunciation = "CSS" - - def __init__(self): - super(CSSTreeRule, self).__init__("CSS", get_css_node()) - - -def get_rule(): - return [CSSTreeRule, RuleDetails(ccrtype=CCRType.SELFMOD)] - diff --git a/castervoice/lib/merge/state/__init__.py b/castervoice/lib/merge/state/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/merge/state/actions.py b/castervoice/lib/merge/state/actions.py deleted file mode 100644 index a0cb929d6..000000000 --- a/castervoice/lib/merge/state/actions.py +++ /dev/null @@ -1,124 +0,0 @@ -from functools import reduce -from dragonfly import ActionBase - -from castervoice.lib import control -from castervoice.lib.merge.state.stackitems import StackItemRegisteredAction, \ - StackItemSeeker, StackItemAsynchronous - - -class RegisteredAction(ActionBase): - def __init__(self, - base, - rspec="default", - rdescript=None, - rundo=None, - show=True): - ActionBase.__init__(self) - self._nexus = None - self.base = base - self.rspec = rspec - self.rdescript = rdescript - self.rundo = rundo - self.show = show - - def __mul__(self, factor): - self.base = self.base * factor - return self - - def _execute(self, data=None): - # copies everything relevant and places it in the stack - self.nexus().state.add(StackItemRegisteredAction(self, data)) - - def set_nexus(self, nexus): - self._nexus = nexus - - def nexus(self): - return self._nexus or control.nexus() - - def __str__(self): - return '{}'.format(self.base) - - -class ContextSeeker(RegisteredAction): - def __init__(self, - back=None, - forward=None, - rspec="default", - rdescript="unnamed command (CS)", - reverse=False): - RegisteredAction.__init__(self, None) - self.back = back - self.forward = forward - self.rspec = rspec - self.rdescript = rdescript - self.reverse = reverse # indicates that context levels on backward seekers should be satisfied in reverse order - assert self.back is not None or self.forward is not None, "Cannot create ContextSeeker with no levels" - - def _execute(self, data=None): - self.nexus().state.add(StackItemSeeker(self, data)) - - def __str__(self): - tail = reduce((lambda x, y: "{}_{}".format(x, y)), self.forward) if isinstance(self.forward, list) else self.forward - return '{}!{}'.format(self.back, tail) if self.back else '!{}'.format(tail) - - -class AsynchronousAction(ContextSeeker): - ''' - AsynchronousAction should have exactly one ContextLevel with one ContextSet. - Any triggers in the 0th ContextSet will terminate the AsynchronousAction. - The repetitions parameter indicates the maximum times the function provided - in the 0th ContextSet should run. 0 indicates forever (or until the - termination word is spoken). The time_in_seconds parameter indicates - how often the associated function should run. - ''' - - def __init__(self, - forward, - time_in_seconds=1, - repetitions=0, - rdescript="unnamed command (A)", - blocking=True, - finisher=None): - forward[0].sets[ - 0].consume = False # consume is for ContextSeekers, not AsynchronousActions - ContextSeeker.__init__(self, None, forward) - self.repetitions = repetitions - self.time_in_seconds = time_in_seconds - self.rdescript = rdescript - self.blocking = blocking - self.base = finisher - assert self.forward is not None, "Cannot create AsynchronousAction with no termination commands" - assert len( - self.forward) == 1, "Cannot create AsynchronousAction with > or < one purpose" - - def _execute(self, data=None): - if data is not None: - if "time_in_seconds" in data: - self.time_in_seconds = float(data["time_in_seconds"]) - if "repetitions" in data: self.time_in_seconds = int(data["repetitions"]) - - self.nexus().state.add(StackItemAsynchronous(self, data)) - - def __str__(self): - action = reduce((lambda x, y: "{}${}".format(x, y)), self.forward) if isinstance(self.forward, list) else self.forward - return '#{}&{}*{}'.format(self.time_in_seconds, action, self.repetitions) - - @staticmethod - def hmc_complete(data_function): - ''' returns a function which applies the passed in function to - the data returned by the pop-up window - the returned function - will be called by AsynchronousAction's timer repeatedly, - to see if the data is available yet''' - - def check_complete(): - data = None - try: - data = control.nexus().comm.get_com("hmc").get_message() - if data is None: - return False - except Exception: - return False - data_function(data) - return True - - return check_complete diff --git a/castervoice/lib/merge/state/actions2.py b/castervoice/lib/merge/state/actions2.py deleted file mode 100644 index bfa9adb1b..000000000 --- a/castervoice/lib/merge/state/actions2.py +++ /dev/null @@ -1,156 +0,0 @@ -from dragonfly.actions.action_function import Function - -from castervoice.asynch.hmc import h_launch -from castervoice.lib import settings, utilities -from castervoice.lib.merge.state.actions import AsynchronousAction, \ - RegisteredAction -from castervoice.lib.merge.state.short import L, S -from castervoice.lib.merge.state.stackitems import StackItemConfirm, \ - StackItemAsynchronous - - -#win32gui.SystemParametersInfo(win32con.SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 1) -class BoxAction(AsynchronousAction): - ''' - Similar to AsynchronousAction, but the repeated action is always - checking on the Homunculus response. - ''' - - def __init__(self, - receiver, - rspec="default", - rdescript="unnamed command (BA)", - repetitions=60, - box_type=settings.QTYPE_DEFAULT, - box_settings={}, - log_failure=False): - _ = {"tries": 0} - self._ = _ # signals to the stack to cease waiting, return True terminates - - def check_for_response(): - try: - _data = self.nexus().comm.get_com("hmc").get_message() - except Exception: - if log_failure: utilities.simple_log() - _["tries"] += 1 - if _["tries"] > 9: - return True # try 10 times max if there's no Homonculus response - else: - return False - if _data is None: return False - try: - _data.append( - _["dragonfly_data"]) # pass dragonfly data into receiver function - _["dragonfly_data"] = None - receiver(_data) - except Exception: - if log_failure: utilities.simple_log() - return True - - AsynchronousAction.__init__( - self, # cannot block, if it does, it'll block its own confirm command - [L(S(["cancel"], check_for_response))], - 1, - repetitions, - rdescript, - blocking=False) - self.rspec = rspec - self.box_type = box_type - self.box_settings = box_settings # custom instructions for setting up the tk window ("Homunculus") - self.log_failure = log_failure - - def _execute(self, data=None): - self._["tries"] = 0 # reset - self._["dragonfly_data"] = data - h_launch.launch(self.box_type, data=self.encode_box_settings()) - self.nexus().state.add(StackItemAsynchronous(self, data)) - - def encode_box_settings(self): - result = "" - instructions_first = False - if self.box_type == settings.QTYPE_INSTRUCTIONS and "instructions" in self.box_settings: - result += settings.HMC_SEPARATOR.join( - self.box_settings["instructions"].split(" ")) + "|" - instructions_first = True - for key in self.box_settings.keys(): - if instructions_first and key == "instructions": - continue - result += settings.HMC_SEPARATOR.join(self.box_settings[key].split(" ")) + "|" - return result - - -class ConfirmAction(AsynchronousAction): - ''' - Similar to AsynchronousAction, but the repeated action is always - checking on the Homunculus response. - - - Homunculus response guide: - 0: no response yet - 1: True - 2: False - - - This is the only action which requires the nexus in the constructor; - the rest of them can use the setter. This is because on_complete - needs a nexus immediately. - ''' - - def __init__(self, - base, - rspec="default", - rdescript="unnamed command (CA)", - instructions="instructions missing", - nexus=None): - self.set_nexus(nexus) - on_complete = AsynchronousAction.hmc_complete(lambda data: receive_response(data)) - AsynchronousAction.__init__( - self, [L(S(["cancel"], on_complete))], 1, 60, rdescript, - False) # cannot block, if it does, it'll block its own confirm command - - self.base = base - self.rspec = rspec - self.instructions = instructions - - mutable_integer = {"value": 0} - - def receive_response( - data): # signals to the stack to cease waiting, return True terminates - ''' - receives response from homunculus, uses it to - stop the stack and tell the ConfirmAction how - to execute - ''' - mutable_integer["value"] = data["confirm"] - - self.mutable_integer = mutable_integer - - def _execute(self, data=None): - '''the factory (ConfirmAction) sharing data with the objects - it generates (StackItemConfirm) would be a problem if there - could ever be more than one of these at a time, but there can't''' - self.mutable_integer["value"] = 0 - - confirm_stack_item = StackItemConfirm(self, data) - confirm_stack_item.shared_state(self.mutable_integer) - - h_launch.launch( - settings.QTYPE_CONFIRM, - data=settings.HMC_SEPARATOR.join(self.instructions.split(" "))) - self.nexus().state.add(confirm_stack_item) - - -class NullAction(RegisteredAction): - def __init__(self, rspec="default", rdescript="unnamed command (RA)", show=False): - RegisteredAction.__init__( - self, - Function(lambda: None), - rspec=rspec, - rdescript=rdescript, - rundo=None, - show=show) - - -class UntilCancelled(AsynchronousAction): - def __init__(self, action, t=3): - AsynchronousAction.__init__(self, [L(S(["cancel"], action))], t, 100, "UC", False, - None) - self.show = True diff --git a/castervoice/lib/merge/state/contextoptions.py b/castervoice/lib/merge/state/contextoptions.py deleted file mode 100644 index 365a913a2..000000000 --- a/castervoice/lib/merge/state/contextoptions.py +++ /dev/null @@ -1,67 +0,0 @@ -''' -Created on Jun 7, 2015 - -@author: dave -''' - -from functools import reduce -from types import FunctionType - - -class ContextSet: # ContextSet - ''' - The context has composed one or more trigger words. These trigger words - will be the spec of another command. That other command will be consumed - by the ContextSeeker and will not be executed. - ''' - - def __init__(self, - specTriggers, - f, - parameters=None, - consume=True, - use_spoken=False, - use_rspec=False): - assert len(specTriggers) > 0, "ContextSet must have at least one spec trigger" - self.specTriggers = specTriggers - self.f = f - self.parameters = parameters - self.consume = consume - self.use_spoken = use_spoken - self.use_rspec = use_rspec - - def __str__(self): - prefix = reduce((lambda x, y: '{}`{}'.format(x, y)), - self.specTriggers) if len(self.specTriggers) > 1 else self.specTriggers[0].__str__() - params = reduce((lambda x, y: '{}, {}'.format(x, y)), self.parameters) if self.parameters else '' - action = self.f.__name__ if type(self.f) is FunctionType else self.f.__str__() - return '{}^{}({})'.format(prefix, action, params) - - -class ContextLevel: # ContextLevel - ''' - A ContextLevel is composed of one or more ContextSets. - Once one of the ContextSets is chosen, the ContextLevel is marked as satisfied - and the result, either an ActionBase or a function object is - determined and parameters set. - ''' - - def __init__(self, *args): - self.sets = args - self.satisfied = False - self.result = None # selected ContextSet - self.dragonfly_data = None - self.index = -1 # used to determine which eat() results to use - - def copy(self): - return ContextLevel(*self.sets) - - def number(self, index): # used for assigning indices - self.index = index - - def __str__(self): - if len(self.sets) > 1: - return reduce((lambda x, y: '{}, {}'.format(x, y)), self.sets) - elif len(self.sets) == 1: - return '{}'.format(self.sets[0]) - return '' diff --git a/castervoice/lib/merge/state/short.py b/castervoice/lib/merge/state/short.py deleted file mode 100644 index 09c7f1e43..000000000 --- a/castervoice/lib/merge/state/short.py +++ /dev/null @@ -1,12 +0,0 @@ -''' -Created on Jun 7, 2015 - -@author: dave -''' -# shorter names for classes -from castervoice.lib.merge.state.actions import RegisteredAction -from castervoice.lib.merge.state.contextoptions import ContextLevel, ContextSet - -R = RegisteredAction -L = ContextLevel -S = ContextSet diff --git a/castervoice/lib/merge/state/stack.py b/castervoice/lib/merge/state/stack.py deleted file mode 100644 index 453f82578..000000000 --- a/castervoice/lib/merge/state/stack.py +++ /dev/null @@ -1,135 +0,0 @@ -''' -Created on Jun 7, 2015 - -@author: dave -''' -import queue as Queue - -from castervoice.lib.merge.state.stackitems import StackItemSeeker, \ - StackItemRegisteredAction, StackItemAsynchronous, StackItemConfirm - - -class CasterState: - def __init__(self): - self.stack = ContextStack(self) - self.blocker = None - self.waiting = Queue.Queue() - - def add(self, stack_item): - if self.blocker is None: - ''' important to block before adding because the add might unblock ''' - if ContextStack.is_asynchronous(stack_item.type) and stack_item.blocking: - self.blocker = stack_item - self.stack.add(stack_item) - else: - if stack_item.rspec in self.blocker.get_triggers(): # let cancels go through - self.unblock() - while not self.waiting.empty(): - self.waiting.get_nowait() # discard the Queue if cancelled - self.add(stack_item) - else: - self.waiting.put_nowait(stack_item) - - def unblock(self): - self.blocker = None - - def run_waiting_commands(self): - self.unblock() - while not self.waiting.empty(): - task = self.waiting.get(True, 2) - task.execute() - if ContextStack.is_asynchronous(task.type): - self.blocker = task - break - - def terminate_asynchronous(self, success): - ''' only for use with Dragonfly Function actions which can't return true or false but need spoken parameters''' - self.blocker.execute(success) - - -class ContextStack: - def __init__(self, state): - self.list = [] - self.max_list_size = 30 - self.state = state - - def add(self, stack_item): - stack_item.preserve() - ''' case: the new item is has backward seeking -- - -- satisfy levels, then move on to other logic''' - if stack_item.type == StackItemSeeker.TYPE and stack_item.back is not None: - seeker = stack_item - stack_size = len(self.list) - seekback_size = len(seeker.back) - - for i in range(0, seekback_size): - '''determine whether the seeker should default''' - no_default = True - if not seeker.reverse: - index = i - no_default = index <= stack_size - 1 - else: - index = stack_size - 1 - i - no_default = index >= 0 - '''satisfy the current level''' - prior_stack_item = None - if no_default: - prior_stack_item = self.list[-seekback_size:][index] - seeker.satisfy_level(index, True, prior_stack_item) - seeker.get_parameters(index, prior_stack_item) - ''' case: there are forward seekers in the stack -- - -- every incomplete seeker has the reach to - get a level from this stack item, so make - a list of incomplete forward seekers, feed - the new stack item to each of them in order, - then check them each for completeness in order - and if they are complete, execute them in FIFO order''' - incomplete = self.get_incomplete_seekers() - number_incomplete = len(incomplete) - seeker_executions = [] - if number_incomplete > 0: - for i in range(0, number_incomplete): - seeker = incomplete[i] - unsatisfied = seeker.get_index_of_next_unsatisfied_level() - seeker.satisfy_level(unsatisfied, False, stack_item) - seeker_is_satisfied = seeker.get_index_of_next_unsatisfied_level() == -1 - ''' consume stack_item, but do not consume seekers; it would disable chaining''' - if (stack_item.type == StackItemRegisteredAction.TYPE or - (ContextStack.is_asynchronous(seeker.type) and seeker_is_satisfied)): - if seeker.forward[unsatisfied].result.consume: - stack_item.complete = True - stack_item.consumed = True - - seeker.get_parameters(unsatisfied, stack_item) - - if seeker_is_satisfied: - seeker_executions.append(lambda: seeker.execute(False)) - - stack_item_is_forward_seeker = stack_item.type == StackItemSeeker.TYPE and stack_item.forward is not None - stack_item_is_continuer = ContextStack.is_asynchronous(stack_item.type) - if not stack_item.consumed and not stack_item_is_forward_seeker and not stack_item_is_continuer: - stack_item.put_time_action( - ) # this is where display window information will happen - stack_item.execute() - elif stack_item_is_continuer: - stack_item.begin() - stack_item.put_time_action() - ''' forward seeker executions occur after unconsumed triggers -- moved here for more consistent behavior ''' - for seeker_execution in seeker_executions: - seeker_execution() - - self.list.append(stack_item) - if len(self.list) > self.max_list_size: # make this number configurable - self.list.remove(self.list[0]) - - def get_incomplete_seekers(self): - incomplete = [] - for i in range(0, len(self.list)): - if not self.list[ - i].complete: # no need to check type because only forward seekers will be incomplete - incomplete.append(self.list[i]) - return incomplete - - @staticmethod - def is_asynchronous(action_type): - return action_type in [StackItemAsynchronous.TYPE, StackItemConfirm.TYPE] diff --git a/castervoice/lib/merge/state/stackitems.py b/castervoice/lib/merge/state/stackitems.py deleted file mode 100644 index a973e9779..000000000 --- a/castervoice/lib/merge/state/stackitems.py +++ /dev/null @@ -1,264 +0,0 @@ -''' -Created on Jun 7, 2015 - -@author: dave -''' -from dragonfly import Pause, ActionBase, get_current_engine - -from castervoice.lib import printer, settings - - -class StackItem: - def __init__(self, type): - assert type in [ - StackItemRegisteredAction.TYPE, StackItemSeeker.TYPE, - StackItemAsynchronous.TYPE, StackItemConfirm.TYPE - ] - self.type = type - self.complete = False # indicates whether it has been run already - self.consumed = False # indicates that an undo is unnecessary - self.rspec = "default" - - def put_time_action(self): - ''' this always happens at the time that the Stack item is placed in the Stack ''' - - -class StackItemRegisteredAction(StackItem): - TYPE = "raction" - - def __init__(self, registered_action, data, type=TYPE): - StackItem.__init__(self, type) - self.dragonfly_data = data - self.base = registered_action.base - self.rspec = registered_action.rspec - self.rdescript = registered_action.rdescript - self.rundo = registered_action.rundo - self.show = registered_action.show - self.preserved = [] - self.nexus = registered_action.nexus() - - def execute(self): - self.complete = True - self.base.execute(self.dragonfly_data) - # do presentation here - self.clean() - - def clean(self): - self.dragonfly_data = None - self.base = None - - def preserve(self): - '''save the useful parts of the incoming dragonfly data - (in this case, spoken words)''' - if self.dragonfly_data is not None: - self.preserved = [x[0] for x in self.dragonfly_data["_node"].results] - return True - return False - - def get_preserved(self): - return self.preserved - - def put_time_action(self): - self.preserve() - if settings.SETTINGS["miscellaneous"]["print_rdescripts"] and self.show: - # formats rdescript with the given data - try: - rd = self.rdescript % self.dragonfly_data if self.dragonfly_data else self.rdescript - except KeyError: - rd = self.rdescript - except TypeError: - print("TypeError: dragonfly_data <{}>".format(self.dragonfly_data)) - rd = self.rdescript - printer.out(rd) - - -class StackItemSeeker(StackItemRegisteredAction): - TYPE = "seeker" - - def __init__(self, seeker, data, type=TYPE): - StackItemRegisteredAction.__init__(self, seeker, data, type) - if self.type == StackItemSeeker.TYPE: self.back = self.copy_direction(seeker.back) - self.forward = self.copy_direction(seeker.forward) - self.reverse = seeker.reverse - self.param_spoken = {} - self.param_rspec = {} - - @staticmethod - def copy_direction(context_levels): - result = None - if context_levels is not None: - result = [] - for i in range(0, len(context_levels)): - context_level = context_levels[i].copy() - context_level.number(i) - result.append(context_level) - return result - - def executeCL(self, context_level - ): # the return value is whether to terminate an AsynchronousAction - action = context_level.result.f - if action is None: - return False - elif isinstance(action, ActionBase): - action.execute(context_level.dragonfly_data) - return False - else: - # it's a function object, so get the parameters, if any - level = context_level.index - fnparams = context_level.result.parameters - if context_level.result.use_spoken: - fnparams = self.param_spoken[level] - if context_level.result.use_rspec: - fnparams = self.param_rspec[level] - if fnparams is None: - return action() - else: - return action(fnparams) - - def get_parameters(self, level, stack_item): - '''gets information from another stack item - for use as parameters in a ContextSet's - function object in executeCL()''' - self.param_spoken[level] = stack_item.preserved # array of strings - self.param_rspec[level] = stack_item.rspec # single string - - def clean(self): - '''clean up now-unnecessary references''' - StackItemRegisteredAction.clean(self) - if self.back is not None: - for context_level in self.back: - context_level.dragonfly_data = None - if self.forward is not None: - for context_level in self.forward: - context_level.dragonfly_data = None - - def fillCL(self, context_level, context_set): - context_level.result = context_set - context_level.dragonfly_data = self.dragonfly_data - - def execute(self, unused=None): # "unused" is only for Async, but must also be here - self.complete = True - c = [] - if self.reverse: self.back.reverse() - if self.back is not None: c += self.back - if self.forward is not None: c += self.forward - for context_level in c: - self.executeCL(context_level) - self.clean() - - def satisfy_level(self, level_index, is_back, stack_item): - direction = self.back if is_back else self.forward - reverse = -1 if self.reverse else 1 - context_level = direction[level_index*reverse] - if not context_level.satisfied: - if stack_item is not None: - for context_set in context_level.sets: - # stack_item must have a spec - if stack_item.rspec in context_set.specTriggers or "*" in context_set.specTriggers: - context_level.satisfied = True - self.fillCL(context_level, context_set) - break - if not context_level.satisfied: # if still not satisfied, do default - context_level.satisfied = True - self.fillCL(context_level, context_level.sets[0]) - - def get_index_of_next_unsatisfied_level(self): - for i in range(0, len(self.forward)): - context_level = self.forward[i] - if not context_level.satisfied: - return i - return -1 - - -class StackItemAsynchronous(StackItemSeeker): - TYPE = "continuer" - - def __init__(self, continuer, data, type=TYPE): - StackItemSeeker.__init__(self, continuer, data, type) - self.back = None - self.closure = None - self.fillCL(self.forward[0], - self.forward[0].sets[0]) # set context set and dragonfly data - self.repetitions = continuer.repetitions - - self.time_in_seconds = continuer.time_in_seconds - self.blocking = continuer.blocking - self.timer = None - - def satisfy_level( - self, level_index, is_back, stack_item - ): # level_index and is_back are unused here, but left in for compatibility - context_level = self.forward[0] - if not context_level.satisfied: - if stack_item is not None: - context_set = context_level.sets[0] - if stack_item.rspec in context_set.specTriggers: # stack_item must have a spec - context_level.satisfied = True - - def get_triggers(self): - return self.forward[0].sets[0].specTriggers - - def execute(self, success): # this method should be what deactivates the continuer - ''' - There are three ways this can be triggered: success, timeout, and cancel. - Success and timeout are in the closure. Cancels are handled in the Stack. - Waiting commands should only be run on success. - ''' - self.complete = True - - if self.base is not None: # finisher - self.base.execute() - - self.clean() - - if success: - self.nexus.state.run_waiting_commands() - else: - self.nexus.state.unblock() - - def clean(self): - StackItemSeeker.clean(self) - self.timer.stop() - self.timer = None - self.closure = None - - def begin(self): - '''here pass along a closure to the timer multiplexer''' - execute_context_levels = self.executeCL - context_level = self.forward[0] - repetitions = self.repetitions - count = {"value": 0} - execute = self.execute - - def closure(): - do_terminate = execute_context_levels(context_level) - if do_terminate: - execute(do_terminate) - - elif repetitions != 0: # if not run forever - count["value"] += 1 - if count["value"] == repetitions: - execute(False) - - self.closure = closure - self.timer = get_current_engine().create_timer(self.closure, self.time_in_seconds) - self.closure() - - -class StackItemConfirm(StackItemAsynchronous): - TYPE = "confirm" - - def __init__(self, confirm, data, type=TYPE): - StackItemAsynchronous.__init__(self, confirm, data, type) - self.base = Pause("50") + confirm.base # TODO: fix this race condition - self.rspec = confirm.rspec - self.hmc_response = 0 - - def execute(self, success): - if self.mutable_integer["value"] == 1: - self.base.execute(self.dragonfly_data) - self.base = None - StackItemAsynchronous.execute(self, success) - - def shared_state(self, mutable_integer): - self.mutable_integer = mutable_integer diff --git a/castervoice/lib/migration.py b/castervoice/lib/migration.py deleted file mode 100644 index 63c60afab..000000000 --- a/castervoice/lib/migration.py +++ /dev/null @@ -1,74 +0,0 @@ -from pathlib import Path -import shutil - -from castervoice.lib import settings -from castervoice.lib.ctrl.mgr.loading.load.content_root import ContentRoot -from castervoice.lib.merge.selfmod.sm_config import SelfModStateSavingConfig - - - -class UserDirUpdater(object): - - def __init__(self, user_dir): - self.user_dir = user_dir - self.root_user_content_package_name = ContentRoot.USER_DIR - - def create_user_dir_directories(self): - for directory in ["data", "sikuli", "settings"]: - Path(self.user_dir).joinpath(directory).mkdir(parents=True, exist_ok=True) - - def update_user_dir_packages_to_v1_7_0(self): - """ - Migrates Caster user dir from v1.0.0 structure to v1.7.0+ structure. - If used for first time, just sets up v1.7.0+ structure. - """ - self._make_root_user_content_package() - for directory in ["rules", "transformers", "hooks"]: - self._move_legacy_package(directory) - self._make_user_content_package(directory) - - def update_bringme_toml_to_v1_7_0(self): - user_dir_path = settings.settings(["paths", "USER_DIR"]) - bringme_config_path = settings.settings(["paths", "SM_BRINGME_PATH"]) - bringme_config = SelfModStateSavingConfig(bringme_config_path) - bringme_config.load() - directory_dict = bringme_config.get("folder") - - if directory_dict is not None and ContentRoot.USER_DIR not in directory_dict["caster rules"]: - # make a backup copy - copy_destination = str(Path(bringme_config_path).with_name("sm_bringme.toml.bak")) - shutil.copy2(str(Path(bringme_config_path)), copy_destination) - - # update the user content paths in the bringme config - directory_dict["caster rules"] = \ - str(Path(user_dir_path).joinpath(ContentRoot.USER_DIR).joinpath("rules")) - directory_dict["caster hooks"] = \ - str(Path(user_dir_path).joinpath(ContentRoot.USER_DIR).joinpath("hooks")) - directory_dict["caster transformers"] = \ - str(Path(user_dir_path).joinpath(ContentRoot.USER_DIR).joinpath("transformers")) - bringme_config.put("folder", directory_dict) - bringme_config.save() - - def _move_legacy_package(self, package_name): - source_path = Path(self.user_dir).joinpath(package_name) - dest_path_base = Path(self.user_dir).joinpath(self.root_user_content_package_name).joinpath(package_name) - dest_path_base.mkdir(parents=True, exist_ok=True) - if source_path.exists(): - for f in source_path.glob("*"): - f.rename(dest_path_base.joinpath(f.stem)) - source_path.rmdir() - - def _make_user_content_package(self, package_name): - """idempotent""" - root_package_path = Path(self.user_dir).joinpath(self.root_user_content_package_name) - package_path = root_package_path.joinpath(package_name) - package_path.mkdir(parents=True, exist_ok=True) - - init_py_file = package_path.joinpath("__init__.py") - init_py_file.touch(exist_ok=True) - - def _make_root_user_content_package(self): - """idempotent""" - root_user_content_package_path = Path(self.user_dir).joinpath(self.root_user_content_package_name) - root_user_content_package_path.mkdir(parents=True, exist_ok=True) - root_user_content_package_path.joinpath("__init__.py").touch(exist_ok=True) diff --git a/castervoice/lib/navigation.py b/castervoice/lib/navigation.py deleted file mode 100644 index f55e9296e..000000000 --- a/castervoice/lib/navigation.py +++ /dev/null @@ -1,308 +0,0 @@ -''' -master_text_nav shouldn't take strings as arguments - it should take ints, so it can be language-agnostic -''' -import six -import subprocess -import time -from dragonfly import get_current_engine, monitors -from castervoice.lib import control, settings, utilities, textformat, printer -from castervoice.lib.actions import Key, Text, Mouse -from castervoice.lib.clipboard import Clipboard - - -class _NavClipBoard(object): - """ - Singleton isn't great, but it's at least better than a global which is - read from disk on first import. - """ - _INSTANCE = None - - def __init__(self): - self.clip = utilities.load_json_file( - settings.settings(["paths", "SAVED_CLIPBOARD_PATH"])) - - @staticmethod - def get_instance(): - if _NavClipBoard._INSTANCE is None: - _NavClipBoard._INSTANCE = _NavClipBoard() - return _NavClipBoard._INSTANCE - - -class Grid: - GRID_PROCESS = None - MODE = None - - @classmethod - def is_grid_active(cls, grid): - # Mouse Grids call this with function context. - # False: MouseGrid rules are not active - # True: MouseGrid rule are active - # grid: grid name - if cls.MODE is None: - return False - elif cls.MODE == grid: - return True - - @classmethod - def mouse_alternates(cls, mode, monitor=1, rough=True): - # Launches the Mouse Grid - args = [] - - if cls.GRID_PROCESS is not None: - cls.GRID_PROCESS.poll() - # If close by Task Manager - # TODO Test MacOS/Linux. Handle error codes when Grid close by Task Manager. - if cls.GRID_PROCESS.returncode == 15: - cls.GRID_PROCESS = None - cls.MODE = None - else: - # This message should only occur if grid is visible. - printer.out("Mouse Grid navigation already in progress \n Return Code: {}".format(cls.GRID_PROCESS.returncode)) - return - - if mode == "legion": - from castervoice.asynch.mouse.legion import LegionScanner - r = monitors[int(monitor) - 1].rectangle - bbox = [ - int(r.x), - int(r.y), - int(r.x) + int(r.dx) - 1, - int(r.y) + int(r.dy) - 1 - ] - ls = LegionScanner() - ls.scan(bbox, rough) - tscan = ls.get_update() - args = [ - settings.settings(["paths", "PYTHONW"]), - settings.settings(["paths", "LEGION_PATH"]), "-t", tscan[0], "-m", - str(monitor) - ] - elif mode == "rainbow": - args = [ - settings.settings(["paths", "PYTHONW"]), - settings.settings(["paths", "RAINBOW_PATH"]), "-g", "r", "-m", - str(monitor) - ] - elif mode == "douglas": - args = [ - settings.settings(["paths", "PYTHONW"]), - settings.settings(["paths", "DOUGLAS_PATH"]), "-g", "d", "-m", - str(monitor) - ] - elif mode == "sudoku": - args = [ - settings.settings(["paths", "PYTHONW"]), - settings.settings(["paths", "SUDOKU_PATH"]), "-g", "s", "-m", - str(monitor) - ] - cls.MODE=mode - cls.GRID_PROCESS = subprocess.Popen(args) if args else None - - @classmethod - def wait_for_grid_exit(cls, timeout=5): - # Polls Grid process until exit - if cls.GRID_PROCESS: - # TODO Remove if-part after fully migrating to Python3 - if six.PY2: - t = 0.0 - inc = 0.1 - while t < timeout: - cls.GRID_PROCESS.poll() - if cls.GRID_PROCESS.returncode is not None: - break - t += inc - time.sleep(inc) - if t >= timeout: - cls.GRID_PROCESS.kill() - else: - try: - cls.GRID_PROCESS.wait(timeout) - except subprocess.TimeoutExpired: # pylint: disable=no-member - cls.GRID_PROCESS.kill() - cls.MODE = None - cls.GRID_PROCESS = None - - @classmethod - def kill(cls): - # Kills the current grid - control.nexus().comm.get_com("grids").kill() - cls.wait_for_grid_exit() - -def _text_to_clipboard(keystroke, nnavi500): - if nnavi500 == 1: - Key(keystroke).execute() - else: - max_tries = 20 - cb = Clipboard(from_system=True) - Key(keystroke).execute() - key = str(nnavi500) - for i in range(0, max_tries): - failure = False - try: - # time for keypress to execute - time.sleep( - settings.settings([u'miscellaneous', u'keypress_wait'])/1000.) - _NavClipBoard.get_instance().clip[key] = Clipboard.get_system_text() - utilities.save_json_file( - _NavClipBoard.get_instance().clip, settings.settings([u'paths', u'SAVED_CLIPBOARD_PATH'])) - except Exception: - failure = True - utilities.simple_log() - if not failure: - break - cb.copy_to_system() - - -def stoosh_keep_clipboard(nnavi500): - _text_to_clipboard("c-c", nnavi500) - - -def cut_keep_clipboard(nnavi500): - _text_to_clipboard("c-x", nnavi500) - - -def drop_keep_clipboard(nnavi500, capitalization, spacing): - # Maintain standard spark functionality for non-strings - if capitalization == 0 and spacing == 0 and nnavi500 == 1: - Key("c-v").execute() - return - # Get clipboard text - if nnavi500 > 1: - key = str(nnavi500) - if key in _NavClipBoard.get_instance().clip: - text = _NavClipBoard.get_instance().clip[key] - else: - get_current_engine().speak("slot empty") - text = None - else: - text = Clipboard.get_system_text() - # Format if necessary, and paste - if text is not None: - cb = Clipboard(from_system=True) - if capitalization != 0 or spacing != 0: - text = textformat.TextFormat.formatted_text( - capitalization, spacing, text) - Clipboard.set_system_text(text) - time.sleep(settings.settings([u'miscellaneous', u'keypress_wait'])/1000.) - Key("c-v").execute() - time.sleep(settings.settings([u'miscellaneous', u'keypress_wait'])/1000.) - # Restore the clipboard contents. - cb.copy_to_system() - - -def duple_keep_clipboard(nnavi50): - cb = Clipboard(from_system=True) - Key("escape, home, s-end, c-c, end").execute() - time.sleep(settings.settings([u'miscellaneous', u'keypress_wait'])/1000.) - for i in range(0, nnavi50): - Key("enter, c-v").execute() - time.sleep(settings.settings([u'miscellaneous', u'keypress_wait'])/1000.) - cb.copy_to_system() - - -def erase_multi_clipboard(): - _NavClipBoard.get_instance().clip = {} - utilities.save_json_file(_NavClipBoard.get_instance().clip, - settings.settings([u'paths', u'SAVED_CLIPBOARD_PATH'])) - - -def mouse_click(button): - if Grid.GRID_PROCESS is not None: - Grid.kill() - Mouse(button).execute() - - -left_click = lambda: mouse_click("left") -right_click = lambda: mouse_click("right") -middle_click = lambda: mouse_click("middle") -left_down = lambda: mouse_click("left:down") -left_up = lambda: mouse_click("left:up") -right_down = lambda: mouse_click("right:down") -right_up = lambda: mouse_click("right:up") - - -def wheel_scroll(direction, nnavi500): - wheel = "wheelup" if direction == "up" else "wheeldown" - for i in range(1, abs(nnavi500) + 1): - Mouse("{}:1/10".format(wheel)).execute() - - -def curse(direction, direction2, nnavi500, dokick): - x, y = 0, 0 - d = str(direction) - d2 = str(direction2) - if d == "up" or d2 == "up": - y = -nnavi500 - if d == "down" or d2 == "down": - y = nnavi500 - if d == "left" or d2 == "left": - x = -nnavi500 - if d == "right" or d2 == "right": - x = nnavi500 - - Mouse("<" + str(x) + ", " + str(y) + ">").execute() - if int(dokick) != 0: - if int(dokick) == 1: - left_click() - elif int(dokick) == 2: - right_click() - -def previous_line(semi): - semi = str(semi) - Key("escape").execute() - time.sleep(0.05) - Key("end").execute() - time.sleep(0.05) - Text(semi).execute() - time.sleep(0.05) - Key("up").execute() - time.sleep(0.05) - Key("enter").execute() - -def next_line(semi): - semi = str(semi) - Key("escape").execute() - time.sleep(0.05) - Key("end").execute() - time.sleep(0.05) - Text(semi).execute() - Key("enter").execute() - - -''' -function for performing an action on one or more lines in a text editor. -E.g.: "cut 128 by 148" - -action: key combination to be pressed once the body of text has been highlighted, could be an empty string -ln1, ln2: line numbers, usually ShortIntegerRef, the default for ln2 should be an empty string -go_to_line: key combo to navigate by line number -select_line_down: key combo to select the line below -wait: some applications are slow and need a pause between keystrokes, e.g. wait="/10" -upon_arrival: keystroke to be pressed after arriving at the first line. Should have a comma afterwards, e.g. "home, " -''' - - -def action_lines(action, - ln1, - ln2, - go_to_line="c-g", - select_line_down="s-down", - wait="", - upon_arrival=""): - num_lines = max(int(ln2) - int(ln1) + 1, int(ln1) - - int(ln2) + 1) if ln2 else 1 - top_line = min(int(ln2), int(ln1)) if ln2 else int(ln1) - command = Key(go_to_line) + Text(str(top_line)) + Key( - "enter%s, %s%s%s:%s, %s" % - (wait, upon_arrival, select_line_down, wait, str(num_lines), action)) - command.execute() - - -actions = { - "select": "", - "copy": "c-c", - "cut": "c-x", - "paste": "c-v", - "delete": "backspace", - "comment": "c-slash", -} diff --git a/castervoice/lib/printer.py b/castervoice/lib/printer.py deleted file mode 100644 index 5cd9448ae..000000000 --- a/castervoice/lib/printer.py +++ /dev/null @@ -1,65 +0,0 @@ -class _DelegatingPrinterMessageHandler(object): - - def __init__(self): - self._queued_messages = [] - self._handlers = [] - self._error_handler = SimplePrintMessageHandler() - - def register_handler(self, handler): - self._handlers.append(handler) - - def handle_message(self, items): - self._queued_messages.append(items) - if len(self._handlers) > 0: - # transfer all messages to a temporary list for processing - messages = self._queued_messages[:] - # empty out the saved messages - del self._queued_messages[:] - - for message in messages: - for handler in self._handlers: - try: - handler.handle_message(message) - except: - self._error_handler.handle_message(message) - - -class BaseMessageHandler(object): - - def handle_message(self, items): - """ - Child classes should implement this, - doing something with the 'items' list. - Each 'item' in the list is an object which - was passed to printer.out as one of its *args. - """ - from castervoice.lib.ctrl.mgr.errors.base_class_error import DontUseBaseClassError - raise DontUseBaseClassError(self) - - -class SimplePrintMessageHandler(BaseMessageHandler): - """ - A simple message handler which only prints messages to the console, - newline-delimited. - """ - - def __init__(self): - super(SimplePrintMessageHandler, self).__init__() - self._print = print - - def handle_message(self, items): - self._print("\n".join([str(m) for m in items])) - - -_DELEGATING_HANDLER = _DelegatingPrinterMessageHandler() - - -def out(*args): - """ - Queues up a message to be printed or otherwise handled. - """ - _DELEGATING_HANDLER.handle_message(args) - - -def get_delegating_handler(): - return _DELEGATING_HANDLER diff --git a/castervoice/lib/qt.py b/castervoice/lib/qt.py deleted file mode 100644 index f4e735647..000000000 --- a/castervoice/lib/qt.py +++ /dev/null @@ -1,41 +0,0 @@ -# pylint: disable=import-error,no-name-in-module - -""" -Minimal PySide2/PySide6 compatibility helpers. -""" - - -try: - from PySide2 import QtCore, QtGui, QtWidgets # type: ignore - QT_API = "PySide2" -except ImportError: # pragma: no cover - from PySide6 import QtCore, QtGui, QtWidgets # type: ignore - QT_API = "PySide6" - - -def qt_attr(root, *paths): - """ - Return the first attribute path that exists on `root`. - - `paths` should be tuples of attribute names, e.g. ("Qt", "Key", "Key_Tab"). - """ - last_error = None - for path in paths: - try: - obj = root - for name in path: - obj = getattr(obj, name) - return obj - except AttributeError as exc: - last_error = exc - if last_error is None: - raise AttributeError("qt_attr() requires at least one path") - raise last_error - - -def qapp_exec(app): - exec_fn = getattr(app, "exec", None) or getattr(app, "exec_", None) - if exec_fn is None: - raise AttributeError("QApplication has no exec/exec_ method") - return exec_fn() - diff --git a/castervoice/lib/rules_collection.py b/castervoice/lib/rules_collection.py deleted file mode 100644 index f1ba607aa..000000000 --- a/castervoice/lib/rules_collection.py +++ /dev/null @@ -1,33 +0,0 @@ -''' -Collection of rules that are merged into a CCR grammar. -''' -_RULES = None - - -class RulesCollection: - - def __init__(self): - self._rules = [] - - def update(self, rules=None): - self._rules = rules - - def serialize(self): - rules = [] - for rule in self._rules: - klass = rule.get_rule_class() - instance = rule.get_rule_instance() - mapping = instance._smr_mapping if '_smr_mapping' in instance.__dict__ else klass.mapping - specs = sorted(["{}::{}".format(x, mapping[x]) for x in mapping]) - rules.append({ - 'name': rule.get_rule_class_name(), - 'specs': specs - }) - return [{'name': 'ccr', 'rules': rules}] - - -def get_instance(): - global _RULES - if _RULES is None: - _RULES = RulesCollection() - return _RULES diff --git a/castervoice/lib/settings.py b/castervoice/lib/settings.py deleted file mode 100644 index 186f071a0..000000000 --- a/castervoice/lib/settings.py +++ /dev/null @@ -1,491 +0,0 @@ -import sys, os -from collections.abc import Mapping -import io -from pathlib import Path - -import tomlkit -from appdirs import * -from castervoice.lib import printer, version -from castervoice.lib.util import guidance -from past.builtins import xrange - -# consts: some of these can easily be moved out of this file -GENERIC_HELP_MESSAGE = """ -If you continue having problems with this or any other issue you can contact -us through Gitter at or on our GitHub -issue tracker at . -Thank you for using Caster! -""" -SOFTWARE_VERSION_NUMBER = version.__version__ -SOFTWARE_NAME = "Caster v " + SOFTWARE_VERSION_NUMBER -HOMUNCULUS_VERSION = "HMC v " + SOFTWARE_VERSION_NUMBER -HMC_TITLE_RECORDING = " :: Recording Manager" -HMC_TITLE_DIRECTORY = " :: Directory Selector" -HMC_TITLE_CONFIRM = " :: Confirm" -HUD_TITLE = "Caster HUD v " + SOFTWARE_VERSION_NUMBER -LEGION_TITLE = "legiongrid" -RAINBOW_TITLE = "rainbowgrid" -DOUGLAS_TITLE = "douglasgrid" -SUDOKU_TITLE = "sudokugrid" -SETTINGS_WINDOW_TITLE = "Caster Settings Window v " -QTYPE_DEFAULT = "0" -QTYPE_INSTRUCTIONS = "3" -QTYPE_RECORDING = "4" -QTYPE_DIRECTORY = "5" -QTYPE_CONFIRM = "6" -QTTYPE_SETTINGS = "7" -HMC_SEPARATOR = "[hmc]" - -# calculated fields -SETTINGS = None -SYSTEM_INFORMATION = None -WSR = False -_BASE_PATH = None -_USER_DIR = None -_SETTINGS_PATH = None - - -def _get_platform_information(): - """Return a dictionary containing platform-specific information.""" - import sysconfig - system_information = {"platform": sysconfig.get_platform()} - system_information.update({"python version": sys.version_info}) - binary_path = str(Path(sys.exec_prefix).joinpath(sys.exec_prefix).joinpath("bin")) - hidden_console_binary = str(Path(sys.executable)) - main_binary = str(Path(sys.executable)) - if sys.platform == "win32": - if sys.prefix == sys.base_prefix: - main_binary = str(Path(sys.exec_prefix).joinpath("python.exe")) - hidden_console_binary = str(Path(sys.exec_prefix).joinpath("pythonw.exe")) - else: - # Virtual environment detected - # TODO: MacOS and Linux? - main_binary = str(Path(sys.prefix) / "Scripts" / "python.exe") - hidden_console_binary = str(Path(sys.prefix) / "Scripts" / "pythonw.exe") - system_information.update({"binary path": binary_path}) - system_information.update({"main binary": main_binary}) - system_information.update({"hidden console binary": hidden_console_binary}) - - return system_information - - -def get_filename(): - return _SETTINGS_PATH - - -def _validate_engine_path(): - ''' - Validates path 'Engine Path' in settings.toml - ''' - if not sys.platform.startswith('win'): - return '' - try: - from natlink import isNatSpeakRunning # pylint: disable=import-error - except ImportError: - return '' - if os.path.isfile(_SETTINGS_PATH): - with io.open(_SETTINGS_PATH, "rt", encoding="utf-8") as toml_file: - data = tomlkit.loads(toml_file.read()).value - engine_path = data["paths"]["ENGINE_PATH"] - if os.path.isfile(engine_path): - return engine_path - else: - if isNatSpeakRunning() is True: - engine_path = _find_natspeak() - data["paths"]["ENGINE_PATH"] = engine_path - try: - formatted_data = str(tomlkit.dumps(data)) - with io.open(_SETTINGS_PATH, "w", encoding="utf-8") as toml_file: - toml_file.write(formatted_data) - printer.out("Setting engine path to {}".format(engine_path)) - except Exception as e: - printer.out("Error saving settings file {} {} ".format(e, _SETTINGS_PATH)) - return engine_path - else: - return _find_natspeak() - - -def _find_natspeak(): - ''' - Finds engine 'natspeak.exe' path and verifies supported DNS versions via Windows Registry. - ''' - - try: - import winreg - except ImportError: - printer.out("Could not import winreg") - return "" - - printer.out("Searching Windows Registry For DNS...") - proc_arch = os.environ['PROCESSOR_ARCHITECTURE'].lower() - try: - proc_arch64 = os.environ['PROCESSOR_ARCHITEW6432'].lower() - except KeyError: - proc_arch64 = False - - if proc_arch == 'x86' and not proc_arch64: - arch_keys = {0} - elif proc_arch == 'x86' or proc_arch == 'amd64': - arch_keys = {winreg.KEY_WOW64_32KEY, winreg.KEY_WOW64_64KEY} - else: - raise Exception("Unhandled arch: %s" % proc_arch) - - for arch_key in arch_keys: - key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, - "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", - 0, winreg.KEY_READ | arch_key) - for i in xrange(0, winreg.QueryInfoKey(key)[0]): - skey_name = winreg.EnumKey(key, i) - skey = winreg.OpenKey(key, skey_name) - DisplayName, Publisher, DisplayVersion, InstallLocation = 'null' - try: - DisplayName = winreg.QueryValueEx(skey, 'DisplayName')[0] - Publisher = winreg.QueryValueEx(skey, 'Publisher')[0] - DisplayVersion = winreg.QueryValueEx(skey, 'DisplayVersion')[0] - InstallLocation = winreg.QueryValueEx(skey, 'InstallLocation')[0] - except OSError as error: - if error.errno == 2: # Suppresses '[Error 2] The system cannot find the file specified' - pass - else: - printer.out(error) - finally: - skey.Close() - if Publisher == "Nuance Communications Inc." and "Dragon" in DisplayName: - DnsVersion = int(str(DisplayVersion)[:2]) - if DnsVersion >= 13: - engine_path = str(Path(InstallLocation).joinpath("Program/natspeak.exe")) - if os.path.isfile(engine_path): - printer.out("Search Complete.") - return engine_path - else: - printer.out( - "Dragon Naturally Speaking {} is not supported by Caster. Only versions 13 and above are supported. Purchase Dragon Naturally Speaking 13 or above" - .format(DnsVersion)) - printer.out("Cannot find dragon engine path") - return "" - - -def _save(data, path): - """ - Only to be used for settings file. - :param data: - :param path: - :return: - """ - guidance.offer() - try: - formatted_data = str(tomlkit.dumps(data)) - with io.open(path, "wt", encoding="utf-8") as f: - f.write(formatted_data) - except Exception as e: - printer.out("Error saving toml file: {} {}".format(e, _SETTINGS_PATH)) - - -def _init(path): - guidance.offer() - result = {} - try: - with io.open(path, "rt", encoding="utf-8") as f: - result = tomlkit.loads(f.read()).value - except ValueError as e: - printer.out("\n\n {} while loading settings file: {} \n\n".format(repr(e), path)) - printer.out(sys.exc_info()) - except IOError as e: - printer.out("\n\n {} while loading settings file: {} \nAttempting to recover...\n\n".format(repr(e), path)) - default_settings = _get_defaults() - result, num_default_added = _deep_merge_defaults(result, default_settings) - if num_default_added > 0: - printer.out("Default settings values added: {} ".format(num_default_added)) - _save(result, _SETTINGS_PATH) - return result - - -def _deep_merge_defaults(data, defaults): - """ - Recursivly merge data and defaults, preferring data. - Only handles nested dicts and scalar values. - Modifies `data` in place. - """ - changes = 0 - for key, default_value in defaults.items(): - # If the key is in the data, use that, but call recursivly if it's a dict. - if key in data: - if isinstance(data[key], Mapping): - child_data, child_changes = _deep_merge_defaults(data[key], default_value) - data[key] = child_data - changes += child_changes - else: - data[key] = default_value - changes += 1 - return data, changes - - -def _get_defaults(): - terminal_path_default = "C:/Program Files/Git/git-bash.exe" - if not os.path.isfile(terminal_path_default): - terminal_path_default = "" - - ahk_path_default = "C:/Program Files/AutoHotkey/AutoHotkey.exe" - if not os.path.isfile(ahk_path_default): - ahk_path_default = "" - - return { - "paths": { - "BASE_PATH": - _BASE_PATH, - "USER_DIR": - _USER_DIR, - # pathlib string conversion can be removed once pathlib is utilized throughout Caster. - # DATA - "SM_BRINGME_PATH": - str(Path(_USER_DIR).joinpath("settings/sm_bringme.toml")), - "SM_ALIAS_PATH": - str(Path(_USER_DIR).joinpath("data/sm_aliases.toml")), - "SM_CHAIN_ALIAS_PATH": - str(Path(_USER_DIR).joinpath("data/sm_chain_aliases.toml")), - "SM_HISTORY_PATH": - str(Path(_USER_DIR).joinpath("data/sm_history.toml")), - "RULES_CONFIG_PATH": - str(Path(_USER_DIR).joinpath("settings/rules.toml")), - "TRANSFORMERS_CONFIG_PATH": - str(Path(_USER_DIR).joinpath("settings/transformers.toml")), - "HOOKS_CONFIG_PATH": - str(Path(_USER_DIR).joinpath("settings/hooks.toml")), - "COMPANION_CONFIG_PATH": - str(Path(_USER_DIR).joinpath("settings/companion_config.toml")), - "DLL_PATH": - str(Path(_BASE_PATH).joinpath("lib/dll/")), - "GDEF_FILE": - str(Path(_USER_DIR).joinpath("caster_user_content/transformers/words.txt")), - "LOG_PATH": - str(Path(_USER_DIR).joinpath("log.txt")), - "SAVED_CLIPBOARD_PATH": - str(Path(_USER_DIR).joinpath("data/clipboard.json")), - "SIKULI_SCRIPTS_PATH": - str(Path(_USER_DIR).joinpath("sikuli")), - "GIT_REPO_LOCAL_REMOTE_PATH": - str(Path(_USER_DIR).joinpath("settings/git_repo_local_to_remote_match.toml")), - "GIT_REPO_LOCAL_REMOTE_DEFAULT_PATH": - str(Path(_BASE_PATH).joinpath("bin/share/git_repo_local_to_remote_match.toml.defaults")), - - # REMOTE_DEBUGGER_PATH is the folder in which pydevd.py can be found - "REMOTE_DEBUGGER_PATH": - str(Path("")), - - # SIKULIX EXECUTABLES - "SIKULI_IDE": - str(Path("")), - "SIKULI_RUNNER": - str(Path("")), - - # EXECUTABLES - "AHK_PATH": - str(Path(_BASE_PATH).joinpath(ahk_path_default)), - "DOUGLAS_PATH": - str(Path(_BASE_PATH).joinpath("asynch/mouse/grids.py")), - "ENGINE_PATH": - _validate_engine_path(), - "HOMUNCULUS_PATH": - str(Path(_BASE_PATH).joinpath("asynch/hmc/h_launch.py")), - "HUD_PATH": - str(Path(_BASE_PATH).joinpath("asynch/hud.py")), - "LEGION_PATH": - str(Path(_BASE_PATH).joinpath("asynch/mouse/legion.py")), - "MEDIA_PATH": - str(Path(_BASE_PATH).joinpath("bin/media")), - "RAINBOW_PATH": - str(Path(_BASE_PATH).joinpath("asynch/mouse/grids.py")), - "REBOOT_PATH": - str(Path(_BASE_PATH).joinpath("bin/reboot.bat")), - "REBOOT_PATH_WSR": - str(Path(_BASE_PATH).joinpath("bin/reboot_wsr.bat")), - "SETTINGS_WINDOW_PATH": - str(Path(_BASE_PATH).joinpath("asynch/settingswindow.py")), - "SIKULI_SERVER_PATH": - str(Path(_BASE_PATH).joinpath("asynch/sikuli/server/xmlrpc_server.sikuli")), - "SUDOKU_PATH": - str(Path(_BASE_PATH).joinpath("asynch/mouse/grids.py")), - "WSR_PATH": - str(Path("C:/Windows/Speech/Common/sapisvr.exe")), - "TERMINAL_PATH": - str(Path(terminal_path_default)), - - # CCR - "CONFIGDEBUGTXT_PATH": - str(Path(_USER_DIR).joinpath("data/configdebug.txt")), - - # PYTHON - "PYTHONW": - SYSTEM_INFORMATION["hidden console binary"], - }, - - # Speech recognition engine settings - "engine": { - "default_engine_mode": False, - "engine_mode": "normal", - "default_mic": False, - "mic_mode": "on", - "mic_sleep_timer_on": True, - "mic_sleep_timer": 300, # Seconds before microphone goes to sleep after last successful recognition. - # Note: No greater than 5 minutes or 300 seconds unless DPI/DPI sleep settings are adjusted - }, - - # python settings - "python": { - "automatic_settings": - True, # Set to false to manually set "version" and "pip" below. - "version": - "python", # Depending Python setup (python, python2, python2.7, py, py -2) - "pip": "pip" # Depending on PIP setup (pip ,pip2, pip2.7) - }, - - # sikuli settings - "sikuli": { - "enabled": False, - "version": "" - }, - - # gitbash settings - "gitbash": { - "loading_time": 5, # the time to initialise the git bash window in seconds - "fetching_time": 3 # the time to fetch a github repository in seconds - }, - - # node rules path - "Tree_Node_Path": { - "SM_CSS_TREE_PATH": str(Path(_USER_DIR).joinpath("data/sm_css_tree.toml")), - }, - - "online": { - "online_mode": True, # False disables updates - "last_update_date": "None", - "update_interval": 7 # Days - }, - - # Default enabled hooks: Use hook class name - "hooks": { - "default_hooks": ['PrinterHook', 'RulesLoadedHook'], - }, - - # miscellaneous section - "miscellaneous": { - "dev_commands": True, - "keypress_wait": 50, # milliseconds - "max_ccr_repetitions": 16, - "atom_palette_wait": 30, # hundredths of a second - "print_rdescripts": True, - "history_playback_delay_secs": 1.0, - "legion_vertical_columns": 30, - "legion_downscale_factor": "auto", - "use_aenea": False, - "hmc": True, - "ccr_on": True, - "dragonfly_pause_default": 0.003, # dragonfly _pause_default 0.02 is too slow! Caster default 0.003 - }, - # Grammar reloading section - "grammar_reloading": { - "reload_trigger": "timer", # manual or timer - "reload_timer_seconds": 5, # seconds - }, - - "formats": { - "_default": { - "text_format": [5, 0], - "secondary_format": [1, 0], - }, - "C plus plus": { - "text_format": [3, 1], - "secondary_format": [2, 1], - }, - "C sharp": { - "text_format": [3, 1], - "secondary_format": [2, 1], - }, - "Dart": { - "text_format": [3, 1], - "secondary_format": [2, 1], - }, - "HTML": { - "text_format": [5, 0], - "secondary_format": [5, 2], - }, - "Java": { - "text_format": [3, 1], - "secondary_format": [2, 1], - }, - "Javascript": { - "text_format": [3, 1], - "secondary_format": [2, 1], - }, - "matlab": { - "text_format": [3, 1], - "secondary_format": [1, 3], - }, - "Python": { - "text_format": [5, 3], - "secondary_format": [2, 1], - }, - "Rust": { - "text_format": [5, 3], - "secondary_format": [2, 1], - }, - "sequel": { - "text_format": [5, 3], - "secondary_format": [1, 3], - }, - } - } - - -def settings(key_path, default_value=None): - """ - This should be the preferred way to use settings.SETTINGS, - a KeyError-safe function call to access the settings dict. - """ - dv = False if default_value is None else default_value - if SETTINGS is None: - return dv - value = SETTINGS - for k in key_path: - if k in value: - value = value[k] - else: - return dv - return value - - -def save_config(): - """ - Save the current in-memory settings to disk - """ - _save(SETTINGS, _SETTINGS_PATH) - - -def initialize(): - global SETTINGS, SYSTEM_INFORMATION - global _BASE_PATH, _USER_DIR, _SETTINGS_PATH - - if SETTINGS is not None: - return - - # calculate prerequisites - SYSTEM_INFORMATION = _get_platform_information() - _BASE_PATH = str(Path(__file__).resolve().parent.parent) - if os.getenv("CASTER_USER_DIR") is not None: - _USER_DIR = os.getenv("CASTER_USER_DIR") - else: - _USER_DIR = user_data_dir(appname="caster", appauthor=False) - _SETTINGS_PATH = str(Path(_USER_DIR).joinpath("settings/settings.toml")) - - # Kick everything off. - SETTINGS = _init(_SETTINGS_PATH) - from castervoice.lib.migration import UserDirUpdater - migrator = UserDirUpdater(_USER_DIR) - migrator.create_user_dir_directories() - migrator.update_user_dir_packages_to_v1_7_0() - migrator.update_bringme_toml_to_v1_7_0() - _debugger_path = SETTINGS["paths"]["REMOTE_DEBUGGER_PATH"] # pylint: disable=invalid-sequence-index - if _debugger_path not in sys.path and os.path.isdir(_debugger_path): - sys.path.append(_debugger_path) - - printer.out("Caster User Directory: {}".format(_USER_DIR)) diff --git a/castervoice/lib/temporary.py b/castervoice/lib/temporary.py deleted file mode 100644 index fbce5bea7..000000000 --- a/castervoice/lib/temporary.py +++ /dev/null @@ -1,71 +0,0 @@ -from dragonfly import ActionBase, Paste -from castervoice.lib import context -from castervoice.lib.actions import Text, Key -''' -Stores the currently highlighted text in a temporary variable, -to be Retrieved after some other action. If no text was -highlighted, an empty string will be stored. -Sample usage: -"find that": Store() + Key("c-f") + Retrieve() + Key("enter") - -In order to enable use with web URLs, Store() takes a string, -space, which will replace all space characters, and a bool, -remove_cr, which if true will remove any newlines in the -selection, to avoid them triggering the request early. -Sample usage: -"wikipedia that": - Store(space="+", remove_cr=True) + Key("c-t") + - Text("https://en.wikipedia.org/w/index.php?search=") + - Retrieve() + Key("enter") - -There are cases where you may want the same function to do -different things depending on whether or not text was highlighted. -The action_if_no_text and action_if_text arguments to Retrieve() -are calls to Key() and allow this. -For example, you may want to finish inside a set of brackets -if no text was highlighted, but outside if there was text. -Sample usage: -"insert bold text": - Store() + Text("\\textbf{}") + Key("left") + - Retrieve(action_if_text="right") - -NOTE: -If the highlighted text is the same as what is currently on the -clipboard, an empty string will be stored. This is a necessary -side-effect of being able to detect when no text is highlighted. -''' -_TEMP = "" - - -class Store(ActionBase): - def __init__(self, space=" ", remove_cr=False): - ActionBase.__init__(self) - self.space = space - self.remove_cr = remove_cr - - def _execute(self, data=None): - global _TEMP - _, orig = context.read_selected_without_altering_clipboard(False) - text = orig.replace(" ", self.space) if orig else "" - _TEMP = text.replace("\n", "") if self.remove_cr else text - return True - - -class Retrieve(ActionBase): - def __init__(self, action_if_no_text="", action_if_text=""): - ActionBase.__init__(self) - self.action_if_no_text = action_if_no_text - self.action_if_text = action_if_text - - @classmethod - def text(cls): - return _TEMP - - def _execute(self, data=None): - output = _TEMP - Paste(output).execute() - if output: - Key(self.action_if_text).execute() - else: - Key(self.action_if_no_text).execute() - return True diff --git a/castervoice/lib/terminal.py b/castervoice/lib/terminal.py deleted file mode 100644 index cb9767d3d..000000000 --- a/castervoice/lib/terminal.py +++ /dev/null @@ -1,40 +0,0 @@ -from dragonfly import RunCommand, Function -from castervoice.lib.merge.state.actions2 import ConfirmAction - -class TerminalCommand(RunCommand): - ''' - TerminalCommand executes trusted or un-trusted RunCommands for terminal or CMD. - Trusted commands not utilize Confirm Action to safeguard RunCommand execution. - - Example 1 - A trusted command - class PingLocalHost(TerminalCommand): - command = "ping localhost" - trusted = True - Ping().execute() - - Example 2 - A synchronous command - "update caster test": - R(TerminalCommand('python -m pip install --upgrade castervoice', synchronous=True), - rdescript="Core: Update"), - - ''' - trusted = False - def __init__(self, command=None, process_command=None, - synchronous=False, trusted=False): - # Pass arguments to RunCommand. - RunCommand.__init__(self, command, process_command, synchronous) - - # Allow setting 'trusted' at the class level. - if trusted: - self.trusted = trusted - - def execute(self, data=None): - if self.trusted: - return RunCommand.execute(self, data) - else: - return ConfirmAction( - Function(lambda: RunCommand.execute(self, data)), - rdescript="CasterTerminalCommand: Confirm Action '%s'?" % self.command, - instructions="Run command '%s'?" % self.command - ).execute(data) - diff --git a/castervoice/lib/text_utils.py b/castervoice/lib/text_utils.py deleted file mode 100644 index a5304d7cb..000000000 --- a/castervoice/lib/text_utils.py +++ /dev/null @@ -1,52 +0,0 @@ -import time - - -from castervoice.lib.actions import Key, Text -from castervoice.lib import settings, context - -def master_text_nav(mtn_mode, mtn_dir, nnavi500, extreme): - ''' - ( | []) [( | )] - mtn_mode: "shin" s, "queue" cs, "fly" c, (default None) - mtn_dir: 0-up, 1-down, 2-left, 3-right, (default right) - nnavi500: number of keypresses (default 1) - extreme: home/end (default None) - ''' - - k = None - if mtn_mode is None: - if extreme is not None: - if mtn_dir == "left": - k = "home" - elif mtn_dir == "right": - k = "end" - elif mtn_dir == "up": - k = "c-home" - elif mtn_dir == "down": - k = "c-end" - else: - k = str(mtn_dir) + "/5:" + str(nnavi500) - elif extreme is None: - k = str(mtn_mode) + "-" + str(mtn_dir) + "/5:" + str(nnavi500) - else: - mtn_dir = str(mtn_dir) - way = "end" if mtn_dir in ["right", "down"] else "home" - k = str(mtn_mode) + "-" + str(way) - Key(k).execute() - time.sleep(settings.SETTINGS["miscellaneous"]["keypress_wait"]/1000.) - - -def enclose_selected(enclosure): - ''' - Encloses selected text in the appropriate enclosures - By using the system Clipboard as a buffer ( doesn't delete previous contents) - ''' - - (err, selected_text) = context.read_selected_without_altering_clipboard(True) - if err == 0: - opener = enclosure.split('~')[0] - closer = enclosure.split('~')[1] - enclosed_text = opener + selected_text + closer - # Attempt to paste enclosed text without altering clipboard - if not context.paste_string_without_altering_clipboard(enclosed_text): - print("failed to paste {}".format(enclosed_text)) \ No newline at end of file diff --git a/castervoice/lib/textformat.py b/castervoice/lib/textformat.py deleted file mode 100644 index f98d42510..000000000 --- a/castervoice/lib/textformat.py +++ /dev/null @@ -1,155 +0,0 @@ -import re -from builtins import str - -from castervoice.lib import settings -from castervoice.lib.actions import Text - - -class TextFormat(): - ''' - Represents text formatting (capitalization and spacing) rules - - Commands for capitalization: - 1 yell - ALLCAPS - 2 tie - TitleCase - 3 Gerrish - camelCase - 4 sing - Sentencecase - 5 laws (default) - alllower - 6 say - whatever speech engine provides - 7 cop - Whatever speech engine provides, initial letter capitalized - 8 slip - whatever speech engine provides, initial letter lowercase - Commands for word spacing: - 0 (default except Gerrish) - words with spaces - 1 gum (default for Gerrish) - wordstogether - 2 spine - words-with-hyphens - 3 snake - words_with_underscores - 4 pebble - words.with.fullstops - 5 incline - words/with/slashes - 6 descent - words\with\backslashes - ''' - - @classmethod - def formatted_text(cls, capitalization, spacing, t): - if capitalization != 0: - if capitalization == 1: - t = t.upper() - elif capitalization == 2: - t = t.title() - # Python's built-in .title() treats apostrophes as word boundaries, - # incorrectly capitalizing contractions (e.g., "don't" becomes "Don'T"). - # This regex lowercases common contractions and possessives, while - # safely preserving proper names like "O'Reilly" or "D'Angelo". - # (?<=[a-zA-Z]) : Ensures a letter precedes the apostrophe. - # '(S|T|M|D|Re|Ve|Ll)\b : Matches the contraction at a word boundary. - t = re.sub(r"(?<=[a-zA-Z])'(S|T|M|D|Re|Ve|Ll)\b", lambda m: m.group(0).lower(), t) - elif capitalization == 3: - t = t.title() - t = re.sub(r"(?<=[a-zA-Z])'(S|T|M|D|Re|Ve|Ll)\b", lambda m: m.group(0).lower(), t) - t = t[0].lower() + t[1:] - elif capitalization == 4: - t = t.capitalize() - elif capitalization == 5: - t = t.lower() - elif capitalization == 6: - pass - elif capitalization == 7: - t = t[0].upper() + t[1:] - elif capitalization == 8: - t = t[0].lower() + t[1:] - if spacing != 0: - if spacing == 1: - t = "".join(t.split(" ")) - elif spacing == 2: - t = "-".join(t.split(" ")) - elif spacing == 3: - t = "_".join(t.split(" ")) - elif spacing == 4: - t = ".".join(t.split(" ")) - elif spacing == 5: - t = "/".join(t.split(" ")) - elif spacing == 6: - t = "\\".join(t.split(" ")) - return t - - @classmethod - def get_text_format_description(cls, capitalization, spacing): - caps = {0: "", 1: "yell", 2: "tie", 3: "gerrish", 4: "sing", 5: "laws", 6: "say", 7: "cop", 8: "slip"} - spaces = { - 0: "", - 1: "gum", - 2: "spine", - 3: "snake", - 4: "pebble", - 5: "incline", - 6: "descent" - } - if capitalization == 0 and spacing == 0: - return "" - else: - text = cls.formatted_text(capitalization, spacing, str("this is a test")) - return "%s %s (%s)" % (caps[capitalization], spaces[spacing], text) - - @classmethod - def normalize_text_format(cls, capitalization, spacing): - if capitalization == 0: - capitalization = 5 - if spacing == 0 and capitalization == 3: - spacing = 1 - return (capitalization, spacing) - - def __init__(self, default_cap, default_spacing): - self.default_cap = default_cap - self.default_spacing = default_spacing - self.capitalization = 0 - self.spacing = 0 - - def set_text_format(self, capitalization, spacing): - self.capitalization, self.spacing = self.normalize_text_format( - capitalization, spacing) - - def clear_text_format(self): - self.capitalization = self.default_cap - self.spacing = self.default_spacing - - def __str__(self): - return self.get_text_format_description(self.capitalization, self.spacing) - - def get_formatted_text(self, t): - return TextFormat.formatted_text(self.capitalization, self.spacing, t) - - -format = TextFormat(*settings.settings(["formats", "_default", "text_format"], default_value=[5, 0])) -secondary_format = TextFormat( - *settings.settings(["formats", "_default", "secondary_format"], default_value=[1, 0])) - - -def _choose_format(big): - return format if not big else secondary_format - - -# module interface -def set_text_format(big, capitalization, spacing): - _choose_format(big).set_text_format(capitalization, spacing) - - -def clear_text_format(big): - _choose_format(big).clear_text_format() - - -def peek_text_format(big): - print("Text formatting: %s" % str(_choose_format(big))) - - -def partial_format_text(big, word_limit, textnv): - Text( - _choose_format(big).get_formatted_text(" ".join( - str(textnv).split(" ")[0:word_limit]))).execute() - - -def prior_text_format(big, textnv): - Text(_choose_format(big).get_formatted_text(str(textnv))).execute() - - -def master_format_text(capitalization, spacing, textnv): - capitalization, spacing = TextFormat.normalize_text_format(capitalization, spacing) - Text(TextFormat.formatted_text(capitalization, spacing, str(textnv))).execute() diff --git a/castervoice/lib/util/__init__.py b/castervoice/lib/util/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/lib/util/bidi_graph.py b/castervoice/lib/util/bidi_graph.py deleted file mode 100644 index 54b332d57..000000000 --- a/castervoice/lib/util/bidi_graph.py +++ /dev/null @@ -1,28 +0,0 @@ -class BiDiGraph(object): - def __init__(self): - self._nodes = {} - - def add(self, *nodes): - """ - Adds nodes to the graph. All nodes in the added group are - assumed to be connected to each other. - - This structure is not thread safe and provides mutable access - to its substructures. - - :param nodes: a group of objects which are all hashable - """ - node_range = range(0, len(nodes)) - for i in node_range: - node = nodes[i] - if node not in self._nodes.keys(): - self._nodes[node] = set() - for k in node_range: - if i != k: - self._nodes[node].add(nodes[k]) - - def get_node(self, node): - return frozenset() if node not in self._nodes else self._nodes[node] - - def get_all_nodes(self): - return [(node, self._nodes[node]) for node in self._nodes] diff --git a/castervoice/lib/util/guidance.py b/castervoice/lib/util/guidance.py deleted file mode 100644 index 22cfde854..000000000 --- a/castervoice/lib/util/guidance.py +++ /dev/null @@ -1,7 +0,0 @@ -def offer(): - """ - This is here to make unit tests fail when code is - contributed which would make unit tests write files. - Do not delete it unless you understand the consequences. - """ - pass diff --git a/castervoice/lib/util/hashable_list.py b/castervoice/lib/util/hashable_list.py deleted file mode 100644 index f7d904a4a..000000000 --- a/castervoice/lib/util/hashable_list.py +++ /dev/null @@ -1,31 +0,0 @@ -class HashableList(object): - """ - A structure that stores a list of str()-able items, - but can also be used as a key in a dict. - - This is not a very good general purpose data structure. - It has a very specific use in DetailsCompatibilityChecker. - """ - def __init__(self, delimiter=","): - self._str_representation = "" - self._list_representation = [] - self._delimiter = delimiter - - def add(self, item): - self._str_representation += str(item) + self._delimiter - self._list_representation.append(item) - - def get_string(self): - return self._str_representation - - def get_list(self): - return list(self._list_representation) - - def __len__(self): - return len(self._list_representation) - - def __hash__(self): - return hash(self._str_representation) - - def __eq__(self, other): - return self.get_string() == other.get_string() diff --git a/castervoice/lib/util/ordered_set.py b/castervoice/lib/util/ordered_set.py deleted file mode 100644 index b46514177..000000000 --- a/castervoice/lib/util/ordered_set.py +++ /dev/null @@ -1,34 +0,0 @@ -class OrderedSet(object): - - def __init__(self, collection=[]): - self._list = list(collection) - self._set = set(collection) - - def add(self, item): - if item not in self._set: - self._list.append(item) - self._set.add(item) - - def add_all(self, collection): - [self.add(item) for item in collection] - - def remove(self, item): - if item in self._set: - self._list.remove(item) - self._set.remove(item) - - def remove_all(self, collection): - [self.remove(item) for item in collection] - - def update(self, item, add=True): - """ Helps avoid ternaries. """ - if add: - self.add(item) - else: - self.remove(item) - - def to_set(self): - return set(self._set) - - def to_list(self): - return list(self._list) diff --git a/castervoice/lib/util/recognition_history.py b/castervoice/lib/util/recognition_history.py deleted file mode 100644 index 11d53df9a..000000000 --- a/castervoice/lib/util/recognition_history.py +++ /dev/null @@ -1,7 +0,0 @@ -from dragonfly import RecognitionHistory - - -def get_and_register_history(utterances=10): - history = RecognitionHistory(utterances) - history.register() - return history diff --git a/castervoice/lib/utilities.py b/castervoice/lib/utilities.py deleted file mode 100644 index 6b7f00533..000000000 --- a/castervoice/lib/utilities.py +++ /dev/null @@ -1,405 +0,0 @@ -import io -import json -import os -import json -import re -import subprocess -import sys -import six -import time -import traceback -import webbrowser -from locale import getpreferredencoding -from pathlib import Path -from urllib.parse import unquote - -import tomlkit -from castervoice.lib.clipboard import Clipboard -from castervoice.lib.util import guidance -from castervoice.asynch import hud_support -from dragonfly import Key, Window, get_current_engine - -try: # Style C -- may be imported into Caster, or externally - BASE_PATH = str(Path(__file__).resolve().parent.parent) - if BASE_PATH not in sys.path: - sys.path.append(BASE_PATH) -finally: - from castervoice.lib import printer, settings - -DARWIN = sys.platform.startswith('darwin') -LINUX = sys.platform.startswith('linux') -WIN32 = sys.platform.startswith('win') - -lasthandle = None - - -# TODO: Move functions that manipulate or retrieve information from Windows to `window_mgmt_support` in navigation_rules. -# TODO: Implement Optional exact title matching for `get_matching_windows` in Dragonfly -def window_exists(windowname=None, executable=None): - return Window.get_matching_windows(title=windowname, executable=executable) and True - - -def get_window_by_title(title=None): - # returns 0 if nothing found - Matches = Window.get_matching_windows(title=title) - if Matches: - return Matches[0].handle - else: - return 0 - - -def get_active_window_title(): - return Window.get_foreground().title - - -def get_active_window_path(): - return Window.get_foreground().executable - - -def get_active_window_info(): - '''Returns foreground window executable_file, executable_path, title, handle, classname''' - FILENAME_PATTERN = re.compile(r"[/\\]([\w_ ]+\.[\w]+)") - window = Window.get_foreground() - executable_path = str(Path(get_active_window_path())) - match_object = FILENAME_PATTERN.findall(window.executable) - executable_file = None - if len(match_object) > 0: - executable_file = match_object[0] - return [executable_file, executable_path, window.title, window.handle, window.classname] - - -def maximize_window(): - ''' - Maximize foreground Window - ''' - Window.get_foreground().maximize() - - -def minimize_window(): - ''' - Minimize foreground Window - ''' - global lasthandle - lasthandle = Window.get_foreground() - Window.get_foreground().minimize() - - -def close_window(): - ''' - Close foreground Window - ''' - Window.get_foreground().close() - - -def restore_window(): - ''' - Restores last minimized window triggered minimize_window. - ''' - global lasthandle - if lasthandle is None: - printer.out("No previous window minimized by voice") - else: - Window.restore(lasthandle) - - -def save_toml_file(data, path): - guidance.offer() - try: - formatted_data = str(tomlkit.dumps(data)) - with io.open(path, "wt", encoding="utf-8") as f: - f.write(formatted_data) - except Exception: - simple_log(True) - - -def load_toml_file(path): - guidance.offer() - result = {} - try: - with io.open(path, "rt", encoding="utf-8") as f: - result = tomlkit.loads(f.read()).value - except IOError as e: - if e.errno == 2: # The file doesn't exist. - save_toml_file(result, path) - else: - raise - except Exception: - simple_log(True) - return result - - -def save_json_file(data, path): - guidance.offer() - try: - formatted_data = str(json.dumps(data, ensure_ascii=False)) - with io.open(path, "wt", encoding="utf-8") as f: - f.write(formatted_data) - except Exception: - simple_log(True) - - -def load_json_file(path): - guidance.offer() - result = {} - try: - with io.open(path, "rt", encoding="utf-8") as json_file: - result = json.load(json_file) - except IOError as e: - if e.errno == 2: # The file doesn't exist. - save_json_file(result, path) - else: - raise - except Exception: - simple_log(True) - return result - - -def list_to_string(l): - return u"\n".join([str(x) for x in l]) - - -def simple_log(to_file=False): - msg = list_to_string(sys.exc_info()) - printer.out(msg) - for tb in traceback.format_tb(sys.exc_info()[2]): - printer.out(tb) - if to_file: - with io.open(settings.SETTINGS["paths"]["LOG_PATH"], 'at', encoding="utf-8") as f: - f.write(msg + "\n") - - -def remote_debug(who_called_it=None): - if who_called_it is None: - who_called_it = "An unidentified process" - try: - import pydevd # @UnresolvedImport pylint: disable=import-error - pydevd.settrace() - except Exception: - printer.out("ERROR: " + who_called_it + - " called utilities.remote_debug() but the debug server wasn't running.") - - -def reboot(): - # TODO: Save engine arguments elsewhere and retrieves for reboot. Allows for user-defined arguments. - popen_parameters = [] - engine = get_current_engine() - if engine.name == 'kaldi': - engine.disconnect() - subprocess.Popen([sys.executable, '-m', 'dragonfly', 'load', '_*.py', '--engine', 'kaldi', '--no-recobs-messages']) - if engine.name == 'sapi5inproc': - engine.disconnect() - subprocess.Popen([sys.executable, '-m', 'dragonfly', 'load', '--engine', 'sapi5inproc', '_*.py', '--no-recobs-messages']) - if engine.name in ["sapi5shared", "sapi5"]: - popen_parameters.append(settings.SETTINGS["paths"]["REBOOT_PATH_WSR"]) - popen_parameters.append(settings.SETTINGS["paths"]["WSR_PATH"]) - printer.out(popen_parameters) - subprocess.Popen(popen_parameters) - if engine.name == 'natlink': - from natlinkcore import natlinkstatus # pylint: disable=import-error - status = natlinkstatus.NatlinkStatus() - if status.NatlinkIsEnabled() == 1: - # Natlink in-process - popen_parameters.append(settings.SETTINGS["paths"]["REBOOT_PATH"]) - popen_parameters.append(settings.SETTINGS["paths"]["ENGINE_PATH"]) - username = status.getUserName() - popen_parameters.append(username) - printer.out(popen_parameters) - subprocess.Popen(popen_parameters) - else: - # Natlink out-of-process - engine.disconnect() - subprocess.Popen([sys.executable, '-m', 'dragonfly', 'load', '--engine', 'natlink', '_*.py', '--no-recobs-messages']) - hud_support.clear_hud() - - -def default_browser_command(): - if WIN32: - from winreg import ( # pylint: disable=import-error,no-name-in-module - HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, CloseKey, - ConnectRegistry, OpenKey, QueryValueEx) - ''' - Tries to get default browser command, returns either a space delimited - command string with '%1' as URL placeholder, or empty string. - ''' - browser_class = 'Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\https\\UserChoice' - try: - reg = ConnectRegistry(None,HKEY_CURRENT_USER) - key = OpenKey(reg, browser_class) - value, t = QueryValueEx(key, 'ProgId') - CloseKey(key) - CloseKey(reg) - reg = ConnectRegistry(None,HKEY_CLASSES_ROOT) - key = OpenKey(reg, '%s\\shell\\open\\command' % value) - path, t = QueryValueEx(key, None) - except WindowsError: # pylint: disable=undefined-variable - # logger.warn(e) - traceback.print_exc() - return '' - finally: - CloseKey(key) - CloseKey(reg) - return path - else: - default_browser = webbrowser.get() - return default_browser.name + " %1" - -def clear_log(): - # Function to clear status window. - # Natlink status window not used in out-of-process mode. - # TODO: window_exists utilized when engine launched through Dragonfly CLI via bat in future - try: - window_title = "Caster: Status Window" - if WIN32: - clearcmd = "cls" # Windows OS - else: - clearcmd = "clear" # Linux - if get_current_engine().name == 'natlink': - from natlinkcore import natlinkstatus # pylint: disable=import-error - status = natlinkstatus.NatlinkStatus() - if status.NatlinkIsEnabled() == 1: - window_title = "Messages from Natlink" - import win32gui # pylint: disable=import-error - handle = get_window_by_title("Messages from Python Macros") - if not handle: - handle = get_window_by_title(window_title) - if handle: - rt_handle = win32gui.FindWindowEx(handle, None, "RICHEDIT", None) - if rt_handle: - win32gui.SetWindowText(rt_handle, "") - else: - if window_exists(windowname=window_title): - os.system(clearcmd) - else: - if window_exists(windowname=window_title): - os.system(clearcmd) - else: - printer.out("clear_log: Not implemented with GUI") - except Exception as e: - printer.out(e) - - -# TODO: BringMe - Implement clipboard formats for Mac -def get_clipboard_formats(): - ''' - Return list of all data formats currently in the clipboard - ''' - formats = [] - if LINUX: - encoding = getpreferredencoding() - com = ["xclip", "-o", "-t", "TARGETS"] - try: - p = subprocess.Popen(com, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - stdin=subprocess.PIPE, - ) - for line in iter(p.stdout.readline, b''): - if isinstance(line, str): - line = line.decode(encoding) - formats.append(line.strip()) - except Exception as e: - print( - "Exception from starting subprocess {0}: " "{1}".format(com, e)) - - if WIN32: - import win32clipboard # pylint: disable=import-error - f = win32clipboard.EnumClipboardFormats(0) - while f: - formats.append(f) - f = win32clipboard.EnumClipboardFormats(f) - - if not formats: - print("get_clipboard_formats: Formats {} were not available for clipboard contents".format(formats)) - else: - return formats - - -def get_selected_files(folders=False): - ''' - Copy selected (text or file is subsequently of interest) to a fresh clipboard - ''' - if WIN32 or LINUX: - cb = Clipboard(from_system=True) - cb.clear_clipboard() - Key("c-c").execute() - time.sleep(0.1) - files = get_clipboard_files(folders) - cb.copy_to_system() - return files - else: - printer.out("get_selected_files: Not implemented for OS") - - -def enum_files_from_clipboard(target): - ''' - Generates absolute paths from clipboard - Returns unverified absolute file/dir paths based on defined mime type - ''' - paths = [] - if LINUX: - encoding = getpreferredencoding() - com = ["xclip", "-selection", "clipboard", "-o", target] - try: - p = subprocess.Popen(com, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - stdin=subprocess.PIPE, - ) - for line in iter(p.stdout.readline, b''): - if isinstance(line, str): - line = line.decode(encoding).strip() - if line.startswith("file://"): - line = line.replace("file://", "") - paths.append(unquote(line)) - return paths - except Exception as e: - print( - "Exception from starting subprocess {0}: " "{1}".format(com, e)) - - -def get_clipboard_files(folders=False): - ''' - Enumerate clipboard content and return files/folders either directly copied or - highlighted path copied - ''' - files = None - if WIN32: - import win32clipboard # pylint: disable=import-error - win32clipboard.OpenClipboard() - f = get_clipboard_formats() - try: - if win32clipboard.CF_HDROP in f: - files = win32clipboard.GetClipboardData(win32clipboard.CF_HDROP) - elif win32clipboard.CF_UNICODETEXT in f: - files = [win32clipboard.GetClipboardData( - win32clipboard.CF_UNICODETEXT)] - elif win32clipboard.CF_TEXT in f: - files = [win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)] - elif win32clipboard.CF_OEMTEXT in f: - files = [win32clipboard.GetClipboardData( - win32clipboard.CF_OEMTEXT)] - if folders: - files = [f for f in files if os.path.isdir(f)] if files else None - else: - files = [f for f in files if os.path.isfile(f)] if files else None - win32clipboard.CloseClipboard() - return files - except Exception as e: - win32clipboard.CloseClipboard() - printer.out(e) - - if LINUX: - f = get_clipboard_formats() - if "UTF8_STRING" in f: - files = enum_files_from_clipboard("UTF8_STRING") - elif "TEXT" in f: - files = enum_files_from_clipboard("TEXT") - elif "text/plain" in f: - files = enum_files_from_clipboard("text/plain") - if folders: - files = [f for f in files if os.path.isdir( - str(f))] if files else None - else: - files = [f for f in files if os.path.isfile( - str(f))] if files else None - return files diff --git a/castervoice/lib/version.py b/castervoice/lib/version.py deleted file mode 100644 index 16c83d88b..000000000 --- a/castervoice/lib/version.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "1.7.0" \ No newline at end of file diff --git a/castervoice/lib/virtual_desktops.py b/castervoice/lib/virtual_desktops.py deleted file mode 100644 index 68ad0fb9b..000000000 --- a/castervoice/lib/virtual_desktops.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys - -if sys.platform == "win32": - from .windows_virtual_desktops import go_to_desktop_number - from .windows_virtual_desktops import move_current_window_to_desktop - from .windows_virtual_desktops import close_all_workspaces -else: - def go_to_desktop_number(n): - print("Virtual desktop commands are not implemented on this platform") - - def move_current_window_to_desktop(n=1, follow=False): - print("Virtual desktop commands are not implemented on this platform") - - def close_all_workspaces(): - print("Virtual desktop commands are not implemented on this platform") diff --git a/castervoice/lib/windows_virtual_desktops.py b/castervoice/lib/windows_virtual_desktops.py deleted file mode 100644 index 3e5e5230b..000000000 --- a/castervoice/lib/windows_virtual_desktops.py +++ /dev/null @@ -1,31 +0,0 @@ -from dragonfly import Window, Key -from ctypes import windll - -# https://github.com/mirober/pyvda -try: - from pyvda import VirtualDesktop, AppView, get_virtual_desktops # pylint: disable=import-error -except Exception as e: - # This could fail on linux or windows <10 - print("Importing package pyvda failed with exception %s" % str(e)) - -ASFW_ANY = -1 - -def go_to_desktop_number(n): - # Helps make sure that the target desktop gets focus - windll.user32.AllowSetForegroundWindow(ASFW_ANY) - VirtualDesktop(n).go() - -def move_current_window_to_desktop(n=1, follow=False): - hwnd = Window.get_foreground().handle - AppView(hwnd).move(VirtualDesktop(n)) - if follow: - go_to_desktop_number(n) - -def close_all_workspaces(): - desktops = get_virtual_desktops() - total = len(desktops) - if total <= 1: - print("Only one desktop exists; nothing to close.") - return - go_to_desktop_number(total - 1) - Key("wc-f4/10:" + str(total - 1)).execute() diff --git a/castervoice/rules/__init__.py b/castervoice/rules/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/rules/apps/__init__.py b/castervoice/rules/apps/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/rules/apps/atlassian/__init__.py b/castervoice/rules/apps/atlassian/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/rules/apps/atlassian/jira.py b/castervoice/rules/apps/atlassian/jira.py deleted file mode 100644 index 52edca5fe..000000000 --- a/castervoice/rules/apps/atlassian/jira.py +++ /dev/null @@ -1,91 +0,0 @@ -from dragonfly import ShortIntegerRef -from castervoice.lib.actions import Key, Text -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R -from dragonfly import AppContext, Dictation, Function, MappingRule, Pause, Repeat -from dragonfly.actions import ContextAction - -class JiraRule(MappingRule): - - mapping = { - # Global Shortcuts - "go to dashboards": - R(Key("g") + Key("d")), - "go to projects": - R(Key("g") + Key("p")), - "go to boards": - R(Key("g") + Key("a")), - "go to issues": - R(Key("g") + Key("i")), - # This requires a plugin - "go to tempo [teams]": - R(Key("g") + Key("t")), - # This requires a plugin - "go to portfolio": - R(Key("p") + Key("v")), - "quick search": - R(Key("slash")), - "create issue": - R(Key("c")), - "submit [form]": - R(Key('as-s')), - - # Navigating Issues - "view issue": - R(Key("o")), - "next (issue | item) []": - R(Key("j"))*Repeat(extra="nnavi10"), - "previous (issue | item) []": - R(Key("k"))*Repeat(extra="nnavi10"), - - # Issue Actions - "edit issue": - R(Key("e")), - - "(action | actions)": - R(Key(".")), - # Opens the action menu and attempts the given action. If the action does not exist the menu remains open. - # Depending on the context the verb "edit" is more natural - "(action | edit) ": - R(Key(".") + Pause("20") + Text("%(action)s") + Pause("20") + Key("enter")), - - # JIRA contains dedicated hotkeys for some operations. However, the above action command makes them redundant. - # - assign issue - # - comment issue - # - edit issue labels - # - log time - # - assign to me - "share issue": - R(Key("s")), - - # Board Shortcuts - "go to backlog": - R(Key("1")), - "go to sprint": - R(Key("2")), - "go to reports": - R(Key("3")), - "toggle details": - R(Key("t")), - "toggle presentation [mode]": - R(Key("z")), - "toggle swim lanes": - R(Key("minus")), - "send to top": - R(Key("s") + Key("t")), - "send to bottom": - R(Key("s") + Key("b")), - } - - exported = True - extras = [ - ShortIntegerRef("nnavi10", 1, 11), - Dictation("action"), - ] - defaults = { - "nnavi10": 1, - "action": "", - } - -def get_rule(): - return JiraRule, RuleDetails(name="Jira", executable=["chrome", "firefox"]) diff --git a/castervoice/rules/apps/browser/__init__.py b/castervoice/rules/apps/browser/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/rules/apps/browser/chrome.py b/castervoice/rules/apps/browser/chrome.py deleted file mode 100644 index 7ea3b6363..000000000 --- a/castervoice/rules/apps/browser/chrome.py +++ /dev/null @@ -1,142 +0,0 @@ -from dragonfly import Repeat, Pause, Function, Choice, MappingRule, ShortIntegerRef - -from castervoice.lib.actions import Key, Mouse, Text - -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - -from castervoice.lib import github_automation -from castervoice.lib.temporary import Store, Retrieve - -class ChromeRule(MappingRule): - mapping = { - "(new window|win new)": - R(Key("c-n")), - "(new incognito window | incognito)": - R(Key("cs-n")), - "new tab []|tab new []": - R(Key("c-t") * Repeat(extra="n")), - "reopen tab []|tab reopen []": - R(Key("cs-t")) * Repeat(extra="n"), - "close tab []|tab close []": - R(Key("c-w")) * Repeat(extra='n'), - "win close|close all tabs": - R(Key("cs-w")), - "(next|forward) tab []|tab (right|sauce) []": - R(Key("c-tab")) * Repeat(extra="n"), - "(back|previous) tab []|tab (left|lease) []": - R(Key("cs-tab")) * Repeat(extra="n"), - "new tab that": - R(Mouse("middle") + Pause("20") + Key("c-tab")), - "go (back|prev|prior|previous) []": - R(Key("a-left/20")) * Repeat(extra="n"), - "go (next|forward) []": - R(Key("a-right/20")) * Repeat(extra="n"), - "zoom in []": - R(Key("c-plus/20")) * Repeat(extra="n"), - "zoom out []": - R(Key("c-minus/20")) * Repeat(extra="n"), - "zoom reset": - R(Key("c-0")), - "(hard refresh|super refresh)": - R(Key("c-f5")), - "find (next|forward) [match] []": - R(Key("c-g/20")) * Repeat(extra="n"), - "find (back|prev|prior|previous) [match] []": - R(Key("cs-g/20")) * Repeat(extra="n"), - # requires an extension in some browsers such as chrome - "[toggle] caret browsing": - R(Key("f7")), - "[go] home [page]": - R(Key("a-home")), - "[show] history": - R(Key("c-h")), - "address bar": - R(Key("c-l")), - "[show] downloads": - R(Key("c-j")), - "[add] bookmark": - R(Key("c-d")), - "bookmark all [tabs]": - R(Key("cs-d")), - "[show] bookmarks": - R(Key("cs-o")), - "[toggle] full screen": - R(Key("f11")), - "(show|view) page source": - R(Key("c-u")), - "resume": - R(Key("f8")), - "step over": - R(Key("f10")), - "step into": - R(Key("f11")), - "step out": - R(Key("s-f11")), - "(duplicate tab|tab duple)": - R(Key("a-d,a-c,c-t/15,c-v/15, enter")), - "(duplicate window|win duple)": - R(Key("a-d,a-c,c-n/15,c-v/15, enter")), - "[show] (menu | three dots)": - R(Key("a-f")), - "[show] settings": - R(Key("a-f/5, s")), - "[show chrome] task manager": - R(Key("s-escape")), - "(clear history|clear browsing data)": - R(Key("cs-del")), - "[show] developer tools": - R(Key("cs-i")), - "checkout [this] pull request [locally]": - R(Function(github_automation.github_checkoutupdate_pull_request, new=True)), - "update [this] pull request [locally]": - R(Function(github_automation.github_checkoutupdate_pull_request, new=False)), - "IRC identify": - R(Text("/msg NickServ identify PASSWORD")), - "tab | tab": - R(Key("c-%(m)s%(nth)s")), - "last tab": - R(Key("c-9")), - "second last tab": - R(Key("c-9, cs-tab")), - "switch focus []": - R(Key("f6/20")) * Repeat(extra="n"), - "[toggle] bookmark bar": - R(Key("cs-b")), - "switch user": - R(Key("cs-m")), - "focus notification": - R(Key("a-n")), - "allow notification": - R(Key("as-a")), - "deny notification": - R(Key("as-a")), - "google that": - R(Store(remove_cr=True) + Key("c-t") + Retrieve() + Key("enter")), - "wikipedia that": - R(Store(space="+", remove_cr=True) + Key("c-t") + Text( - "https://en.wikipedia.org/w/index.php?search=") + Retrieve() + Key("enter")), - "[show] (extensions|plugins)": - R(Key("a-f/20, l, e/15, enter")), - "more tools": - R(Key("a-f/5, l")), - } - extras = [ - Choice("nth", { - "first": "1", - "second": "2", - "third": "3", - "fourth": "4", - "fifth": "5", - "sixth": "6", - "seventh": "7", - "eighth": "8", - }), - ShortIntegerRef("n", 1, 100), - ShortIntegerRef("m", 1, 10) - ] - defaults = {"n": 1, "m":"", "nth": ""} - - -def get_rule(): - return ChromeRule, RuleDetails(name="google chrome", executable="chrome") diff --git a/castervoice/rules/apps/browser/firefox.py b/castervoice/rules/apps/browser/firefox.py deleted file mode 100644 index 055bdefc0..000000000 --- a/castervoice/rules/apps/browser/firefox.py +++ /dev/null @@ -1,120 +0,0 @@ -from dragonfly import Repeat, Pause, Function, Choice, MappingRule, ShortIntegerRef - -from castervoice.lib.actions import Key, Mouse, Text - -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - -from castervoice.lib import github_automation -from castervoice.lib.temporary import Store, Retrieve - -class FirefoxRule(MappingRule): - mapping = { - "(new window|win new)": - R(Key("c-n")), - "(new incognito window | incognito)": - R(Key("cs-n")), - "new tab []|tab new []": - R(Key("c-t") * Repeat(extra="n")), - "reopen tab []|tab reopen []": - R(Key("cs-t")) * Repeat(extra="n"), - "close tab []|tab close []": - R(Key("c-w")) * Repeat(extra='n'), - "win close|close all tabs": - R(Key("cs-w")), - "(next|forward) tab []|tab (right|sauce) []": - R(Key("c-tab")) * Repeat(extra="n"), - "(back|previous) tab []|tab (left|lease) []": - # control shift tab doesn't work and this appears to be an undocumented workaround - R(Key("c-tab/30")) * Repeat(extra="n"), - "new tab that": - R(Mouse("middle") + Pause("20") + Key("c-tab")), - "go (back|prev|prior|previous) []": - R(Key("a-left/20")) * Repeat(extra="n"), - "go (next|forward) []": - R(Key("a-right/20")) * Repeat(extra="n"), - "zoom in []": - R(Key("c-plus/20")) * Repeat(extra="n"), - "zoom out []": - R(Key("c-minus/20")) * Repeat(extra="n"), - "zoom reset": - R(Key("c-0")), - "(hard refresh|super refresh)": - R(Key("c-f5")), - "find (next|forward) [match] []": - R(Key("c-g/20")) * Repeat(extra="n"), - # requires an extension in some browsers such as chrome - "[toggle] caret browsing": - R(Key("f7")), - "[go] home [page]": - R(Key("a-home")), - "[show] history": - R(Key("c-h")), - "address bar": - R(Key("c-l")), - "[show] downloads": - R(Key("c-j")), - "[add] bookmark": - R(Key("c-d")), - "bookmark all [tabs]": - R(Key("cs-d")), - "[show] bookmarks": - R(Key("cs-o")), - "[toggle] full screen": - R(Key("f11")), - "(show|view) page source": - R(Key("c-u")), - "resume": - R(Key("f8")), - "step over": - R(Key("f10")), - "step into": - R(Key("f11")), - "step out": - R(Key("s-f11")), - "(duplicate tab|tab duple)": - R(Key("a-d,a-c,c-t/15,c-v/15, enter")), - "(duplicate window|win duple)": - R(Key("a-d,a-c,c-n/15,c-v/15, enter")), - "[show] (menu | three dots)": - R(Key("a-f")), - "[show] settings": - R(Key("a-f/5, s")), - "(clear history|clear browsing data)": - R(Key("cs-del")), - "[show] developer tools": - R(Key("cs-i")), - "checkout [this] pull request [locally]": - R(Function(github_automation.github_checkoutupdate_pull_request, new=True)), - "update [this] pull request [locally]": - R(Function(github_automation.github_checkoutupdate_pull_request, new=False)), - "IRC identify": - R(Text("/msg NickServ identify PASSWORD")), - "[toggle] bookmark bar": - R(Key("c-b")), - "[show] (extensions|plugins)": - R(Key("a-a, l, e/15, enter")), - "google that": - R(Store(remove_cr=True) + Key("c-t") + Retrieve() + Key("enter")), - "wikipedia that": - R(Store(space="+", remove_cr=True) + Key("c-t") + Text( - "https://en.wikipedia.org/w/index.php?search=") + Retrieve() + Key("enter")), - } - extras = [ - Choice("nth", { - "first": "1", - "second": "2", - "third": "3", - "fourth": "4", - "fifth": "5", - "sixth": "6", - "seventh": "7", - "eighth": "8", - }), - ShortIntegerRef("n", 1, 100), - ShortIntegerRef("m", 1, 10) - ] - defaults = {"n": 1, "m":"", "nth": ""} - -def get_rule(): - return FirefoxRule, RuleDetails(name="fire fox", executable="firefox") diff --git a/castervoice/rules/apps/chat/MSTeamsRule.py b/castervoice/rules/apps/chat/MSTeamsRule.py deleted file mode 100644 index 75e9baf74..000000000 --- a/castervoice/rules/apps/chat/MSTeamsRule.py +++ /dev/null @@ -1,119 +0,0 @@ -from dragonfly import ShortIntegerRef -from castervoice.lib.actions import Key, Text, Mouse -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R -from dragonfly import (AppContext, Choice, Dictation, Function, MappingRule, - Repeat) - -class MSTeamsRule(MappingRule): - name = "microsoft teams" - mapping = { - # General - "search": - R(Key("c-e")), - "keyboard shortcuts": - R(Key("c-.")), - "settings": - R(Key("c-comma")), - "help": - R(Key("f1")), - "commands": - R(Key("c-slash")), - "filter": - R(Key("cs-f")), - "go to": - R(Key("c-g")), - "new chat": - R(Key("c-n")), - - # Navigation - "activity": - R(Key("c-1")), - "chat": - R(Key("c-2")), - "teams": - R(Key("c-3")), - "calendar": - R(Key("c-4")), - "calls": - R(Key("c-5")), - "files": - R(Key("c-6")), - "shifts": - R(Key("c-7")), - "previous item []": - R(Key("a-up"))*Repeat(extra="nnavi10"), - "next item []": - R(Key("a-down"))*Repeat(extra="nnavi10"), - "previous team": - R(Key("cs-up")), - "next team": - R(Key("cs-down")), - "previous section": - R(Key("cs-f6")), - "next section": - R(Key("c-f6")), - - # Messaging - "focus compose": - R(Key("c")), - "expand compose": - R(Key("cs-x")), - "send": - R(Key("c-enter")), - "attach": - R(Key("c-o")), - "new-line": - R(Key("s-enter")), - "reply": - R(Key("r")), - - # meetings calls and calendar - "Accept [video] call": - R(Key("cs-a")), - "Accept [audio] call": - R(Key("cs-s")), - "decline [call]": - R(Key("cs-d")), - "start audio call": - R(Key("cs-c")), - "Start video call": - R(Key("cs-u")), - "toggle mute": - R(Key("cs-m")), - "screen share": - R(Key("cs-e")), - "toggle video": - R(Key("cs-o")), - "sharing toolbar": - R(Key("cs-space")), - "decline screen share": - R(Key("cs-d")), - "Accept screen share": - R(Key("cs-a")), - "Schedule meeting": - R(Key("as-n")), - "go to current time": - R(Key("a-.")), - "go to previous (day | week)": - R(Key("ca-left")), - "go to next (day | week)": - R(Key("ca-right")), - "View day": - R(Key("ca-1")), - "View workweek": - R(Key("ca-2")), - "View week": - R(Key("ca-3")), - } - exported = True - extras = [ - ShortIntegerRef("nnavi10", 1, 11) - ] - defaults = { - "nnavi10": 1 - } - - -def get_rule(): - return MSTeamsRule, RuleDetails(name="Microsoft Teams", executable="teams") diff --git a/castervoice/rules/apps/chat/__init__.py b/castervoice/rules/apps/chat/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/rules/apps/chat/gitter.py b/castervoice/rules/apps/chat/gitter.py deleted file mode 100644 index 1f981f2be..000000000 --- a/castervoice/rules/apps/chat/gitter.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -__author__ = 'LexiconCode' -Command-module for Gitter -Official Site "https://gitter.im/" -""" -from dragonfly import Pause, Choice, MappingRule - -from castervoice.lib.actions import Key, Text - -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R -from castervoice.lib.temporary import Store, Retrieve - - -class GitterRule(MappingRule): - mapping = { - "bold": - R(Store() + Text("****") + Key("left:2") + - Retrieve(action_if_text="right:2")), - "emphasize": - R(Store() + Text("**") + Key("left") + Retrieve(action_if_text="right")), - "strike through": - R(Store() + Text("~~~~") + Key("left:2") + - Retrieve(action_if_text="right:2")), - "latex": - R(Store() + Text("$$$$") + Key("left:2") + - Retrieve(action_if_text="right:2")), - " header": - R(Store() + Text("%(header_size)s ") + Retrieve(action_if_text="s-enter")), - "insert item": - R(Store() + Text("*") + Key("space") + Retrieve(action_if_text="s-enter")), - "block quote": - R(Store() + Text(">") + Key("space") + Retrieve(action_if_text="s-enter")), - "mention": - R(Store() + Text("@") + Retrieve(action_if_text="right, space")), - "insert link": - R(Store() + Text("[]()") + Key("left:3") + - Retrieve(action_if_text="right:2")), - "insert image": - R(Store() + Text("![]()") + Key("left:3") + - Retrieve(action_if_text="right:2")), - "insert code": - R(Store() + Text("``") + Key("left") + Retrieve(action_if_text="right")), - "formatted code": - R(Store() + Text("``````") + Pause("0.5") + Key("left:3,s-enter:2,up") + - Retrieve()), - } - extras = [ - Choice("header_size", { - "small": "###", - "medium": "##", - "large": "#", - }), - ] - Defaults = {} - - -def get_rule(): - return GitterRule, RuleDetails(name="Gitter", executable="gitter") diff --git a/castervoice/rules/apps/chat/webexteams.py b/castervoice/rules/apps/chat/webexteams.py deleted file mode 100644 index 6d3a9cd05..000000000 --- a/castervoice/rules/apps/chat/webexteams.py +++ /dev/null @@ -1,114 +0,0 @@ -from dragonfly import ShortIntegerRef -from castervoice.lib.actions import Key, Text -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R -from dragonfly import (Dictation, MappingRule, Repeat) - -class WebexTeamsRule(MappingRule): - # See https://help.webex.com/en-us/7wr87q/Keyboard-Navigation-and-Shortcuts-for-Cisco-Webex-Teams - mapping = { - # Navigation - Primary - "show spaces": - R(Key("c-1")), - "show teams": - R(Key("c-2")), - "show calls": - R(Key("c-3")), - "show meetings": - R(Key("c-4")), - "help": - R(Key("f1")), - "create space": - R(Key("cs-n")), - "contact person []": - R(Key("c-n") + Text("%(person)s")), - "(search | find)": - R(Key("c-f")), - - # Navigation - Primary - Filtering - # There does not appear to be a hotkey to reset filters at this time - #"show all": - # R(Key("sa-?")), - "show drafts": - R(Key("sa-d")), - "show favorites": - R(Key("cs-u")), - "show flags": - R(Key("sa-f")), - "show mentions all": - R(Key("cs-l")), - "show mentions me": - R(Key("cs-o")), - "show notifications": - R(Key("sa-n")), - "show unread": - R(Key("sa-r")), - - # Navigation - Space - # Note - A number of space navigation items do not have documented hotkeys - "add (person | people) []": - R(Key("cs-p") + Text("%(person)s")), - "create whiteboard": - R(Key("cs-b")), - "show whiteboards": - R(Key("cs-w")), - "leave space": - R(Key("cs-e")), - "(search | find) space": - R(Key("cs-j")), - - # Navigation - Extra - "previous (space | item) []": - R(Key("a-up"))*Repeat(extra="nnavi10"), - "next (space | item) []": - R(Key("a-down"))*Repeat(extra="nnavi10"), - - # Messaging - "attach": - R(Key("c-o")), - "emoji": - R(Key("w-.")), - "gif | jeff": - R(Key("c-g")), - "toggle markdown": - R(Key("c-m")), - "new-line": - R(Key("s-enter")), - "personal meeting link": - R(Key("sa-p")), - "send": - R(Key("enter")), - - # Formatting - Non-markdown - "strong | bold": - R(Key("c-b")), - "emphasis | italicize": - R(Key("c-i")), - "underline": - R(Key("c-u")), - "(number | numbered) list": - R(Key("sa-o")), - "(bullet | bulletted) list": - R(Key("sa-u")), - "heading one": - R(Key("sa-1")), - "heading two": - R(Key("sa-2")), - "heading three": - R(Key("sa-3")), - - # Formatting - markdown - # Use "markdown" rule - } - exported = True - extras = [ - ShortIntegerRef("nnavi10", 1, 11), - Dictation("person"), - ] - defaults = { - "nnavi10": 1, - "person": "", - } - -def get_rule(): - return WebexTeamsRule, RuleDetails(name="Web X Teams", executable="CiscoCollabHost") diff --git a/castervoice/rules/apps/editor/__init__.py b/castervoice/rules/apps/editor/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/rules/apps/editor/atom.py b/castervoice/rules/apps/editor/atom.py deleted file mode 100644 index a77b21e43..000000000 --- a/castervoice/rules/apps/editor/atom.py +++ /dev/null @@ -1,571 +0,0 @@ -""" -__author__ = 'LexiconCode' -Command-module for Atom -Official Site "https://atom.io/" -""" - -# How long to wait for the Atom palette to load before hitting the enter key -from dragonfly import Pause, Function, Repeat, Dictation, Choice, MappingRule, ShortIntegerRef - -from castervoice.lib.actions import Text, Key - -from castervoice.lib import settings, navigation -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - -atom_palette_wait = 30 -if settings.settings(["miscellaneous", "atom_palette_wait"]): - atom_palette_wait = int(settings.SETTINGS["miscellaneous"]["atom_palette_wait"]) - - -def ACP(command): - """Utilize the Palette UI to execute commands.""" - return R(Key("cs-p") + Pause(str(atom_palette_wait)) + Text(command) + Key("enter")) - -class AtomRule(MappingRule): - """ - Commands for the Atom editor. - - `R(Key("command keys"))` - Registers a key and label combination for use in a voice commands. - `ACP("command name")` - Registers an Atom Palette Command and label combination for use in voice commands. - - Spoken commands that are commented out do not have assigned default shortcut keys or - are incompatible. The '#extra' subsection of commands are commands that fit within - the category but are not displayed by the menu or UI Legend: '#' for not assigned, - '##' for shortcut or functional duplicate. - """ - - mapping = { - # Menu UI------------------------------------------------------------------------ - #File Menu - "[open] new window": - R(Key("cs-n")), - "new file": - R(Key("c-n")), - "open file": - R(Key("c-o")), - "open folder": - R(Key("cs-o")), - "add project folder": - R(Key("ac-o")), - "open settings": - R(Key("c-comma")), - "reopen closed item": - ACP("Reopen Closed Item"), - "open [your] config": - ACP("Open Your Config"), - "open [your] int script": - ACP("Open Your Int Script"), - "open [your] key map": - ACP("Open Your Key Map"), - "open [your] snippet": - ACP("Open Your Snippet"), - "open [your] style sheet": - ACP("Open your Stylesheet"), - "save as": - R(Key("cs-s")), - "save all": - ACP("Save All"), - "close pane": - R(Key("c-k, c-w")), - "close pane others": - R(Key("c-k, ca-w")), - "close window": - R(Key("cs-w")), - #Extra - #Edit Menu - "copy path": - R(Key("cs-c")), - "select all": - R(Key("c-a")), - "[toggle] (comments | comment line)": - R(Key("c-slash")), - "reflow section": - R(Key("ac-q")), - "select encoding": - R(Key("cs-u")), - "[go to] line ": - R( - Key("c-g") + Pause(str(atom_palette_wait)) + Text("%(ln1)s") + - Key("enter")), - " [line] [by ]": - R(Function(navigation.action_lines)), - "select grammar": - R(Key("cs-l")), - #Lines Submenu - "toggle out dent": - R(Key("c-rightbrace")), - "auto indent windows": - ACP("Window Auto Indent"), - "[move] line up []": - R(Key("c-up")*Repeat(extra="n")), - "[move] line down []": - R(Key("c-down")*Repeat(extra="n")), - "delete line []": - R(Key("cs-k")*Repeat(extra="n")), - "join line": - R(Key("c-j")), - #Text Submenu - "uppercase": - ACP("Editor Upper Case"), - "lowercase": - ACP("Editor Lower Case"), - "delete sub [word] []": - R(Key("a-backspace")*Repeat(extra="n")), - "delete [to] previous [word] []": - ACP("Delete to Previous Word boundary")*Repeat(extra="n"), - "delete [to] next [word] []": - ACP("Delete to Next Word Boundary")*Repeat(extra="n"), - "transpose": - ACP("Transpose"), - #Folding Submenu - "fold": - R(Key("ac-lbrace")), - "unfold": - R(Key("ac-rightbrace")), - "unfold all": - R(Key("c-k, c-0, acs-rightbrace")), - "fold [level] ": - R(Key("c-k, c-%(n2)s")), - #Bookmarks Submenu - "view (all | [all] bookmarks)": - R(Key("c-f2")), - "bookmark | book": - R(Key("ca-f2")), - "next (bookmark | book)": - R(Key("f2")), - "previous (bookmark | book)": - R(Key("s-f2")), - #View Menu - "reload file": - R(Key("ac-r")), - "full screen": - R(Key("f11")), - "toggle menu bar": - ACP("Toggle Menu Bar"), - "increase font [size] []": - R(Key("cs-equals")*Repeat(extra="n")), - "decrease font [size] []": - R(Key("cs-minus")*Repeat(extra="n")), - "reset font [size]": - R(Key("c-0")), - "toggle soft wrap": - ACP("Toggle Soft Wrap"), - "[toggle] tree view": - R(Key("c-backslash")), - #Panes Submenu - "split [pane] above": - R(Key("c-k, up")), - "split [pane] below": - R(Key("c-k, down")), - "split [pane] left": - R(Key("c-k, left")), - "split [pane] right": - R(Key("c-k, right")), - "[focus [on]] next pane": - R(Key("c-k, c-n")), - "[focus [on]] previous pane": - R(Key("c-k, c-p")), - "(focus [on] [pane] | pane) above": - R(Key("c-k, c-up")), - "(focus [on] [pane] | pane) below": - R(Key("c-k, c-down")), - "(focus [on] [pane] | pane) left": - R(Key("c-k, c-left")), - "(focus [on] [pane] | pane) right": - R(Key("c-k, c-right")), - #extras - "[go to] pane [item] ": - R(Key("a-%(n2)s")), - "[go to] (tab | pane [item])": - R(Key("a-%(nrw)s")), - #Developer Submenu - #"open in development mode": R(Key("", "Open in Development Mode")), - "run atom [specs]": - R(Key("ac-s")), - "run package [specs]": - R(Key("ac-p")), - "[toggle] developer tools": - R(Key("ac-i")), - #Selection Menu - "[add] select above []": - R(Key("ac-up")*Repeat(extra="n")), - "[add] select below []": - R(Key("ac-down")*Repeat(extra="n")), - "split into lines": - ACP("Split Into Lines"), - "select line": - R(Key("c-l")), - "[select] [to] (begin | beginning) [of] line": - ACP("Editor: Select to Beginning of Line"), - "[select] inside brackets": - R(Key("ac-comma")), - #Find Menu - "find (selection | selected)": - R(Key("c-e")), - "find [and] select all": - R(Key("a-f3")), - "[find] select next []": - R(Key("c-d")*Repeat(extra="n")), - "[find] select skip [this] []": - R(Key("c-k, c-d")*Repeat(extra="n")), - "[find] select skip next []": - R(Key("c-d")) + R(Key("c-k, c-d")*Repeat(extra="n")), - "find replace next": - ACP("Find and Replace: Replace Next"), - "find replace all": - ACP("Find and Replace: Replace All"), - "find buffer": - R(Key("c-b")), - "(find | go to) file": - R(Key("c-p")), - "find modified file": - R(Key("cs-b")), - #Packages Menu - #Bracket Matcher Submenu - "bracket [go to] match": - R(Key("c-m")), - "bracket remove [from] selection": - R(Key("c-lbrace")), - "close [current] tag": - ACP("Bracket Matcher: Close Tag"), - "bracket remove matching": - R(Key("ac-backspace")), - #Command Palette Submenu - "[toggle] [command] palette": - R(Key("cs-p")), - #Dev Live Reload Submenu - "reload [all] styles": - R(Key("acs-r")), - #Git Diff Submenu - "move to next diff [different]": - ACP("Move to Next Diff"), - "move to previous diff [different]": - ACP("Move to Previous Diff"), - "[toggle] diff List": - ACP("Toggle Diff List"), - #Keybinding Resolver Submenu - "toggle key [binding] resolver": - ACP("Key Binding Resolver: Toggle"), - #Markdown Preview Submenu - "markdown preview": - R(Key("cs-m")), - #Extras - "markdown copy html": - ACP("Markdown Preview: Copy HTML"), - "markdown toggle break on new line": - ACP("Markdown Preview: Toggle Break On Single Newline"), - #Package Generator Submenu - "(make|generate) package": - ACP("Package Generator: Generate Package"), - "(make|generate) syntax theme": - ACP("Package Generator: Generate Syntax Theme"), - #Settings View Submenu - ##"open setting": R(Key("c-comma")), - "show key bindings": - ACP("Settings View: Show Key Bindings"), - "installed themes": - ACP("Settings View: Installed Themes"), - "uninstalled themes": - ACP("Settings View: Uninstall Themes"), - "installed packages": - ACP("Settings View: Installed Packages"), - "uninstalled packages": - ACP("Settings View: Uninstalled Packages"), - "search (packages|themes)": - ACP("Settings View: Install Packages and Themes"), - "update packages": - ACP("Settings View: Check for Package Update"), - #Snippets Submenu - "expand snippets": - ACP("Snippets: Expand"), - "next snippet": - R(Key("tab")), - "previous snippet": - R(Key("a-tab")), - "available snippet": - R(Key("as-tab")), - #Styleguide Submenu - "show style [guide]": - R(Key("cs-g")), - #Symbol - "find symbol": - R(Key("c-r")), - "project symbol": - R(Key("cs-r")), - #Timecop Submenu - "time cop": - ACP("Timecop: View"), - #Tree View Submenu - "tree focus": - R(Key("c-0")), - "tree [View] [toggle] view": - R(Key("c-backslash")), - "tree [View] [reveal] active file": - R(Key("cs-backslash")), - "tree [View] [toggle] side": - ACP("Tree View: show"), - #Extras - "tree show": - ACP("Tree View: Show"), - "tree rename": - ACP("Tree View: Rename"), - "tree remove": - ACP("Tree View: Remove"), - "tree add file": - ACP("Tree View: Add File"), - "tree duplicate": - ACP("Tree View: Duplicate"), - "tree add folder": - ACP("Tree View: Add Folder"), - #Whitespaces Submenu - "remove trailing [white] spaces": - ACP("Whitespace: Remove Trailing Whitespace"), - "convert tabs [to] spaces": - ACP("Whitespace: Convert Tabs to Spaces"), - "convert spaces [to] tabs": - ACP("Whitespace: Convert Spaces to Tabs"), - #Open on GitHub - "github [open] blame": - ACP("Open on GitHub: Blame"), - "github [open] [branch] compare": - ACP("Open on GitHub: Branch Compare"), - "github [open] [copy] URL": - ACP("Open on GitHub: Copy URL"), - "github [open] file": - ACP("Open on GitHub: File"), - "github [open] history": - ACP("Open on GitHub: History"), - "github [open] issues": - ACP("Open on GitHub: Issues"), - "github [open] repository": - ACP("Open on GitHub: Repository"), - #Open on GitHub - "github close different": - ACP("GitHub: Close All Diff Views"), - "github empty different": - ACP("GitHub: Close Empty Diff Views"), - "github [show waterfall] diagnostics": - ACP("GitHub:Okay Show Waterfall Diagnostics"), - "github [open] (issues | pull request)": - ACP("GitHub: Open Issue or Pull Request"), - "github view staged changes [for current file]": - ACP("GitHub: View Staged Changes for Current File"), - "github view unstaged changes [for current file]": - ACP("GitHub: View Unstaged Changes for Current File"), - #Open on GitHub - "github pull": - R(Key("a-g, s-f")), - "github push": - R(Key("a-g, p")), - "github clone": - R(Key("a-g, equal")), - "github fetch": - R(Key("a-g, f")), - "github logout": - ACP("GitHub: Logout"), - "github force push": - R(Key("a-g, s-p")), - "github tab [toggle]": - R(Key("c-8")), - "github focus [tab]": - R(Key("c-9")), - # Atom Development - "dev (restart | reload) [atom]": - ACP("Window: Reload"), - - # ----Atom Optional Third-Party Packages and Dependencies----------------------------------------------------------------------------- - #Install through command prompt, Atom install manager or a .bat file at http://tinyurl.com/Atom-Dependencies - # pip install --upgrade autopep8T - # apm install project-sidebar - # apm install project-manager - # apm install git-plus - # apm install script - # apm install atom-beautify - # apm install goto-last-edit - # apm install tab-numbers - # apm install menu-manager - # apm install string-looper - # apm install toggle-quotes - # apm install delete-Plus - # apm install expand-selection-to-quotes - # apm install highlight-selected - # apm install sublime-style-column-selection - - #Atom Third-Party Package Commands------------------------------------------------------------------------------------------------- - #Atom Beautify - "beautify editor": - ACP("Atom Beautify: Beautify Editor"), - "beautify migrate settings": - ACP("Atom Beautify: Migrate Settings"), - "beautify debug editor": - ACP("Atom Beautify: Help Debug Editor"), - #Toggle Quotes - "toggle quotes": - R(Key("cs-apostrophe")), - #Script - "script run": - ACP("Script: Run"), - "script [run] options": - ACP("Script: Run Options"), - "script [run] profile": - ACP("Script: Run With Profile"), - "script run [by] line": - ACP("Script: Run By Line Number"), - "script kill [process]": - ACP("Script: Kill Process"), - "script close view": - ACP("Script: Close View"), - "script copy [run] [results]": - ACP("Script: Copy Run Results"), - #"script close window and stop script": ACP("Script: Close Window and Stop Script"), - #Delete Plus - "delete words": - ACP("Delete Plus: Delete"), - #Last Edit - "back edit": - R(Key("c-i")), - "next edit": - R(Key("ca-i")), - #Looper - #"cursor loud|capitalize []": R(Key("a-down") * Repeat(extra="n")), # Not fully implemented - #"cursor camel []": R(Key("a-down") * Repeat(extra="n")), # Not fully implemented - #"cursor lowercase []": R(Key("a-down") * Repeat(extra="n")), # Not fully implemented - "looping down cursor": - R(Key("a-down")), - "looping up cursor": - R(Key("a-up")), - "looping up": - R(Key("wa-up")), - #Git Plus - "git (custom|run)": - ACP("Git Plus: Run"), - "git log": - ACP("Git Plus: Log"), - "git log current [file]": - ACP("Git Plus: Log Current File"), - "git status": - ACP("Git Plus: Status"), - "git show": - ACP("Git Plus: Show"), - "git tags": - ACP("Git Plus: Tags"), - "git open changed files": - ACP("Git Plus: Git Open Changed Files"), - "git checkout [branch|tag]": - ACP("Git Plus: Checkout"), - "git menu": - ACP("Git Plus: Menu"), - "git pull": - ACP("Git Plus: Pull"), - "git pull [using] rebase": - ACP("Git Plus: Pull Using Rebase"), - "git push": - ACP("Git Plus: Push"), - "git commit": - ACP("Git Plus: Commit"), - "git commit amend": - ACP("Git Plus: Commit Amend"), - "git merge": - ACP("Git Plus: Merge"), - "git merge remote": - ACP("Git Plus: Merge Remote"), - "git diff": - ACP("Git Plus: Diff"), - "git diff all": - ACP("Git Plus: Diff All"), - "git add": - ACP("Git Plus: Add"), - "git add all": - ACP("Git plus: Add All"), - "git add [and] commit": - ACP("Git Plus: Add And Commit"), - "git add all [and] commit": - ACP("Git Plus: Add All and Commit"), - "git add all commit [and] push": - ACP("Git Plus: Add All Commit And Push"), - "git new branch": - ACP("Git Plus: New Branch"), - "git (rm|remove)": - ACP("Git Plus: Remove"), - #Project Manager - "project manager [list]": - ACP("Project Manager:List"), - "project manager save": - ACP("Project Manager:Save Project"), - "project manager edit": - ACP("Project Manager:Edit Project"), - #Menu Sidebar - "[project manager] sidebar": - ACP("Project Sidebar: Toggle"), - #Expand Selection to Quotes - "(expand|fill) quotes": - R(Key("c-apostrophe")), - #Auto Complete - "auto [complete]": - R(Key("c-space")), - #Highlight Selected---- #Placeholder - #Sublime Style Column Selection---- #Placeholder - - #Atom | Dragonfly Development-------------------------------------------------------------------------------------------------------------------------------------------------------- - # Template to create more commands. Documentation: https://dragonfly.readthedocs.org/en/latest/actions.html and http://castervoice.readthedocs.io/en/latest/castervoice/doc/Intro/ - # Used for basic key shortcuts - #"text for voice command": R(Key("modifier-key", "program name: command name/description")), - #"": R(Key("")), - # Used for command that utilizes the "command palette" shortcut in the absence of assigned keyboard shortcut. - #"text for voice command": ACP("text as described in command palette", "command name/description"), - #"": ACP(""), - #Atom Shortcut Snippets - "dev keys [input] []": - R(Text('#"": R(Key("-"),') + Key("enter"))*Repeat(extra="n"), - "dev [command] palette []": - R(Text('#"": ACP(""),') + Key("enter"))*Repeat(extra="n"), - #Repeatable Snippets - "dev numb keys [input] []": - R(Text('#" []": R(Key("-") * Repeat(extra="n"),') + Key("enter"))* - Repeat(extra="n"), - "dev numb [command] palette []": - R(Text('#" []": ACP("") * Repeat(extra="n"),') + Key("enter"))* - Repeat(extra="n"), - #Basic Dragonfly Snippets - "dev key []": - R(Text('"": Key(""),'))*Repeat(extra="n"), - "dev text []": - R(Text('"": Text(""),'))*Repeat(extra="n"), - "send command []": - R(Text('"": R(Function(SendJsonCommands, a_command=""), rdescript=""),'))* - Repeat(extra="n"), - } - - extras = [ - Dictation("text"), - Dictation("mim"), - ShortIntegerRef("n", 1, 50), - ShortIntegerRef("ln1", 1, 50000), - ShortIntegerRef("ln2", 1, 50000), - ShortIntegerRef("n2", 1, 10), - Choice("action", navigation.actions), - Choice( - "nrw", { - "first": 1, - "second": 2, - "third": 3, - "fourth": 4, - "fifth": 5, - "sixth": 6, - "seventh": 7, - "eighth": 8, - "(ninth | last)": 9, - }), - ] - defaults = { - "n": 1, - "ln2": "", - "mim": "", - } - - -def get_rule(): - return AtomRule, RuleDetails(name="atom", executable="atom", title="Atom") diff --git a/castervoice/rules/apps/editor/eclipse_rules/__init__.py b/castervoice/rules/apps/editor/eclipse_rules/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/rules/apps/editor/eclipse_rules/eclipse.py b/castervoice/rules/apps/editor/eclipse_rules/eclipse.py deleted file mode 100644 index f9fbe7296..000000000 --- a/castervoice/rules/apps/editor/eclipse_rules/eclipse.py +++ /dev/null @@ -1,49 +0,0 @@ -from dragonfly import Dictation, Function, Paste, Pause, ShortIntegerRef - -try: # Try first loading from caster user directory - from eclipse_support import ec_con -except ImportError: - from castervoice.rules.apps.editor.eclipse_rules.eclipse_support import ec_con - -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.mergerule import MergeRule -from castervoice.lib.const import CCRType -from castervoice.lib.merge.additions import Boolean -from castervoice.lib.merge.state.short import R - -from castervoice.lib.actions import Key, Text - - -class EclipseCCR(MergeRule): - pronunciation = "eclipse jump" - - mapping = { - #Line Ops - "configure": - R(Paste(ec_con.analysis_chars) + - Key("left:2/5, c-f/20, backslash, rbracket, enter") + - Function(ec_con.analyze_for_configure)), - "jump in []": - R(Key("c-f, a-o") + Paste(r"[\(\[\{\<]") + Function(ec_con.regex_on) + - Key("enter:%(n)d/5, escape, right")), - "jump out []": - R(Key("c-f, a-o") + Paste(r"[\)\] \}\>]") + Function(ec_con.regex_on) + - Key("enter:%(n)d/5, escape, right")), - "jump back []": - R(Key("c-f/5, a-b") + Paste(r"[\)\]\}\>]") + Function(ec_con.regex_on) + - Key("enter:%(n)d/5, escape, left")), - "[go to] line ": - R(Key("c-l") + Pause("50") + Text("%(n)d") + Key("enter") + Pause("50")), - "shackle []": - R(Key("c-l") + Key("right, cs-left") + Function(ec_con.lines_relative)), - } - extras = [ - Dictation("text"), - ShortIntegerRef("n", 1, 1000), - Boolean("back"), - ] - defaults = {"n": 1, "back": False} - - -def get_rule(): - return EclipseCCR, RuleDetails(ccrtype=CCRType.APP, executable="eclipse", title="Eclipse") diff --git a/castervoice/rules/apps/editor/eclipse_rules/eclipse2.py b/castervoice/rules/apps/editor/eclipse_rules/eclipse2.py deleted file mode 100644 index 1769011b2..000000000 --- a/castervoice/rules/apps/editor/eclipse_rules/eclipse2.py +++ /dev/null @@ -1,102 +0,0 @@ -from dragonfly import Repeat, Dictation, Function, Choice, MappingRule, ShortIntegerRef - -from castervoice.lib.actions import Key - -try: # Try first loading from caster user directory - from eclipse_support import ec_con -except ImportError: - from castervoice.rules.apps.editor.eclipse_rules.eclipse_support import ec_con - -from castervoice.rules.core.alphabet_rules import alphabet_support # Manually change import path if in user directory. -from castervoice.lib.merge.additions import Boolean -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class EclipseRule(MappingRule): - mapping = { - "prior tab []": - R(Key("cs-f6"))* - Repeat(extra="n"), # these two must be set up in the eclipse preferences - "next tab []": - R(Key("c-f6"))*Repeat(extra="n"), - "open resource": - R(Key("cs-r")), - "open type": - R(Key("cs-t")), - "jump to source": - R(Key("f3")), - "editor select": - R(Key("c-e")), - "step over []": - R(Key("f6/50")*Repeat(extra="n")), - "step into": - R(Key("f5")), - "step out [of]": - R(Key("f7")), - "resume": - R(Key("f8")), - "(debug | run) last": - R(Key("f11")), - "mark occurrences": - R(Key("as-o")), - - # "terminate" changes to the settings for this hotkey: (when: in dialogs and windows) - "terminate": - R(Key("c-f2")), - "refractor symbol": - R(Key("sa-r")), - "symbol next []": - R(Key("c-k"))*Repeat(extra="n"), - "symbol prior []": - R(Key("cs-k"))*Repeat(extra="n"), - "format code": - R(Key("cs-f")), - "do imports": - R(Key("cs-o")), - "comment line": - R(Key("c-slash")), - "build it": - R(Key("c-b")), - "split view horizontal": - R(Key("cs-underscore")), - "split view vertical": - R(Key("cs-lbrace")), - - #Line Ops - "find everywhere": - R(Key("ca-g")), - "find word [] []": - R(Key("c-f") + Function(ec_con.regex_off) + Function(ec_con.find)), - "find regex [] []": - R(Key("c-f") + Function(ec_con.regex_on) + Function(ec_con.find)), - "find [ []] [] []": - R(Key("c-f") + Function(ec_con.find)), - "find [] []": - R(Key("c-f") + Function(ec_con.find)), - } - extras = [ - Dictation("text"), - Dictation("mim"), - ShortIntegerRef("n", 1, 3000), - alphabet_support.get_alphabet_choice("a"), - alphabet_support.get_alphabet_choice("b"), - alphabet_support.get_alphabet_choice("c"), - Choice("punctuation", {"hash tag": "#"}), - Boolean("back"), - Boolean("go"), - ] - defaults = { - "n": 1, - "mim": "", - "a": None, - "b": None, - "c": None, - "punctuation": None, - "back": False, - "go": False - } - - -def get_rule(): - return EclipseRule, RuleDetails(name="eclipse", executable="eclipse", title="Eclipse") diff --git a/castervoice/rules/apps/editor/eclipse_rules/eclipse_support.py b/castervoice/rules/apps/editor/eclipse_rules/eclipse_support.py deleted file mode 100644 index 86c006a1c..000000000 --- a/castervoice/rules/apps/editor/eclipse_rules/eclipse_support.py +++ /dev/null @@ -1,89 +0,0 @@ -import re - -from castervoice.lib.actions import Key - -from castervoice.lib import utilities, context -from castervoice.lib.actions import Text -from castervoice.lib.merge.state.actions2 import UntilCancelled - - -class EclipseController(object): - def __init__(self): - self.regex = False - self.analysis_chars = r"\]" - - def regex_on(self): - if not self.regex: - Key("a-x").execute() # turn on regex - self.regex = True - - def regex_off(self): - if self.regex: - Key("a-x").execute() # turn off regex - self.regex = False - - def analyze_for_configure(self): - '''solves the problem of the editor not being smart about toggles by using text - to see which toggles are active''' - '''regex toggle check''' - Key("escape").execute() # get out of Find - result = context.read_nmax_tries(10) - if result == self.analysis_chars: - self.regex = False - Key("backspace").execute() - elif result == self.analysis_chars[1]: - self.regex = True - Key("delete, backspace").execute() - else: - print("Eclipse configuration failed (%s)" % result) - - def lines_relative(self, back, n): - if back: #backward - try: - num = context.read_nmax_tries(10) - txt = str(int(num) - int(n) + 1) # +1 to include current line - Text(txt).execute() - except ValueError: - utilities.simple_log() - return - Key("enter").execute() - else: #forward - Key("escape, end, home, home").execute( - ) # end-home-home to include all of current line - - # forward or backward - Key("s-down:" + str(int(n)) + "/5, s-left").execute() - - def find(self, back, go, text=None, punctuation=None, a=None, b=None, c=None): - '''set direction''' - - key = "b" if back else "o" - Key("a-" + key).execute() - '''figure out what to search for''' - if text is not None: - text = str(text) - '''simple vowel-removal regex''' - if self.regex: - text = re.sub("[aeiouAEIOU]+", r".*", text) - if text.endswith(r".*"): - text = text[:-2] - elif punctuation is not None: - text = str(punctuation) - self.regex_off() - elif a is not None: - a = str(a) - b = str(b) if b is not None else "" - c = str(c) if c is not None else "" - text = a + b + c - self.regex_off() - Text(text).execute() - '''"go" indicates that we should keep looking''' - if go: - u = UntilCancelled(Key("enter"), 2) - u.show = False - u.execute() - else: - Key("enter, escape").execute() - - -ec_con = EclipseController() diff --git a/castervoice/rules/apps/editor/emacs.py b/castervoice/rules/apps/editor/emacs.py deleted file mode 100644 index 739806f3f..000000000 --- a/castervoice/rules/apps/editor/emacs.py +++ /dev/null @@ -1,55 +0,0 @@ -from dragonfly import Dictation, MappingRule, ShortIntegerRef - -from castervoice.lib.actions import Key - -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class EmacsRule(MappingRule): - mapping = { - "open file": R(Key("c-x, c-f")), - "save file": R(Key("c-x, c-s")), - "save as": R(Key("c-x, c-w")), - "save all": R(Key("c-x, s")), - "revert to file": R(Key("c-x, c-v")), - "revert buffer": R(Key("a-x")), - "close buffer": R(Key("c-x, c-c")), - "undo": R(Key("c-underscore")), - "begin selection": R(Key("c-space")), - "cancel selection": R(Key("c-g")), - "cut selection": R(Key("c-w")), - "paste": R(Key("c-y")), - "copy number ": R(Key("c-x, r, s, %(n)d")), - "paste number ": R(Key("c-x, r, i, %(n)d")), - # delete - "forward delete": R(Key("c-delete")), - "delete word": R(Key("a-delete")), - "forward delete word": R(Key("a-d")), - "word forward": R(Key("a-f")), - "word backward": R(Key("a-b")), - "line forward": R(Key("c-a")), - "line backward": R(Key("c-e")), - "paragraph forward": R(Key("a-lbrace")), - "paragraph backward": R(Key("a-rbrace")), - "document forward": R(Key("a-langle")), - "document backward": R(Key("a-rangle")), - "C function forward": R(Key("ac-a")), - "C function backward": R(Key("ac-e")), - "incremental search": R(Key("c-s")), - "incremental reverse": R(Key("c-r")), - "interactive search": R(Key("a-percent")), - "go to line ": R(Key("a-x, %(n)d")), - "prior bracket": R(Key("escape:down, c-b, escape:up")), - "next bracket": R(Key("escape:down, c-f, escape:up")), - } - extras = [ - Dictation("text"), - Dictation("mim"), - ShortIntegerRef("n", 1, 1000), - ] - defaults = {"n": 1, "mim": ""} - - -def get_rule(): - return EmacsRule, RuleDetails(name="E max", executable="emacs", title="emacs") diff --git a/castervoice/rules/apps/editor/flashdevelop.py b/castervoice/rules/apps/editor/flashdevelop.py deleted file mode 100644 index 532f9c5c0..000000000 --- a/castervoice/rules/apps/editor/flashdevelop.py +++ /dev/null @@ -1,46 +0,0 @@ -from dragonfly import Repeat, Dictation, MappingRule, Pause, ShortIntegerRef - -from castervoice.lib.actions import Key, Text - -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class FlashDevelopRule(MappingRule): - mapping = { - "prior tab []": R(Key("c-pgup"))*Repeat(extra="n"), - "next tab []": R(Key("c-pgdown"))*Repeat(extra="n"), - "open resource": R(Key("c-r")), - "jump to source": R(Key("f4")), - "jump away": R(Key("s-f4")), - "step over []": R(Key("f10")*Repeat(extra="n")), - "step into": R(Key("f11")), - "step out [of]": R(Key("s-f11")), - "resume": R(Key("a-d, c")), - "terminate": R(Key("s-f5")), - "find everywhere": R(Key("cs-f")), - "refractor symbol": R(Key("a-r, r")), - "symbol next []": R(Key("f3"))*Repeat(extra="n"), - "symbol prior []": R(Key("s-f3"))*Repeat(extra="n"), - "format code": R(Key("cs-2")), - "comment line": R(Key("c-q")), - "clean it": R(Key("s-f8")), - "build it": R(Key("f8")), - "(debug | run) last": R(Key("f5")), - "split view horizontal": R(Key("cs-enter")), - "auto complete": R(Key("cs-1")), - "[go to] line ": R(Key("c-g") + Pause("50") + Text("%(n)d") + Key("enter")), - } - extras = [ - Dictation("text"), - Dictation("mim"), - ShortIntegerRef("n", 1, 1000), - ] - defaults = {"n": 1, "mim": ""} - - -def get_rule(): - details = RuleDetails(name="flash develop", - executable="FlashDevelop", - title="FlashDevelop") - return FlashDevelopRule, details diff --git a/castervoice/rules/apps/editor/jetbrains.py b/castervoice/rules/apps/editor/jetbrains.py deleted file mode 100644 index e9baf5cf8..000000000 --- a/castervoice/rules/apps/editor/jetbrains.py +++ /dev/null @@ -1,139 +0,0 @@ -from dragonfly import Dictation, Repeat, MappingRule, ShortIntegerRef - -from castervoice.lib.actions import Text, Key -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - -# Directional Movement - -RIGHT = "(right|sauce)" -LEFT = "(left|lease)" -UP = "(up|sauce)" -DOWN = "(down|dunce)" -FORWARD = "(%s|next|forward)" % RIGHT -BACK = "(%s|back|prev|prior|previous)" % LEFT - -# Miscellaneous -method = "(meth|method)" -methods = "(meths|methods)" -extract = "(pull|extract)" - -# Delay Timer -DELAY = "20" - - -class JetbrainsRule(MappingRule): - - mapping = { - "quick fix": R(Key("a-enter")), - "(duplicate|duple) %s" % DOWN: R(Key("c-d")), - "find action": R(Key("cs-a")), - "format [code]": R(Key("ca-l")), - "show doc": R(Key("c-q")), - "find class": R(Key("c-n")), - "build": R(Key("c-f9")), - "build and run": R(Key("s-f10")), - "%s tab []|tab %s []" % (FORWARD, RIGHT): R(Key("a-right/%s" % DELAY)) * Repeat(extra="n"), - "%s tab []|tab %s []" % (BACK, LEFT): R(Key("a-left/%s" % DELAY)) * Repeat(extra="n"), - "(comment|rem) [line]": R(Key("c-slash")), - "(uncomment|unrem) [line]": R(Key("cs-slash")), - "select ex" : R(Key("c-w")), - "select ex down" : R(Key("cs-w")), - "find file": R(Key("shift, shift")), - "find": R(Key("c-f")), - "find next": R(Key("f3")), - "find prior": R(Key("f3")), - "find %s [match] []" % FORWARD: R(Key("enter")) * Repeat(extra="n"), - "find %s [match] []" % BACK: R(Key("s-enter")) * Repeat(extra="n"), - "replace [here]": R(Key("c-r")), - "find [in] (all|files)": R(Key("cs-f")), - "replace [in] (all|files)": R(Key("cs-r")), - "go [to line] []": R(Key("c-g/%s" % DELAY) + Text("%(n)s") + Key("enter")), - "implement (%s|%s)" % (method, methods): R(Key("c-i")), - "override %s" % method: R(Key("c-o")), - "run config": R(Key("as-f10")), - "[find] (usage|usages)": R(Key("a-f7")), - "show (usage|usages)": R(Key("ca-f7")), - "[find] (usage|usages) in file": R(Key("c-f7")), - "[go to] (source|declaration)": R(Key("c-b")), - "[go to] implementation": R(Key("ca-b")), - "(skraken|smart kraken)": R(Key("cs-space")), - "go %s []" % FORWARD: R(Key("ca-right")) * Repeat(extra="n"), - "go %s []" % BACK: R(Key("ca-left")) * Repeat(extra="n"), - "%s %s []" % (method, FORWARD): R(Key("a-down")) * Repeat(extra="n"), - "%s %s []" % (method, BACK): R(Key("a-up")) * Repeat(extra="n"), - "go block start": R(Key("c-[")), - "go block end": R(Key("c-]")), - "(%s error|error %s)" % (FORWARD, RIGHT): R(Key("f2")) * Repeat(extra="n"), - "(%s error|error %s)" % (BACK, LEFT): R(Key("s-f2")) * Repeat(extra="n"), - "[organize|optimize] imports": R(Key("ca-o")) * Repeat(extra="n"), - "[move] line %s []" % UP: R(Key("as-up")) * Repeat(extra="n"), - "[move] line %s []" % DOWN: R(Key("as-down")) * Repeat(extra="n"), - "expand [selection] []": R(Key("c-w")) * Repeat(extra="n"), - "shrink [selection] []": R(Key("cs-w")) * Repeat(extra="n"), - "auto indent": R(Key("ca-i")), - "close tab []|tab close []": R(Key("c-f4/%s" % DELAY)) * Repeat(extra="n"), - "run": R(Key("s-f10")), - "debug": R(Key("s-f9")), - "redo []": R(Key("cs-z")) * Repeat(extra="n"), - "[show] settings": R(Key("ca-s")), - "collapse": R(Key("c--")), - "uncollapse": R(Key("c-+")), - "collapse all": R(Key("cs--")), - "uncollapse all": R(Key("cs-+")), - - # only works if you disable tabs. - "close pane []|pane close []": R(Key("c-f4/%s" % DELAY)) * Repeat(extra="n"), - - # refactoring - "refactor": R(Key("cas-t")), - "rename": R(Key("s-f6")), - "inline": R(Key("ca-n")), - "(pull|extract)": R(Key("ca-m")), - "%s [variable|var]" % extract: R(Key("ca-v")) * Repeat(extra="n"), - "%s field" % extract: R(Key("ca-f")) * Repeat(extra="n"), - "%s constant" % extract: R(Key("ca-c")) * Repeat(extra="n"), - "%s (param|parameter)" % extract: R(Key("ca-p")) * Repeat(extra="n"), - - # debugging - "step over": R(Key("f8")), - "step into": R(Key("f7")), - "smart step over": R(Key("s-f7")), - "step out": R(Key("s-f8")), - "toggle breakpoint": R(Key("c-f8")), - "view breakpoints": R(Key("cs-f8,cs-f8")), - "continue": R(Key("f9")), - - # window navigation - "focus editor": R(Key("escape")), - "go tool ": R(Key("a-%(n)s")), - "[toggle] (term|terminal)": R(Key("a-f12")), - - # must be bound manually below this point - "(kill|delete) %s" % FORWARD: R(Key("a-d,0")), - "(kill|delete) %s" % BACK: R(Key("a-d,$")), - - # jet brains can only split horizontally or vertically - "split [pane] %s" % UP: R(Key("cs-s,h")), - "split [pane] %s" % DOWN: R(Key("cs-s,h")), - "split [pane] %s" % RIGHT: R(Key("cs-s,v")), - "split [pane] %s" % LEFT: R(Key("cs-s,v")), - "pane %s []" % UP: R(Key("cs-s,up")) * Repeat(extra="n"), - "pane %s []" % DOWN: R(Key("cs-s,down")) * Repeat(extra="n"), - "(pane %s|%s pane) []" % (RIGHT, RIGHT): R(Key("cs-s,right")) * Repeat(extra="n"), - "(pane %s|%s pane) []" % (LEFT, LEFT): R(Key("cs-s,left")) * Repeat(extra="n"), - "file rename | rename file": R(Key("cas-r")), - } - extras = [ - Dictation("text"), - Dictation("mim"), - ShortIntegerRef("n", 1, 1000), - ] - - defaults = {"n": 1, "mim": ""} - - -def get_rule(): - details = RuleDetails(name="jet brains", - executable=["idea", "idea64", "studio64", "pycharm", "rider64", "webstorm", "webstorm64"]) - return JetbrainsRule, details diff --git a/castervoice/rules/apps/editor/lyx.py b/castervoice/rules/apps/editor/lyx.py deleted file mode 100644 index 7aef6caf6..000000000 --- a/castervoice/rules/apps/editor/lyx.py +++ /dev/null @@ -1,52 +0,0 @@ -from dragonfly import Repeat, Choice, MappingRule, ShortIntegerRef -from castervoice.lib.actions import Key -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class LyxRule(MappingRule): - mapping = { - "new file": R(Key("c-n")), - "open file": R(Key("c-o")), - "save as": R(Key("cs-s")), - - "math mode": R(Key("c-m")), - "display mode": R(Key("cs-m")), - - "view PDF": R(Key("c-r")), - "update PDF": R(Key("cs-r")), - - "move line up []": R(Key("a-up"))*Repeat(extra="n"), - "move line down []": R(Key("a-down"))*Repeat(extra="n"), - - "insert ": R(Key("a-i, h, %(environment)s")), - } - extras = [ - ShortIntegerRef("n", 1, 10), - Choice("environment", { - "(in line formula | in line)": "i", - "(display formula | display)": "d", - "(equation array environment | equation array)": "e", - "(AMS align environment | AMS align)": "a", - "AMS align at [environment]": "t", - "AMS flalign [environment]": "f", - "(AMS gathered environment | AMS gather)": "g", - "(AMS multline [environment]| multiline)": "m", - "array [environment]": "y", - "(cases [environment] | piecewise)": "c", - "(aligned [environment] | align)": "l", - "aligned at [environment]": "v", - "gathered [environment]": "h", - "split [environment]": "s", - "delimiters": "r", - "matrix": "x", - "macro": "o", - }), - ] - defaults = { - "n": 1, - } - - -def get_rule(): - return LyxRule, RuleDetails(name="lyx", executable="lyx") diff --git a/castervoice/rules/apps/editor/msvc.py b/castervoice/rules/apps/editor/msvc.py deleted file mode 100644 index 0913a9a52..000000000 --- a/castervoice/rules/apps/editor/msvc.py +++ /dev/null @@ -1,39 +0,0 @@ -from dragonfly import Repeat, Dictation, MappingRule, ShortIntegerRef -from castervoice.lib.actions import Key -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class MSVCRule(MappingRule): - mapping = { - "cursor prior": R(Key("c-minus")), - "cursor next": R(Key("cs-minus")), - "toggle full screen": R(Key("sa-enter")), - "resolve": R(Key("c-dot")), - "jump to source": R(Key("f12")), - "snippet": R(Key("tab")), - "step over []": R(Key("f10/50")*Repeat(extra="n")), - "step into": R(Key("f11")), - "step out [of]": R(Key("s-f11")), - "resume": R(Key("f8")), - "build [last]": R(Key("ca-f7")), - "debug [last]": R(Key("f5")), - "comment out": R(Key("c-k/50, c-c")), - "on comment out": R(Key("c-k/50, c-u")), - "set bookmark": R(Key("c-k, c-k")), - "next bookmark": R(Key("c-k, c-n")), - "break point": R(Key("f9")), - "format code": R(Key("cs-f")), - "(do imports | import all)": R(Key("cs-o")), - "comment line": R(Key("c-slash")), - "go to line": R(Key("c-g")), - } - extras = [ - Dictation("text"), - ShortIntegerRef("n", 1, 1000), - ] - defaults = {"n": 1} - - -def get_rule(): - return MSVCRule, RuleDetails(name="Microsoft visual studio", executable="WDExpress") diff --git a/castervoice/rules/apps/editor/notepadplusplus.py b/castervoice/rules/apps/editor/notepadplusplus.py deleted file mode 100644 index 768cb02f2..000000000 --- a/castervoice/rules/apps/editor/notepadplusplus.py +++ /dev/null @@ -1,38 +0,0 @@ -from dragonfly import Repeat, Dictation, MappingRule, ShortIntegerRef - -from castervoice.lib.actions import Key, Text, Mouse - -from castervoice.lib.actions import Text -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class NPPRule(MappingRule): - - mapping = { - "stylize ": - R(Mouse("right") + Key("down:6/5, right") + - (Key("down")*Repeat(extra="n2")) + Key("enter")), - "remove style": - R(Mouse("right") + Key("down:6/5, right/5, down:5/5, enter")), - "preview in browser": - R(Key("cas-r")), - - # requires function list plug-in: - "function list": - R(Key("cas-l")), - "open": - R(Key("c-o")), - "go [to] line ": - R(Key("c-g/10") + Text("%(n)s") + Key("enter")), - } - extras = [ - Dictation("text"), - ShortIntegerRef("n", 1, 1000), - ShortIntegerRef("n2", 1, 10), - ] - defaults = {"n": 1} - - -def get_rule(): - return NPPRule, RuleDetails(name="notepad plus plus", executable="notepad++") diff --git a/castervoice/rules/apps/editor/rstudio.py b/castervoice/rules/apps/editor/rstudio.py deleted file mode 100644 index fb725ed41..000000000 --- a/castervoice/rules/apps/editor/rstudio.py +++ /dev/null @@ -1,81 +0,0 @@ -from dragonfly import Pause, Function, Choice, MappingRule, ShortIntegerRef - -from castervoice.lib.actions import Key, Text, Mouse - -from castervoice.lib import navigation -from castervoice.lib.actions import Text -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R -from castervoice.lib.temporary import Store, Retrieve - - -class RStudioRule(MappingRule): - mapping = { - "new file": - R(Key("cs-n")), - "open file": - R(Key("c-o")), - "open recent project": - R(Key("a-f, j")), - "open project": - R(Key("a-f, n, enter")), - "save all": - R(Key("ac-s")), - "select all": - R(Key("c-a")), - "find": - R(Key("c-f")), - - "[go to] line ": - R(Key("as-g") + Pause("10") + Text("%(ln1)s") + Key("enter")), - " [line] [by ]" : - R(Function(navigation.action_lines, go_to_line="as-g/10", select_line_down="s-down", wait="/3", upon_arrival="home, ")), - - "focus console": - R(Key("c-2")), - "focus main": - R(Key("c-1")), - - "next tab": - R(Key("c-f12")), - "first tab": - R(Key("cs-f11")), - "previous tab": - R(Key("c-f11")), - "last tab": - R(Key("cs-f12")), - "close tab": - R(Key("c-w")), - - - "run line": - R(Key("c-enter")), - "run document": - R(Key("ac-r")), - "comment (line | selected)": - R(Key("cs-c")), - - "next plot": - R(Key("ac-f12")), - "previous plot": - R(Key("ac-f11")), - - "(help | document) that": - R(Store() + Key("c-2, question") + Retrieve() + Key("enter, c-3")), - "glimpse that": - R(Store() + Key("c-2") + Retrieve() + Key("space, percent, rangle, percent") + Text(" glimpse()") + Key("enter/50, c-1")), - "vee table that": - R(Store() + Key("c-2") + Text("library(vtable)") + Key("enter/50") + Retrieve() + Key("space, percent, rangle, percent") + Text(" vtable()") + Key("enter/50, c-1")), - - } - extras = [ - ShortIntegerRef("ln1", 1, 10000), - ShortIntegerRef("ln2", 1, 10000), - Choice("action", navigation.actions), - ] - defaults = {"ln2": ""} - - -def get_rule(): - details = RuleDetails(name="are studio", executable="rstudio") - return RStudioRule, details diff --git a/castervoice/rules/apps/editor/sqldeveloper.py b/castervoice/rules/apps/editor/sqldeveloper.py deleted file mode 100644 index 0d3aff692..000000000 --- a/castervoice/rules/apps/editor/sqldeveloper.py +++ /dev/null @@ -1,27 +0,0 @@ -from dragonfly import Dictation, MappingRule, ShortIntegerRef - -from castervoice.lib.actions import Key - -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class SQLDeveloperRule(MappingRule): - - mapping = { - "run this query": R(Key("f9")), - "format code": R(Key("c-f7")), - "comment line": R(Key("c-slash")), - } - extras = [ - Dictation("text"), - ShortIntegerRef("n", 1, 1000), - ] - defaults = {"n": 1} - - -def get_rule(): - details = RuleDetails(name="sequel developer", - executable="sqldeveloper64W", - title="SQL Developer") - return SQLDeveloperRule, details diff --git a/castervoice/rules/apps/editor/ssms.py b/castervoice/rules/apps/editor/ssms.py deleted file mode 100644 index 46de05e7a..000000000 --- a/castervoice/rules/apps/editor/ssms.py +++ /dev/null @@ -1,37 +0,0 @@ -from dragonfly import Repeat, Dictation, MappingRule, ShortIntegerRef -from castervoice.lib.actions import Key -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class SSMSRule(MappingRule): - mapping = { - # There doesn't seem to be a hotkey for sequential tab navigation in SSMS, but something is better than nothing... - "next tab []": R(Key("c-tab"))*Repeat(extra="n"), - "prior tab []": R(Key("cs-tab"))*Repeat(extra="n"), - "close tab []": R(Key("c-f4/20"))*Repeat(extra="n"), - "go to line": R(Key("c-g")), - "comment line": R(Key("c-k, c-c")), - "comment block": R(Key("c-k, c-c")), - "(un | on) comment line": R(Key("c-k/50, c-u")), - "(un | on) comment block": R(Key("c-k/50, c-u")), - "[toggle] full screen": R(Key("sa-enter")), - "(set | toggle) bookmark": R(Key("c-k, c-k")), - "next bookmark": R(Key("c-k, c-n")), - "prior bookmark": R(Key("c-k, c-p")), - "[toggle] break point": R(Key("f9")), - "step over []": R(Key("f10/50")*Repeat(extra="n")), - "step into": R(Key("f11")), - "step out [of]": R(Key("s-f11")), - "resume": R(Key("f5")), - } - extras = [ - Dictation("text"), - Dictation("mim"), - ShortIntegerRef("n", 1, 1000), - ] - defaults = {"n": 1, "mim": ""} - - -def get_rule(): - return SSMSRule, RuleDetails(name="sequel server management studio", executable="ssms") diff --git a/castervoice/rules/apps/editor/sublime.py b/castervoice/rules/apps/editor/sublime.py deleted file mode 100644 index 79700e3b0..000000000 --- a/castervoice/rules/apps/editor/sublime.py +++ /dev/null @@ -1,230 +0,0 @@ -from dragonfly import Function, Dictation, Choice, MappingRule, Repeat, ShortIntegerRef - -from castervoice.lib import navigation -from castervoice.lib.actions import Key, Text -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R -from castervoice.lib.temporary import Store, Retrieve - - -class SublimeRule(MappingRule): - mapping = { - "new file": - R(Key("c-n")), - "new window": - R(Key("cs-n")), - "open file": - R(Key("c-o")), - "open folder": - R(Key("f10, f, down:2, enter")), - "open recent": - R(Key("f10, f, down:3, enter")), - "save as": - R(Key("cs-s")), - # - "comment line": - R(Key("c-slash")), - "comment block": - R(Key("cs-slash")), - "outdent lines": - R(Key("c-lbracket")), - "join lines": - R(Key("c-j")), - "match bracket": - R(Key("c-m")), - # - "(select | sell) all": - R(Key("c-a")), - "(select | sell) scope []": - R(Key("cs-space")*Repeat(extra="n2")), - "(select | sell) brackets []": - R(Key("cs-m")*Repeat(extra="n2")), - "(select | sell) indent": - R(Key("cs-j")), - # - "find": - R(Key("c-f")), - "get all": - R(Key("a-enter")), - "replace": - R(Key("c-h")), - "replace all": - R(Key("ca-enter")), - "paste from history": - R(Key("c-k,c-v")), - "edit lines": - R(Key("cs-l")), - "edit next []": - R(Key("c-d/10"))*Repeat(extra="n3"), - "edit only next []": - R(Key("c-k,c-d/10"))*Repeat(extra="n3"), - "edit up []": - R(Key("ac-up"))*Repeat(extra="n3"), - "edit down []": - R(Key("ac-down"))*Repeat(extra="n3"), - "edit all": - R(Key("a-f3")), - # - "transform upper": - R(Key("c-k, c-u")), - "transform lower": - R(Key("c-k, c-l")), - # - "line ": - R(Key("c-g/10") + Text("%(ln1)s") + Key("enter")), - " [line] [by ]": - R(Function(navigation.action_lines)), - "[move] line down []": - R(Key("cs-down") * Repeat(extra='n3')), - "[move] line up []": - R(Key("cs-up") * Repeat(extra='n3')), - # - "go to file": - R(Key("c-p")), - "go to []": - R(Key("c-p") + Text("%(dict)s" + "%(filetype)s") + Key("enter")), - "file back []": - R(Key("c-p") + Key("down")*Repeat(extra="n2") + Key("enter")), - # - "go to word": - R(Key("c-semicolon")), - "go to symbol": - R(Key("c-r")), - "go to [symbol in] project": - R(Key("cs-r")), - "go to that": - R(Store() + Key("cs-r") + Retrieve() + Key("enter")), - "find that in project": - R(Store() + Key("cs-f") + Retrieve() + Key("enter")), - "find that": - R(Store() + Key("c-f") + Retrieve() + Key("enter")), - "command pallette": - R(Key("cs-p")), - # - "go back []": - R(Key("a-minus")*Repeat(extra="n2")), - "go forward []": - R(Key("a-plus")*Repeat(extra="n2")), - "next modification":R(Key("c-dot")), - "previous modification":R(Key("c-comma")), - # - "fold": - R(Key("cs-lbracket")), - "unfold": - R(Key("cs-rbracket")), - "unfold all": - R(Key("c-k, c-j")), - "fold [level] ": - R(Key("c-k, c-%(n2)s")), - # - "full screen": - R(Key("f11")), - "toggle side bar": - R(Key("c-k, c-b")), - "show key bindings": - R(Key("f10, p, right, k")), - "show at center": - R(Key("c-k,c-c")), - "zoom in []": - R(Key("c-equal")*Repeat(extra="n2")), - "zoom out []": - R(Key("c-minus")*Repeat(extra="n2")), - # - "(set | add) bookmark": - R(Key("c-f2")), - "next bookmark": - R(Key("f2")), - "previous bookmark": - R(Key("s-f2")), - "clear bookmarks": - R(Key("cs-f2")), - # - "set mark": R(Key("c-k,c-space")), - "select mark": R(Key("c-k,c-a")), - "swap with mark": R(Key("c-k,c-x")), - "delete mark":R(Key("c-k,c-w")), - # - "build it": R(Key("c-b")), - "build with": R(Key("cs-b")), - "build ":R(Key("c-s,a-%(nth)s,c-b")), - "build [] last":R(Key("c-s,a-1") + Key("c-pageup")*Repeat(extra="nth") + Key("c-b")), - # - "record macro": - R(Key("c-q")), - "play [back] macro []": - R(Key("cs-q/10")), - "(new | create) snippet": - R(Key("ac-n")), - # - "close tab": - R(Key("c-w")), - "next tab": - R(Key("c-pgdown")), - "previous tab": - R(Key("c-pgup")), - " tab": - R(Key("a-%(nth)s")), - "[] last tab": - R(Key("a-1") + Key("c-pageup")*Repeat(extra="nth")), - - "column ": - R(Key("as-%(cols)s")), - "focus ": - R(Key("c-%(panel)s")), - "move ": - R(Key("cs-%(panel)s")), - # - "open terminal": - R(Key("cs-t")), - "open console": - R(Key("c-`")), - } - extras = [ - Dictation("dict"), - ShortIntegerRef("ln1", 1, 1000), - ShortIntegerRef("ln2", 1, 1000), - ShortIntegerRef("n2", 1, 9), - ShortIntegerRef("n3", 1, 21), - Choice("action", navigation.actions), - Choice( - "nth", { - "first": "1", - "second": "2", - "third": "3", - "fourth": "4", - "fifth": "5", - "sixth": "6", - "seventh": "7", - "eighth": "8", - "ninth": "9", - }), - Choice("cols", { - "one": "1", - "two": "2", - "three": "3", - "grid": "5", - }), - Choice("panel", { - "one": "1", - "left": "1", - "two": "2", - "right": "2", - }), - Choice("filetype", { - "pie | python": "py", - "mark [down]": "md", - "tech": "tex", - "tommel": "toml", - }), - ] - defaults = { - "ln2": "", - "n2": 1, - "n3": 1, - "file type": "", - "nth":"1", - } - - -def get_rule(): - return SublimeRule, RuleDetails(name="sublime", executable="sublime_text", title="Sublime Text") diff --git a/castervoice/rules/apps/editor/typora.py b/castervoice/rules/apps/editor/typora.py deleted file mode 100644 index e97e8a1c5..000000000 --- a/castervoice/rules/apps/editor/typora.py +++ /dev/null @@ -1,89 +0,0 @@ -""" -__author__ = 'LexiconCode' -Command-module for Typora -Official Site "https://typora.io/" -""" -from dragonfly import Repeat, Dictation, MappingRule, ShortIntegerRef - -from castervoice.lib.actions import Key -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class TyporaRule(MappingRule): - mapping = { - # File - "new file": R(Key("c-n")), - "new window": # Listed but not implemented - R(Key("cs-n")), - # "new tab": R(Key("")), # Not implemented in Windows OS - "open file": R(Key("c-o")), - "go [to] file": R(Key("c-p")), - "reopen [closed] file": R(Key("cs-t")), - "save as": R(Key("cs-s")), - "close file": R(Key("c-w")), - # Edit - # "new paragraph": R(Key("enter")) * Repeat(extra="h"), # Caster: "shock" - "new line ": R(Key("s-enter"))*Repeat(extra="h"), - "copy [as] markdown": R(Key("cs-c")), - "delete row ": R(Key("cs-backspace"))*Repeat(extra="n"), - "select [cell | scope]": R(Key("c-e")), - "[select] word ": R(Key("c-d"))*Repeat(extra="n"), - "delete word ": R(Key("cs-d"))*Repeat(extra="n"), - # "jump [to] top": R(Key("c-home")), # Caster: "sauce wally" - # "jump [to] selection": R(Key("c-j")), # Caster: "dunce wally" - "jump [to] buttom": R(Key("c-end")), - "find": # Say "escape" to exit the find/replace context - R(Key("c-f")), - "find next": R(Key("f3")), - "replace": R(Key("c-h")), - # Paragraph - "heading ": R(Key("c-%(h)d")), - "paragraph": R(Key("c-o")), - "increase heading [level] ": R(Key("c-equal"))*Repeat(extra="h"), - "decrease heading [level] ": R(Key("c-minus"))*Repeat(extra="h"), - "table": R(Key("c-t")), # could be automated. - "code fences": R(Key("cs-k")), - "math block": R(Key("cs-m")), - "quote": R(Key("cs-q")), - "ordered list": R(Key("cs-[")), - "indent ": R(Key("cs-]"))*Repeat(extra="h"), - "out dent ": R(Key("cs-["))*Repeat(extra="h"), - # Format - "strong | bold": R(Key("c-b")), - "emphasis | italicize": R(Key("c-i")), - "underline": R(Key("c-u")), - "code": R(Key("cs-`")), - "strike": R(Key("as-5")), - "hyperlink": R(Key("c-k")), - "image": R(Key("cs-i")), - "clear [format]": R(Key("c-\\")), - # View - "[toggle] sidebar": R(Key("cs-l")), - "outline": R(Key("cs-1")), - "articles": R(Key("sc-2")), - "file tree": R(Key("cs-3")), - "source code [mode]": R(Key("c-slash")), - "focus mode": R(Key("f8")), - "typewriter [mode]": R(Key("f9")), - "[toggle] fullscreen": R(Key("f11")), - "actual size": R(Key("cs-0")), - "zoom in ": R(Key("cs-="))*Repeat(extra="n"), - "zoom out ": R(Key("cs--"))*Repeat(extra="n"), - "switch documnets": R(Key("c-tab")), - "toggle [dev] tools": R(Key("cs-f12")), - } - - extras = [ - Dictation("text"), - ShortIntegerRef("h", 0, 6), - ShortIntegerRef("n", 1, 30), - ] - - defaults = {"n": 1, "h": 1} - - -def get_rule(): - details = RuleDetails(name="tie poor a", - executable="typora") - return TyporaRule, details diff --git a/castervoice/rules/apps/editor/unity.py b/castervoice/rules/apps/editor/unity.py deleted file mode 100644 index 0aa9736a0..000000000 --- a/castervoice/rules/apps/editor/unity.py +++ /dev/null @@ -1,65 +0,0 @@ -from dragonfly import Key, MappingRule, Dictation, Choice, Text, IntegerRef -from castervoice.lib.merge.state.short import R -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails - -class UnityRule(MappingRule): - mapping = { - "show " : R(Key("c-%(window)s")), - "search []" : R(Key("c-%(searchable)s,c-f") + Text("%(dictation)s")), - "clear [search]" : R(Key("c-%(searchable)s,c-f,backspace")), - "show console" : R(Key("cs-c")), - - "max view" : R(Key("s-space")), - - "(play | stop) game" : R(Key("c-p")), - "pause game" : R(Key("cs-p")), - - "build and run" : R(Key("c-b")), - "build settings" : R(Key("cs-b")), - - "make empty [game object]" : R(Key("as-n")), - "add component" : R(Key("cs-a")), - - "align with view" : R(Key("cs-f")), - "move to view" : R(Key("ca-f")), - - "move [sibling] first" : R(Key("c-equals")), - "move [sibling] last" : R(Key("c-hyphen")), - "(set active | toggle )" : R(Key("as-a")), - - "[load] selection [<1to9>]" : R(Key("cs-%(1to9)s")), - "store selection [<1to9>]" : R(Key("ca-%(1to9)s")), - - "rename": - R(Key("f2")), - } - extras = [ - Dictation("dictation"), - IntegerRef("1to9", 1, 10), - Choice("searchable", - { - "scene" : "1", - "(hierarchy | hire)" : "4", - "project" : "5", - }), - Choice("window", - { - "scene" : "1", - "game" : "2", - "inspector" : "3", - "(hierarchy | hire)" : "4", - "project" : "5", - "animation" : "6", - "profiler" : "7", - "audio mixer" : "8", - "asset store" : "9", - "services" : "0", - }), - ] - defaults = { - "dictation":"", - "1to9": "1" - } -def get_rule(): - details = RuleDetails(name = "unity",executable="unity") - return UnityRule, details diff --git a/castervoice/rules/apps/editor/visualstudio.py b/castervoice/rules/apps/editor/visualstudio.py deleted file mode 100644 index 93e0b1f09..000000000 --- a/castervoice/rules/apps/editor/visualstudio.py +++ /dev/null @@ -1,99 +0,0 @@ -from dragonfly import Repeat, Dictation, MappingRule, ShortIntegerRef - - -from castervoice.lib.actions import Key, Text -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class VisualStudioRule(MappingRule): - mapping = { - "next tab []": - R(Key("ca-pgdown"))*Repeat(extra="n"), - "prior tab []": - R(Key("ca-pgup"))*Repeat(extra="n"), - "close tab []": - R(Key("c-f4/20"))*Repeat(extra="n"), - "(list | show) documents": - R(Key("a-w, w")), - "[focus] document (window | pane)": - R(Key("a-w, w, enter")), - "solution explorer": - R(Key("ca-l")), - "team explorer": - R(Key("c-backslash, c-m")), - "source control explorer": - R(Key("c-q") + Text("Source Control Explorer") + Key("enter")), - "quick launch": - R(Key("c-q")), - "go to line": - R(Key("c-g")), - "comment line": - R(Key("c-k, c-c")), - "comment block": - R(Key("c-k, c-c")), - "(un | on) comment line": - R(Key("c-k/50, c-u")), - "(un | on) comment block": - R(Key("c-k/50, c-u")), - "[toggle] full screen": - R(Key("sa-enter")), - "(set | toggle) bookmark": - R(Key("c-k, c-k")), - "next bookmark": - R(Key("c-k, c-n")), - "prior bookmark": - R(Key("c-k, c-p")), - "collapse to definitions": - R(Key("c-m, c-o")), - "toggle [section] outlining": - R(Key("c-m, c-m")), - "toggle all outlining": - R(Key("c-m, c-l")), - "[toggle] break point": - R(Key("f9")), - "step over []": - R(Key("f10/50")*Repeat(extra="n")), - "step into": - R(Key("f11")), - "step out [of]": - R(Key("s-f11")), - "(resume | go debug)": - R(Key("f5")), - "run tests": - R(Key("c-r, t")), - "run all tests": - R(Key("c-r, a")), - "build solution": - R(Key("cs-b")), - "get latest [version]": - R(Key("a-f, r, l")), - "(show | view) history": - R(Key("a-f, r, h")), - "compare (files | versions)": - R(Key("a-f, r, h")), - "undo (checkout | pending changes)": - R(Key("a-f, r, u")), - "[open] [go to] work item": - R(Key("a-m, g")), - "[add] [new] linked work item": - R(Key("sa-l")), - "go back": - R(Key("c--")), - "go forward": - R(Key("cs--")), - "go to definition": - R(Key("f12")), - "show refs": - R(Key("a-2")), - } - extras = [ - Dictation("text"), - Dictation("mim"), - ShortIntegerRef("n", 1, 1000), - ] - defaults = {"n": 1, "mim": ""} - - -def get_rule(): - return VisualStudioRule, RuleDetails(name="visual studio", executable="devenv") diff --git a/castervoice/rules/apps/editor/vscode_rules/__init__.py b/castervoice/rules/apps/editor/vscode_rules/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/rules/apps/editor/vscode_rules/vscode.py b/castervoice/rules/apps/editor/vscode_rules/vscode.py deleted file mode 100644 index 628336b43..000000000 --- a/castervoice/rules/apps/editor/vscode_rules/vscode.py +++ /dev/null @@ -1,155 +0,0 @@ -# thanks to Casper for contributing commands to this. -from dragonfly import Repeat, Dictation, Choice, ShortIntegerRef - -from castervoice.lib.actions import Key - -from castervoice.lib.const import CCRType -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.mergerule import MergeRule -from castervoice.lib.merge.state.short import R - - -class VSCodeCcrRule(MergeRule): - pronunciation = "visual studio code ccr" - - mapping = { - "[show] terminal": - R(Key("c-backtick")), - # Note: If you get the bad grammar grammar too complex error, move some of these commands into the non-CCR rule - # cursor/line navigation - "scroll up []": - R(Key("c-up")*Repeat(extra='n'), - rdescript="VS Code: Scroll Up One Line at a Time"), - "scroll down []": - R(Key("c-down")*Repeat(extra='n'), - rdescript="VS Code: Scroll Down One Line at a Time"), - "scroll page up []": - R(Key("a-pgup")*Repeat(extra='n'), - rdescript="VS Code: Scroll Up One Page Up at a Time"), - "scroll page down []": - R(Key("a-pgdown")*Repeat(extra='n'), - rdescript="VS Code: Scroll Down One Page Down At a Time"), - "comment [line]": - R(Key("c-slash"), rdescript="VS Code: Line Comment"), - "block comment": - R(Key("sa-a"), rdescript="VS Code: Block Comment"), - # Multi-cursor and selection - "cursor above []": - R(Key("ca-up")*Repeat(extra='n'), rdescript="VS Code: Insert Cursor Above"), - "cursor below []": - R(Key("ca-down")*Repeat(extra='n'), rdescript="VS Code: Insert Cursor Above"), - "remove cursor": - R(Key("csa-down"), rdescript="VS Code: Remove Cursor" - ), # not sure if this command works always; also try csa-up - # csa-down/up seems to work sometimes to remove 1 of the cursors - # but I don't really understand how this works - "tall cursor up": - R(Key("csa-pgup"), rdescript="VS Code: Add Cursors All The Way Up"), - "tall cursor down": - R(Key("csa-pgdown"), rdescript="VS Code: Add Cursors All The Way Down"), - - "expand []": R(Key("sa-right"), - rdescript="highlight current word(s)") * Repeat(extra='n'), - "shrink []": R(Key("sa-left"), - rdescript="shrink the previous highlighting range or unhighlight") * Repeat(extra='n'), - - # Command below requires "brackets select" extension for VS code - "select [in] brackets []": - R(Key("ca-a")*Repeat(extra='n'), - rdescript= - "VS Code: Select in between parable punctuation inclusive using 'brackets select' extension" - )*Repeat(extra='n'), - "all current selection": - R(Key("c-l"), - rdescript="VS Code: Select All Occurrences of Current Selection"), - "all current word": - R(Key("c-f2"), rdescript="VS Code: Select All Occurrences of Current Word"), - "select next []": - R(Key("c-f3")*Repeat(extra='n'), - rdescript="VS Code: Select Next Occurrence of Current Word"), - "go to next []": - R(Key("sa-right/2, c-f3, c-left/2, escape")*Repeat(extra='n'), - rdescript="VS Code: Go to Next Occurrence of Current Word"), - # may or may not want the escape afterwards to close the find box - # note the above command might sometimes be off by one so you have to say one higher - # than what you mean e.g. if the cursor is at the beginning of the word rather - # than in the middle or end, you will have to say "next word two" to get to the next word - "select prior []": - R(Key("cs-f3"), rdescript="VS Code: Select Prior Occurrence of Current Word"), - "go to prior []": - R(Key("sa-right/2, cs-f3, c-left/2, escape")*Repeat(extra='n'), - rdescript="VS Code: Go to Prior Occurrence of Current Word"), - # may or may not want the escape afterwards to close the find box - "cursor all": - R(Key("cs-l"), - rdescript="VS Code: Add Cursor to All Occurrences of Current Selection"), - "next cursor []": - R(Key("c-d")*Repeat(extra='n'), - rdescript="VS Code: Add Cursor to Next Occurrence of Current Selection"), - "skip next cursor []": - R(Key("c-k,c-d") * Repeat(extra="n"), - rdescript="VS Code: Skip Selection and Add Cursor to Next Occurrence of Current Selection", - ), - "indent []": - R(Key("c-]"), rdescript="VS Code: Indent"), - "(unindent|out dent) []": - R(Key("c-["), rdescript="VS Code: Unindent"), - "hard delete []": - R(Key("s-del"), rdescript="VS Code: Eliminates Line not Just the Text on it"), - "copy line up []": - R(Key("sa-up")*Repeat(extra='n'), rdescript="VS Code: Duplicate Line Above"), - "copy line down []": - R(Key("sa-down")*Repeat(extra='n'), - rdescript="VS Code: Duplicate Line Below"), - "switch line down []": - R(Key("a-down")*Repeat(extra='n'), - rdescript="VS Code: Switch Line With the One Below it"), - "switch line up []": - R(Key("a-up")*Repeat(extra='n'), - rdescript="VS Code: Switch Line With the One Above it"), - "match bracket": - R(Key("cs-backslash"), rdescript="VS Code: Jump to Matching Bracket"), - - # commands for selecting between parable characters using "quick and simple text selection" VScode extension (required) - # repetition of these commands by saying the number expands the selection to include the text between the next (i.e. outer) set of parable characters of the given type - "select between []": - R(Key("c-k, %(between_parables)s")*Repeat(extra='n'), - rdescript= - "VS Code: Select between parentheses noninclusive using 'quick and simple text selection' VScode extension" - ), - "select around []": - R(Key("c-k, %(around_parables)s")*Repeat(extra='n'), - rdescript= - "VS Code: Select between parentheses inclusive using 'quick and simple text selection' VScode extension" - ), - } - extras = [ - Dictation("text"), - Dictation("mim"), - ShortIntegerRef("n", 1, 100), - ShortIntegerRef("m", 1, 10), - Choice( - "between_parables", { - "prekris": "lparen", - "brax": "lbracket", - "curly": "lbrace", - "angle": "langle", - "single": "squote", - "quote": "dquote", - }), - Choice("around_parables", { - "prekris": "rparen", - "brax": "rbracket", - "curly": "rbrace", - "angle": "rangle", - }), - ] - - defaults = {"n": 1, "mim": "", "text": ""} - - -def get_rule(): - details = RuleDetails(executable="code", - title="Visual Studio Code", - ccrtype=CCRType.APP) - return VSCodeCcrRule, details diff --git a/castervoice/rules/apps/editor/vscode_rules/vscode2.py b/castervoice/rules/apps/editor/vscode_rules/vscode2.py deleted file mode 100644 index 4f17640de..000000000 --- a/castervoice/rules/apps/editor/vscode_rules/vscode2.py +++ /dev/null @@ -1,313 +0,0 @@ -from dragonfly import Function, Repeat, Choice, Dictation, MappingRule, Pause, ShortIntegerRef - -from castervoice.lib.actions import Key, Mouse - -from castervoice.lib import navigation -from castervoice.lib.actions import Text -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -def _find_nth_token(text, n, direction): - Key("c-f").execute() - Text("%(text)s").execute({"text": text}) - if direction == "reverse": - print("yeah? %(n)d") - Key("s-enter:%(n)d").execute() - else: - Key("enter:%(n)d").execute() - print("no? %(n)d") - Key('escape').execute() - - -class VSCodeNonCcrRule(MappingRule): - mapping = { - # Moving around a file - "[(go to | jump | jump to)] line ": - R(Key("c-g") + Text("%(n)d") + Key("enter")), - " [line] [by ]": - R(Function(navigation.action_lines)), - - "go back []": - R(Key("a-left") * Repeat(extra='n')), - "go forward []": - R(Key("a-right")) * Repeat(extra="n"), - - # Display - # note that most of these can be turned on/off with the same command - "[toggle] full screen": - R(Key("f11")), - "toggle orientation": - R(Key("sa-0")), - "zoom in []": - R(Key("c-equal") * Repeat(extra='n')), - "zoom out []": - R(Key("c-minus") * Repeat(extra='n')), - "sidebar": - R(Key("c-b")), - "explorer": - R(Key("cs-e")), - "source control": - R(Key("cs-g")), - "keyboard shortcuts": - R(Key("c-k, c-s")), - "key mappings": - R(Key("c-k, c-s:2")), - "settings": - R(Key("a-f, p, s, enter"), rdescript="VS Code: User/workspace Settings"), - "snippets": - R(Key("a-f, p, s:2, enter"), rdescript="VS Code: User Snippets"), - "extensions": - R(Key("cs-x")), - "search details": - R(Key("cs-j")), - "output panel": - R(Key("cs-u")), - "markdown preview": - R(Key("cs-v")), - "markdown preview side": - R(Key("c-k, v")), - "Zen mode": - # note: use esc esc to exit - R(Key("c-k, z")), - - # File Management - "copy path": - R(Key("c-k, p")), - "[open] command palette []": - R(Key("cs-p") + Text("%(text)s"), rdescript="VS Code: Command Palette"), - "(open file | go to [tab]) []": - R(Key("c-p") + Text("%(text)s"), rdescript="VS Code: Go to File without using dialogbox"), - "open project []": - R(Key("c-r") + Pause("30") + Text("%(text)s")), - "open dialogue": - R(Key("c-o"), rdescript="VS Code: open file dialogbox"), - "open folder": - R(Key("c-k, c-o"), rdescript="VS Code: Open folder"), - "Save and close": - R(Key("c-s/10, c-w")), - "new file": - R(Key("c-n")), - "new window": - R(Key("cs-n")), - "close window": - R(Key("a-f4")), - "close workspace": - R(Key("c-k, f")), - "close editor": - R(Key("c-f4")), - "save as": - R(Key("cs-s")), - "save all": - R(Key("c-k, s")), - "next tab []": - R(Key("c-pgdown") * Repeat(extra='n')), - "previous tab []": - R(Key("c-pgup") * Repeat(extra='n')), - "close tab []": - R(Key("c-f4/20") * Repeat(extra='n')), - "(recent | R) tab []": - R(Key("c-tab") * Repeat(extra='n')), - "reopen tab []": - R(Key("cs-t") * Repeat(extra='n')), - "Exit preview": - R(Key("space, c-z")), - "keep [preview] open": - R(Key("c-k, enter")), - "windows explorer here": - R(Key("c-k, r")), - "show active file in new window": - R(Key("c-k, o")), - - # Search - "(search | find)": - R(Key("c-f")), - "replace": - R(Key("c-h")), - "find in files": - R(Key("cs-f")), - "replace in files": - R(Key("cs-h")), - "next find": - R(Key("f3")), - "(prior | previous) find": - R(Key("s-f3")), - "select all occurrences": - R(Key("a-enter")), - - "toggle case sensitive": - R(Key("a-c"), rdescript="VS Code: Toggle Find Case Sensitive"), - "toggle regex": - R(Key("a-r"), rdescript="VS Code: Toggle Find Regular Expressions"), - "toggle whole word": - R(Key("a-w"), rdescript="VS Code: Toggle Find Whole Word"), - - "(find | jump [to]) next ": - R(Function(_find_nth_token, n=1, direction="forward")), - "(find | jump [to]) previous ": - R(Function(_find_nth_token, n=1, direction="reverse")), - "show all symbols": - R(Key("c-t")), - "go to symbol": - R(Key("cs-o")), - - # Editor Management - "close editor": - R(Key("c-w")), - "close folder": - R(Key("c-k, f")), - "split editor": - R(Key("c-backslash")), - "next pane": - R(Key("c-k, c-right")), - "(prior | previous | un) pane": - R(Key("c-k, c-left")), - "move tab left": - R(Key("ca-left"), - rdescript="VS Code: Move the current tab to the editor pane on the left."), - "move tab right": - R(Key("ca-right"), - rdescript="VS Code: Move the current tab to the editor pane on the right."), - "shift group left": - R(Key("c-k, left"), - rdescript="VS Code: Shift Current Group of Tabs to the Left E.g. Swap with Pane to the Left"), - "shift group right": - R(Key("c-k, right"), - rdescript="VS Code: Shift Current Group of Tabs to the Right E.g. Swap with Pane to the Right" - ), - " tab": - R(Key("c-%(nth)s")), - - # Languages Editing - "go to definition": - R(Key("f12")), - "go to required definition": - R(Key("c-f12:2, c-right:5, left/50, f12")), - "peak definition": - R(Key("a-f12")), - "trigger parameter hints": - R(Key("cs-space")), - "format (that | selection)": - R(Key("c-k, c-f")), - "format (doc | document)": - R(Key("sa-f")), - "(definition to side | side def)": - R(Key("c-k, f12")), - "show references": - R(Key("s-f12")), - "rename symbol": - R(Key("f2")), - "(trim white)": - R(Key("c-k, c-x")), - "change file language": - R(Key("c-k, m")), - - # Debugging - "debug": - R(Key("cs-d")), - "[toggle] breakpoint": - R(Key("f9")), - "step over []": - R(Key("f10/50") * Repeat(extra='n')), - "step into": - R(Key("f11")), - "step out [of]": - R(Key("s-f11")), - "resume": - R(Key("f5")), - "stopper": - R(Key("s-f5")), - "continue": - R(Key("f5"), rdescript="VS Code: Start/Continue"), - "(show hover|mouse hover|hover mouse)": - R(Key("c-k, c-i"), - rdescript="Show the little box as if you are hovering your mouse over the place where the cursor (As opposed to the mouse pointer) currently is" - ), - "[show] problems [panel]": - R(Key("cs-m")), - "next error": - R(Key("f8")), # doesn't seem to be working properly - "(prior | previous) error": - R(Key("s-f8")), - "toggle tab moves focus": - R(Key("c-m")), - - # Integrated Terminal - - "new terminal": - R(Key("cs-backtick")), - "terminal scroll up": - R(Key("c-up")), - "terminal scroll down": - R(Key("c-down")), - "terminal page up": - R(Key("s-pgup")), - "terminal page down": - R(Key("s-pgdown")), - "altar kick": - R(Key("alt:down") + Mouse("left") + Key("alt:up")), - - # Collapsing - "(fold | collapse) region": - R(Key("cs-lbracket")), - "(unfold | uncollapse) region": - R(Key("cs-rbracket")), - "(fold | collapse) [all] subregions": - R(Key("c-k, c-lbracket")), - "(unfold | uncollapse) [all] subregions": - R(Key("c-k, c-rbracket")), - "(fold | collapse) [all] regions": - R(Key("c-k, c-0")), - "(unfold | uncollapse) [all] regions": - R(Key("c-k, c-j")), - "toggle word wrap": - R(Key("a-z")), - - "run this line": - R(Key("csa-l")), - "join line": - R(Key("f1") + Text("join lines") + Key("enter")), - - # requires gitlens extension - "toggle blame": - R(Key("cs-g, b")), - "lens commit details": - R(Key("cs-g, c")), - "lens file history": - R(Key("cs-g, h")), - "lens repo status": - R(Key("cs-g, s")), - "toggle git lens": - R(Key("cs-g, s-b")), - - # requires bookmark extension - "mark (prev | prior | previous)": - R(Key("ca-j")), - "mark next": - R(Key("ca-l")), - } - extras = [ - Dictation("text"), - Dictation("mim"), - ShortIntegerRef("ln1", 1, 1000), - ShortIntegerRef("ln2", 1, 1000), - ShortIntegerRef("n", 1, 1000), - Choice("action", navigation.actions), - Choice( - "nth", { - "first": "1", - "second": "2", - "third": "3", - "fourth": "4", - "fifth": "5", - "sixth": "6", - }), - ] - defaults = {"n": 1, "ln2": "", "mim": "", "text": ""} - - -def get_rule(): - details = RuleDetails(name="Visual Studio Code", - executable="code", - title="Visual Studio Code") - return VSCodeNonCcrRule, details diff --git a/castervoice/rules/apps/file_manager/__init__.py b/castervoice/rules/apps/file_manager/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/rules/apps/file_manager/fman.py b/castervoice/rules/apps/file_manager/fman.py deleted file mode 100644 index 35a8ad11e..000000000 --- a/castervoice/rules/apps/file_manager/fman.py +++ /dev/null @@ -1,51 +0,0 @@ -from dragonfly import Pause, Choice, MappingRule, ShortIntegerRef - -from castervoice.lib.actions import Key, Text - -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class fmanRule(MappingRule): - mapping = { - "copy": R(Key("f5")), - "deselect": R(Key("c-d")), - "edit": R(Key("f4")), - "explorer": R(Key("f10")), - # Set these yourself and add them to the Choice at the bottom - # Requires the favourites plug-in - "go ": R(Key("c-0") + Pause("15") + Text("%(fav)s") + Key("enter")), - "go see": R(Key("c-p") + Pause("15") + Text("c") + Key("enter")), - "go to": R(Key("c-p")), - "move": R(Key("f6")), - "new file": R(Key("s-f4")), - "new folder": R(Key("f7")), - "open left": R(Key("c-left")), - "open right": R(Key("c-right")), - "properties": R(Key("a-enter")), - "refresh": R(Key("c-r")), - "rename": R(Key("s-f6")), - "search": R(Key("cs-f")), - "set favourite": R(Key("s-f")), - "show favourites": R(Key("c-0")), - "(show | hide) hidden": R(Key("c-dot")), - "sort [by] name": R(Key("c-f1")), - "sort [by] size": R(Key("c-f2")), - "sort [by] (modified | date)": R(Key("c-f3")), - "(stoosh | copy) path": R(Key("f11")), - "terminal": R(Key("f9")), - "command pallette": R(Key("cs-p")), - } - extras = [ - ShortIntegerRef("num", 1, 4), - Choice("fav", { - "example favourite": "ef", - }), - ] - defaults = { - "num": 1, - } - - -def get_rule(): - return fmanRule, RuleDetails(name="F man", executable="fman", title="fman") diff --git a/castervoice/rules/apps/file_manager/totalcmd_rules/__init__.py b/castervoice/rules/apps/file_manager/totalcmd_rules/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/rules/apps/file_manager/totalcmd_rules/totalcmd.py b/castervoice/rules/apps/file_manager/totalcmd_rules/totalcmd.py deleted file mode 100644 index f680ae1e1..000000000 --- a/castervoice/rules/apps/file_manager/totalcmd_rules/totalcmd.py +++ /dev/null @@ -1,34 +0,0 @@ -from dragonfly import MappingRule -from castervoice.lib.actions import Key -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class TotalCommanderRule(MappingRule): - mapping = { - "find [in] files": R(Key('a-f7')), - "view": R(Key('f3')), - "edit": R(Key('f4')), - "copy": R(Key('f5')), - "move": R(Key('f6')), - "new directory": R(Key('f7')), - "wipe": R(Key('s-delete')), - "FTP": R(Key('c-f')), - "synchronize": R(Key('a-c, y')), - "sort by name": R(Key('c-f3')), - "sort by extension": R(Key('c-f4')), - "sort by date": R(Key('c-f5')), - "sort by size": R(Key('c-f6')), - "file filter": R(Key('c-f12')), - "new tab": R(Key('c-t')), - "multi rename": R(Key('c-m')), - "display thumbnails": R(Key('cs-f1')), - "display list": R(Key('c-f1')), - "display details": R(Key('c-f2')), - "display file tree": R(Key('c-f8')), - } - - -def get_rule(): - return TotalCommanderRule, RuleDetails(name="total commander", executable=["totalcmd", "totalcmd64"]) - diff --git a/castervoice/rules/apps/file_manager/totalcmd_rules/totalcmd2.py b/castervoice/rules/apps/file_manager/totalcmd_rules/totalcmd2.py deleted file mode 100644 index 905da603e..000000000 --- a/castervoice/rules/apps/file_manager/totalcmd_rules/totalcmd2.py +++ /dev/null @@ -1,23 +0,0 @@ -from dragonfly import MappingRule - -from castervoice.lib.actions import Key -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class SyncDirsRule(MappingRule): - mapping = { - "compare files": R(Key('c-f3')), - "copy left": R(Key('c-l')), - "copy right": R(Key('c-r')), - "view right": R(Key('s-f3')), - "remove selection": R(Key('c-m')), - "synchronize": R(Key('a-c')), - } - - -def get_rule(): - details = RuleDetails(name="total commander synchronize directories", - executable=["totalcmd", "totalcmd64"], - title='synchronize directories') - return SyncDirsRule, details diff --git a/castervoice/rules/apps/git_clients/__init__.py b/castervoice/rules/apps/git_clients/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/rules/apps/git_clients/githubdesktop.py b/castervoice/rules/apps/git_clients/githubdesktop.py deleted file mode 100644 index f326462c8..000000000 --- a/castervoice/rules/apps/git_clients/githubdesktop.py +++ /dev/null @@ -1,51 +0,0 @@ -from dragonfly import Repeat, MappingRule, ShortIntegerRef - -from castervoice.lib.actions import Key - -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class GitHubDeskRule(MappingRule): - mapping = { - "new repository": R(Key("c-n")), - "add local repository": R(Key("c-o")), - "clone repository": R(Key("c-o")), - "options": R(Key("c-comma")), - - "changes": R(Key("c-1")), - "history": R(Key("c-2")), - "(repositories | repository list)": R(Key("c-t")), - "branches [list]": R(Key("c-b")), - - "zoom in []": R(Key("c-equals"))*Repeat(extra="n"), - "zoom out []": R(Key("c-minus"))*Repeat(extra="n"), - "reset zoom": R(Key("c-0")), - - "push [repository]": R(Key("c-p")), - "pull [repository]": R(Key("cs-p")), - "remove repository": R(Key("c-delete")), - "view on github": R(Key("cs-g")), - "(terminal | command prompt)": R(Key("c-backtick")), - "explorer": R(Key("cs-f")), - "edit": R(Key("cs-a")), - - "new branch": R(Key("cs-n")), - "rename branch": R(Key("cs-r")), - "delete branch": R(Key("cs-d")), - - "update from master": R(Key("cs-u")), - "compare to branch": R(Key("cs-b")), - "merge into current [branch]": R(Key("cs-m")), - - "compare on github": R(Key("cs-c")), - "[create] pull request": R(Key("c-r")), - } - extras = [ - ShortIntegerRef("n", 1, 10), - ] - defaults = {"n": 1} - - -def get_rule(): - return GitHubDeskRule, RuleDetails(name="github desktop", executable="GitHubDesktop") diff --git a/castervoice/rules/apps/git_clients/kdiff3.py b/castervoice/rules/apps/git_clients/kdiff3.py deleted file mode 100644 index 2c98efaef..000000000 --- a/castervoice/rules/apps/git_clients/kdiff3.py +++ /dev/null @@ -1,20 +0,0 @@ -from dragonfly import Dictation, MappingRule, ShortIntegerRef -from castervoice.lib.actions import Key -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -class KDiff3Rule(MappingRule): - mapping = { - "refresh": R(Key("f5")), - } - extras = [ - Dictation("text"), - Dictation("mim"), - ShortIntegerRef("n", 1, 1000), - ] - defaults = {"n": 1, "mim": ""} - - -def get_rule(): - return KDiff3Rule, RuleDetails(name="K diff", executable="kdiff3") diff --git a/castervoice/rules/apps/microsoft_office/__init__.py b/castervoice/rules/apps/microsoft_office/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/rules/apps/microsoft_office/excel.py b/castervoice/rules/apps/microsoft_office/excel.py deleted file mode 100644 index 7dc65f78e..000000000 --- a/castervoice/rules/apps/microsoft_office/excel.py +++ /dev/null @@ -1,101 +0,0 @@ -""" -Command-module for Microsoft Excel -You also can find some good vocola commands for Excel on Mark Lillibridge's Github: -https://github.com/mdbridge/bit-bucket/tree/master/voice/my_commands/commands -Alex Boche 2019 -""" - -# this function takes a dictionary and returns a dictionary whose keys are sequences of keys of the original dictionary -# and whose values our the corresponding sequences of values of the original dictionary -from dragonfly import Repeat, Dictation, Choice, MappingRule, Repetition, ShortIntegerRef - -from castervoice.rules.core.alphabet_rules import alphabet_support # Manually change in port in if in user directory -from castervoice.lib.actions import Text, Key -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - -class ExcelRule(MappingRule): - mapping = { - "next sheet []": - R(Key("c-pgdown"))*Repeat(extra='n'), - "(prior | previous) sheet []": - R(Key("c-pgup"))*Repeat(extra='n'), - "[select] cell ": - R(Key("c-g") + Text("%(column_1)s%(row_1)s") + Key("enter")), - "select through ": - R(Key("c-g") + Text("%(column_1)s%(row_1)s:%(column_2)s%(row_2)s") + - Key("enter")), - "go to cell": - R(Key("c-g")), - "select current column": - R(Key("c-space")), - "select current row": - R(Key("s-space")), - "top of column": - R(Key("c-up")), - "beginning of row": - R(Key("c-left")), - "insert stuff": - R(Key("cs-plus")), - "insert row": - R(Key("cs-plus, a-r, enter")), - "insert column": - R(Key("cs-plus, a-c, enter")), - "insert cell [to the] left": - R(Key("cs-plus, a-i, enter")), - "insert cell above": - R(Key("cs-plus, a-d, enter")), - "insert pivot table": - R(Key("a-n, v")), - "insert pivot chart": - R(Key("a-n, s, z, c")), - "add-ins": - R(Key("a-t, i")), - "add border": - R(Key("cs-ampersand")), - "arrange Windows": - R(Key("a-w/10, a")), - "auto sum": - R(Key("a-equal")), - "freeze panes": - R(Key("a-w, f")), - - # From Mark Lillibridge regarding the edit cell command below: - # There are at least two modes, edit (blue background) and enter (yellow background). - # In enter mode for formulas, arrow keys select a - # cell (range if shifted), whereas in edit mode, they move the cursor - # inside the formula. For non-formulas, in enter mode, the arrows - # finished entering the current cell and move to another cell. - # - # and "edit cell" initially switch to edit mode then - # toggle thereafter for the given cell. Typing initially puts you in - # enter mode. - # - - # edit cell: always edits directly in cell (blue background) - - # - # this has the effect of pressing F2 without DNS around. - # - # Want "edit directly in cell" option turned off: - # Office button->advanced-> turn off allow editing directly in cells - # (Dragon handles edit in cell directly badly) - # - # First time, edits current cell via formula bar. Unlike with - # editing directly in a cell, this highlights ranges and cells used. - "toggle edit cell": - R(Key("f2")), - } - extras = [ - Dictation("dict"), - ShortIntegerRef("n", 1, 10), - ShortIntegerRef("row_1", 1, 100), - ShortIntegerRef("row_2", 1, 100), - # change max to 3 if you want sequences of lentgh three and so on - Repetition(Choice("alphabet1", alphabet_support.caster_alphabet()), min=1, max=2, name="column_1"), - Repetition(Choice("alphabet2", alphabet_support.caster_alphabet()), min=1, max=2, name="column_2") - ] - defaults = {"n": 1, "dict": ""} - -def get_rule(): - return ExcelRule, RuleDetails(name="excel", executable="excel") \ No newline at end of file diff --git a/castervoice/rules/apps/microsoft_office/outlook.py b/castervoice/rules/apps/microsoft_office/outlook.py deleted file mode 100644 index ad872d698..000000000 --- a/castervoice/rules/apps/microsoft_office/outlook.py +++ /dev/null @@ -1,131 +0,0 @@ -from dragonfly import Function, Repeat, Dictation, Choice, MappingRule, ShortIntegerRef - -from castervoice.lib.actions import Key, Text -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R - - -def capitalize(text): - output = str(text).title() - Text(output).execute() - - -class OutlookRule(MappingRule): - mapping = { - # create new thing - "new (appointment | event)": R(Key("sc-a")), - "new contact": R(Key("cs-c")), - "new folder": R(Key("cs-e")), - "advanced (search| find)": R(Key("cs-f")), - "new office document": R(Key("cs-h")), - "(inbox | go to inbox)": R(Key("cs-i")), - "new journal entry": R(Key("cs-j")), - "new task": R(Key("cs-k")), - "new contact group": R(Key("cs-l")), - "(new message| new mail)": R(Key("cs-m")), - "new note": R(Key("cs-n")), - "open the new search folder window": R(Key("cs-p")), - "new meeting request": R(Key("cs-q")), - "new task request": R(Key("cs-u")), - - # new message window - "to field": R(Key("a-dot")), - "c c field": R(Key("a-c")), - "subject [field]": R(Key("a-u")), - "subject ": R(Key("a-u") + Function(capitalize) + Key("tab")), - "attach file": R(Key("n, a, f")), - "add to dictionary": R(Key("s-f10/2, a")), - "click send message": R(Key("a-s")), # be careful - "find and replace": R(Key("c-h")), - "check names": R(Key("c-k")), - "spell check": R(Key("f7")), - "save as": R(Key("f12")), # only in mail view - - # folders pane - "expand [that]": R(Key("asterisk")), - "collapse [that]": R(Key("minus")), - - # folders navigation - # some of these may be user dependent, depends on the order of your folders - # which you can inspect by pressing control y - # also I think some of these are built into Dragon - "[go to] sent mail": R(Key("c-y/10, s, enter")), - "go to drafts": R(Key("c-y/10, d, enter")), - "go to trash": R(Key("c-y/10, t, enter")), - "go to spam": R(Key("c-y/10, s:2, enter")), - "go to starred": R(Key("c-y/10, s:3, enter")), - "go to important": R(Key("c-y/10, i:2, enter")), - "go to outbox": R(Key("cs-o")), - - # center pane - "sort by []": R(Key("a-v/5, a, b/5, %(sort_by)s")), - "reverse sort": R(Key("a-v, r, s")), - "block sender": R(Key("a-h/3, j/3, b")), - "search [bar] []": R(Key("c-e") + Text("%(dict)s")), - "(message list | messages)": R(Key("tab:3")), - "(empty | clear) search [bar]": R(Key("c-e, c-a, del/3, escape")), - # from the search bar to get the focus into the messages is three tabs - # pressing escape also seems to work. - "refresh [mail]": R(Key("f9")), - - # reading pane - "open attachment": R(Key("s-tab, enter")), - "[open] attachment menu": R(Key("s-tab, right")), - "next message []": R(Key("s-f6/10, down"))*Repeat(extra='n'), - "(prior | previous) message []": R(Key("s-f6/20, up"))*Repeat(extra='n'), - "[select] next link": R(Key("tab")), - "[select] (previous | prior) link": R(Key("s-tab")), - - # calendar - "workweek [view]": R(Key("ca-2")), - "full week [view]": R(Key("ca-3")), - "month view": R(Key("ca-4")), - - # message shortcuts - "reply []": R(Key("c-r") + Text("%(dict)s")), - "reply all []": R(Key("cs-r") + Text("%(dict)s")), - "forward": R(Key("c-f")), - "Mark as read": R(Key("c-q")), - "Mark as unread": R(Key("c-u")), - "(folder | go to folder)": R(Key("c-y")), - - # navigation - "next pane []": R(Key("f6"))*Repeat(extra='n'), - "(un|prior|previous) pane []": R(Key("s-f6"))*Repeat(extra='n'), - "mail view": R(Key("c-1")), - "calendar": R(Key("c-2")), - "contacts": R(Key("c-3")), - "tasks": R(Key("c-4")), - "go to notes": R(Key("c-5")), - "folder list": R(Key("c-6")), - "find contact": R(Key("f11")), - "address book": R(Key("cs-a")), - "next open message": R(Key("c-dot")), - "(prior | previous) open message": R(Key("c-comma")), - "previous view": R(Key("a-left")), - "next view": R(Key("a-right")), - - # misc - "[go] back": R(Key("a-left")), - } - extras = [ - Dictation("dict"), - Dictation("text"), - ShortIntegerRef("n", 1, 100), - Choice( - "sort_by", { - "date": "d", - "from": "f", - "to": "t", - "size": "s", - "subject": "j", - "type": "t", - "attachments": "c", - "account": "o", - }), - ] - defaults = {"n": 1, "dict": "", "text": "", "sort_by": ""} - - -def get_rule(): - return OutlookRule, RuleDetails(name="outlook", executable="outlook") diff --git a/castervoice/rules/apps/mouse_grids/__init__.py b/castervoice/rules/apps/mouse_grids/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/castervoice/rules/apps/mouse_grids/griddouglas.py b/castervoice/rules/apps/mouse_grids/griddouglas.py deleted file mode 100644 index e3cab8e3c..000000000 --- a/castervoice/rules/apps/mouse_grids/griddouglas.py +++ /dev/null @@ -1,105 +0,0 @@ -import time -from dragonfly import Function, Choice, MappingRule, ShortIntegerRef -from dragonfly.actions.mouse import get_cursor_position -from castervoice.lib import control -from castervoice.lib.navigation import Grid -from castervoice.lib.actions import Mouse -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R -from castervoice.rules.ccr.standard import SymbolSpecs - - -def send_input(x, y, action): - s = control.nexus().comm.get_com("grids") - s.move_mouse(int(x), int(y)) - int_a = int(action) - if (int_a == 0) | (int_a == 1) | (int_a == 2) | (int_a == -1): - s.kill() - Grid.wait_for_grid_exit() - if int_a == 0: - Mouse("left").execute() - if int_a == 1: - Mouse("left:2").execute() - elif int_a == 2: - Mouse("right").execute() - - -def send_input_select(x1, y1, x2, y2): - s = control.nexus().comm.get_com("grids") - s.move_mouse(int(x1), int(y1)) - _x1, _y1 = get_cursor_position() - s.move_mouse(int(x2), int(y2)) - _x2, _y2 = get_cursor_position() - s.kill() - Grid.wait_for_grid_exit() - drag_from_to(_x1, _y1, _x2, _y2) - - -def send_input_select_short(x1, y1, x2): - send_input_select(x1, y1, x2, y1) - - -def drag_from_to(x1, y1, x2, y2): - Mouse("[{}, {}]".format(x1, y1)).execute() - time.sleep(0.1) - Mouse("left:down").execute() - Mouse("[{}, {}]".format(x2, y2)).execute() - time.sleep(0.1) - Mouse("left:up").execute() - - -x1 = None -x2 = None -y1 = None -y2 = None - - -def store_first_point(): - global x1, y1 - x1, y1 = get_cursor_position() - - -def select_text(): - global x1, y1, x2, y2 - x2, y2 = get_cursor_position() - s = control.nexus().comm.get_com("grids") - s.kill() - Grid.wait_for_grid_exit() - drag_from_to(x1, y1, x2, y2) - - -class DouglasGridRule(MappingRule): - mapping = { - " [by] []": - R(Function(send_input)), - " [by] (grab | select) [by] ": - R(Function(send_input_select)), - " [by] (grab | select) ": - R(Function(send_input_select_short)), - "squat {weight=2}": - R(Function(store_first_point)), - "bench {weight=2}": - R(Function(select_text)), - SymbolSpecs.CANCEL + " {weight=2}": - R(Function(Grid.kill)), - } - extras = [ - ShortIntegerRef("x", 0, 300), - ShortIntegerRef("y", 0, 300), - ShortIntegerRef("x1", 0, 300), - ShortIntegerRef("y1", 0, 300), - ShortIntegerRef("x2", 0, 300), - ShortIntegerRef("y2", 0, 300), - Choice("action", { - "kick": 0, - "kick (double | 2)": 1, - "psychic": 2, - "move": 3, - }), - ] - defaults = { - "action": -1, - } - -def get_rule(): - return DouglasGridRule, RuleDetails(name="douglas grid rule", function_context = lambda: Grid.is_grid_active("douglas")) diff --git a/castervoice/rules/apps/mouse_grids/gridlegion.py b/castervoice/rules/apps/mouse_grids/gridlegion.py deleted file mode 100644 index 40b241476..000000000 --- a/castervoice/rules/apps/mouse_grids/gridlegion.py +++ /dev/null @@ -1,86 +0,0 @@ -import time -from dragonfly import Function, Choice, MappingRule, Mouse, ShortIntegerRef -from castervoice.lib import control -from castervoice.lib.navigation import Grid -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R -from castervoice.rules.ccr.standard import SymbolSpecs - - -def send_input(n, action): - s = control.nexus().comm.get_com("grids") - - int_a = int(action) - response = None - - if int_a != 2: - s.go(str(n)) - elif int_a == 2: - response = s.retrieve_data_for_highlight(str(int(n))) - - s.kill() - Grid.wait_for_grid_exit() - - if int_a == 0: - Mouse("left").execute() - elif int_a == 1: - Mouse("right").execute() - elif int_a == 2: - x1 = response["l"] + 2 - x2 = response["r"] - y = response["y"] - Mouse("[{}, {}]".format(x1, y)).execute() - time.sleep(0.1) - Mouse("left:down").execute() - Mouse("[{}, {}]".format(x2, y)).execute() - time.sleep(0.1) - Mouse("left:up").execute() - - -def drag_highlight(n1, n2): - s = control.nexus().comm.get_com("grids") - response1 = s.retrieve_data_for_highlight(str(int(n1))) - response2 = s.retrieve_data_for_highlight(str(int(n2))) - s.kill() - Grid.wait_for_grid_exit() - x11 = response1["l"] + 2 - y1 = response1["y"] - x22 = response2["r"] - y2 = response2["y"] - Mouse("[{}, {}]".format(x11, y1)).execute() - time.sleep(0.1) - Mouse("left:down").execute() - Mouse("[{}, {}]".format(x22, y2)).execute() - time.sleep(0.1) - Mouse("left:up").execute() - - -class LegionGridRule(MappingRule): - - mapping = { - " []": - R(Function(send_input)), - "refresh": - R(Function(Grid.mouse_alternates, mode="legion")), - SymbolSpecs.CANCEL + " {weight=2}": - R(Function(Grid.kill)), - " (select | light) ": - R(Function(drag_highlight)), - } - extras = [ - Choice("action", { - "kick": 0, - "psychic": 1, - "select | light": 2, - }), - ShortIntegerRef("n", 0, 1000), - ShortIntegerRef("n1", 0, 1000), - ShortIntegerRef("n2", 0, 1000), - ] - defaults = { - "action": -1, - } - - -def get_rule(): - return LegionGridRule, RuleDetails(name="legion grid rule", function_context=lambda: Grid.is_grid_active("legion")) diff --git a/castervoice/rules/apps/mouse_grids/gridrainbow.py b/castervoice/rules/apps/mouse_grids/gridrainbow.py deleted file mode 100644 index 6e0b8e54a..000000000 --- a/castervoice/rules/apps/mouse_grids/gridrainbow.py +++ /dev/null @@ -1,137 +0,0 @@ -import time -from dragonfly import Function, Choice, MappingRule, ShortIntegerRef -from dragonfly.actions.mouse import get_cursor_position -from castervoice.lib import control -from castervoice.lib.navigation import Grid -from castervoice.lib.actions import Mouse -from castervoice.lib.ctrl.mgr.rule_details import RuleDetails -from castervoice.lib.merge.state.short import R -from castervoice.rules.ccr.standard import SymbolSpecs - - -def send_input(pre, color, n, action): - s = control.nexus().comm.get_com("grids") - s.move_mouse(int(pre), int(color), int(n)) - int_a = int(action) - if (int_a == 0) | (int_a == 1) | (int_a == 2) | (int_a == -1): - s.kill() - Grid.wait_for_grid_exit() - time.sleep(0.1) - if int_a == 0: - Mouse("left").execute() - if int_a == 1: - Mouse("left:2").execute() - elif int_a == 2: - Mouse("right").execute() - - -def send_input_select(pre1, color1, n1, pre2, color2, n2): - s = control.nexus().comm.get_com("grids") - s.move_mouse(int(pre1), int(color1), int(n1)) - _x1, _y1 = get_cursor_position() - s.move_mouse(int(pre2), int(color2), int(n2)) - _x2, _y2 = get_cursor_position() - s.kill() - Grid.wait_for_grid_exit() - drag_from_to(_x1, _y1, _x2, _y2) - - -def send_input_select_short(pre1, color1, n1, n2): - send_input_select(pre1, color1, n1, pre1, color1, n2) - - -def drag_from_to(x1, y1, x2, y2): - Mouse("[{}, {}]".format(x1, y1)).execute() - time.sleep(0.1) - Mouse("left:down").execute() - Mouse("[{}, {}]".format(x2, y2)).execute() - time.sleep(0.1) - Mouse("left:up").execute() - - -x1 = None -x2 = None -y1 = None -y2 = None - - -def store_first_point(): - global x1, y1 - x1, y1 = get_cursor_position() - - -def select_text(): - global x1, y1, x2, y2 - x2, y2 = get_cursor_position() - s = control.nexus().comm.get_com("grids") - s.kill() - Grid.wait_for_grid_exit() - drag_from_to(x1, y1, x2, y2) - - -class RainbowGridRule(MappingRule): - - mapping = { - "[
]   []":
-            R(Function(send_input)),
-        "[]   (grab | select) []  ":
-            R(Function(send_input_select)),
-        "[]   (grab | select) ":
-            R(Function(send_input_select_short)),
-        "squat {weight=2}":
-            R(Function(store_first_point)),
-        "bench {weight=2}":
-            R(Function(select_text)),
-        SymbolSpecs.CANCEL + " {weight=2}":
-            R(Function(Grid.kill)),
-    }
-    extras = [
-        ShortIntegerRef("pre", 0, 9),
-        ShortIntegerRef("pre1", 0, 9),
-        ShortIntegerRef("pre2", 0, 9),
-        Choice(
-            "color", {
-                "(red | rot)": 0,
-                "(orange | tan | brown | braun)": 1,
-                "(yellow | gelb)": 2,
-                "(green | gruen)": 3,
-                "(blue | blau)": 4,
-                "(purple | lila)": 5
-            }),
-        Choice(
-            "color1", {
-                "(red | rot)": 0,
-                "(orange | tan | brown | braun)": 1,
-                "(yellow | gelb)": 2,
-                "(green | gruen)": 3,
-                "(blue | blau)": 4,
-                "(purple | lila)": 5
-            }),
-        Choice(
-            "color2", {
-                "(red | rot)": 0,
-                "(orange | tan | brown | braun)": 1,
-                "(yellow | gelb)": 2,
-                "(green | gruen)": 3,
-                "(blue | blau)": 4,
-                "(purple | lila)": 5
-            }),
-        ShortIntegerRef("n", 0, 100),
-        ShortIntegerRef("n1", 0, 100),
-        ShortIntegerRef("n2", 0, 100),
-        Choice("action", {
-            "kick": 0,
-            "kick (double | 2)": 1,
-            "psychic": 2,
-            "move": 3,
-        }),
-    ]
-    defaults = {
-        "pre": 0,
-        "pre1": 0,
-        "pre2": 0,
-        "action": -1,
-    }
-
-def get_rule():
-    return RainbowGridRule, RuleDetails(name="rainbow grid rule", function_context=lambda: Grid.is_grid_active("rainbow"))
diff --git a/castervoice/rules/apps/mouse_grids/gridsudoku.py b/castervoice/rules/apps/mouse_grids/gridsudoku.py
deleted file mode 100644
index bc60de87b..000000000
--- a/castervoice/rules/apps/mouse_grids/gridsudoku.py
+++ /dev/null
@@ -1,128 +0,0 @@
-import time
-from dragonfly import Function, Choice, MappingRule, ShortIntegerRef
-from dragonfly.actions.mouse import get_cursor_position
-from castervoice.lib import control
-from castervoice.lib.navigation import Grid
-from castervoice.lib.actions import Mouse
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.state.short import R
-from castervoice.rules.ccr.standard import SymbolSpecs
-
-
-# Perform an action based on the passed in action number
-# action - optional mouse action after movement
-def perform_mouse_action(action):
-    if action == 0:
-        Mouse("left").execute()
-    if action == 1:
-        Mouse("left:2").execute()
-    elif action == 2:
-        Mouse("right").execute()
-
-
-# Command to move the mouse
-# n - square to move to
-# s - optional inner square to move to
-# action - optional mouse action after movement
-def move_mouse(n, s, action):
-    sudoku = control.nexus().comm.get_com("grids")
-    sudoku.move_mouse(int(n), int(s))
-    int_a = int(action)
-    if (int_a == 0) | (int_a == 1) | (int_a == 2) | (int_a == -1):
-        sudoku.kill()
-        Grid.wait_for_grid_exit()
-
-    time.sleep(0.1)
-    perform_mouse_action(int(action))
-
-# Command to drag the mouse from the current position
-# n0 - optional square to drag from
-# s0 - optional inner square to drag from
-# n  - square to drag to
-# s  - optional inner square to drag to
-# action - optional mouse action after movement
-def drag_mouse(n0, s0, n, s, action):
-    sudoku = control.nexus().comm.get_com("grids")
-    # These numbers are internal to the monitor the screen is on
-    x, y = sudoku.get_mouse_pos(int(n), int(s))
-    
-    # If dragging from a different location, move there first
-    if int(n0) > 0:
-        sudoku.move_mouse(int(n0), int(s0))
-    sudoku.kill()
-    Grid.wait_for_grid_exit()
-    time.sleep(0.1)
-    # Hold down click, move to drag destination, and release click
-    Mouse("left:down/10").execute()
-    Mouse("[{}, {}]".format(x, y)).execute()
-    time.sleep(0.1)
-    Mouse("left:up/30").execute()
-    perform_mouse_action(int(action))
-
-# This is used for the fine movement dragging
-def drag_from_to(x1, y1, x2, y2):
-    Mouse("[{}, {}]".format(x1, y1)).execute()
-    time.sleep(0.5)
-    Mouse("left:down").execute()
-    time.sleep(0.5)
-    Mouse("[{}, {}]".format(x2, y2)).execute()
-    time.sleep(0.5)
-    Mouse("left:up").execute()
-
-def store_first_point():
-    global x1, y1
-    x1, y1 = get_cursor_position()
-    
-def select_text():
-    global x1, y1, x2, y2
-    x2, y2 = get_cursor_position()
-    s = control.nexus().comm.get_com("grids")
-    s.kill()
-    Grid.wait_for_grid_exit()
-    drag_from_to(x1, y1, x2, y2)
-
-'''
-Rules for sudoku grid. We can either move the mouse or drag it.
-The number n is one of the numbered squares.
-The grid portion is a number from 1-9 referencing an inner unnumbered square.
-'''
-
-
-class SudokuGridRule(MappingRule):
-    pronunciation = "sudoku grid"
-
-    mapping = {
-        " [grid ] []":
-            R(Function(move_mouse)),
-        "[] [grid ] (grab | select | drag)  [grid ] []":
-            R(Function(drag_mouse)),
-        "squat {weight=2}":
-            R(Function(store_first_point)),
-        "bench {weight=2}":
-            R(Function(select_text)),
-        SymbolSpecs.CANCEL + "{weight=2}":
-            R(Function(Grid.kill)),
-    }
-    extras = [
-        ShortIntegerRef("n", -1, 1500),
-        ShortIntegerRef("n0", -1, 1500),
-        ShortIntegerRef("s", 0, 10),
-        ShortIntegerRef("s0", 0, 10),
-        Choice("action", {
-            "kick": 0,
-            "kick (double | 2)": 1,
-            "psychic": 2,
-            "move": 3,
-        }),
-    ]
-    defaults = {
-        "n": 0,
-        "n0": 0,
-        "s": 0,
-        "s0": 0,
-        "action": -1,
-    }
-
-def get_rule():
-    Details = RuleDetails(name="Sudoku Grid", function_context=lambda: Grid.is_grid_active("sudoku"))
-    return SudokuGridRule, Details
diff --git a/castervoice/rules/apps/pdf/__init__.py b/castervoice/rules/apps/pdf/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/castervoice/rules/apps/pdf/adobe_acrobat.py b/castervoice/rules/apps/pdf/adobe_acrobat.py
deleted file mode 100644
index 776ed34be..000000000
--- a/castervoice/rules/apps/pdf/adobe_acrobat.py
+++ /dev/null
@@ -1,108 +0,0 @@
-from dragonfly import Dictation, Repeat, Pause, MappingRule, ShortIntegerRef
-from castervoice.lib.actions import Text, Key, Mouse
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.state.short import R
-
-_SHOW_HIDE_MENU = Key("a-v, s")
-
-
-class AcrobatRule(MappingRule):
-    mapping = {
-        "[go to] page ":
-            R(Key("a-v, n, g/15") + Text("%(n)s") + Key("enter")),
-        "set zoom ":
-            R(Key("c-y/40") + Text("%(n)s") + Key("enter")),
-        "open file":
-            R(Key("c-o")),
-        "duplicate tab":
-            R(Key("a-w,n/40,ws-left")),
-        "enable scrolling":
-            R(Key("a-v, p, c")),
-        "(disable scrolling | single page mode)":
-            R(Key("a-v, p, s")),
-        "next tab []":
-            R(Key("c-tab"))*Repeat(extra="n"),
-        "prior tab []":
-            R(Key("cs-tab"))*Repeat(extra="n"),
-        "home button":
-            R(Mouse("[100, 101], left")),  # coordinates may be user dependent
-
-        # Sticky Note Commands
-        # must have the cursor over the location where you want the sticky note
-        "add note []":
-            R(Mouse("right") + Key("t/5") + Text("%(dict)s")),
-        "fast [add] note []":
-            R(Mouse("right") + Key("t/5") + Text("%(dict)s") + Pause("10") +
-              Key("escape/5, c-s")),
-        "open blank note":
-            R(Mouse("right") + Key("t/5")),
-        "add blank note":
-            R(Mouse("right") + Key("t/5, escape/5, c-s")),
-        "delete note":
-            R(Mouse("right") + Key("l, c-s")),
-        "go back []":
-            R(Key("a-left"))*Repeat(extra='n'),
-        "save as":
-            R(Key("a-f, a")),
-
-        # when you open up a document that you have previously saved, and then click save,
-        # Adobe will sometimes make you go back into the save dialogbox
-        # and choose the location you want to save it in and then make you say that you want
-        # to overwrite the file. This is annoying, but this command "fast save" will automatically
-        # do all that for you.
-        "fast save":
-            R(Key("c-s/10, enter/10, enter/10, left, enter")),
-
-        # if page down goes too far down then try this command
-        "down it []":
-            R(Key("pgdown:%(n)s, up:4")),
-        "up it []":
-            R(Key("pgup:%(n)s, down:4")),
-        "tools pane":
-            R(_SHOW_HIDE_MENU + Key("t")),
-        "menu bar":
-            R(_SHOW_HIDE_MENU + Key("m")),
-        "model tree":
-            R(_SHOW_HIDE_MENU + Key("n, e")),
-        "bookmarks":
-            R(_SHOW_HIDE_MENU + Key("n, b")),
-        "[page] thumbnails":
-            R(_SHOW_HIDE_MENU + Key("n, b")),
-        "rotate []":
-            R(Key("c-plus"))*Repeat(extra='n'),
-
-        # Scrolling Commands
-        # Acrobat has a built-in scrolling function with nine speeds.
-        # Unfortunately, there are not separate commands for our scrolling up and down
-        # You have to start by scrolling in the most recently used direction and then reverse the direction
-        "scroll ":
-            R(Key("cs-h/2, %(speed_one_to_nine)s")),
-        "scroll":
-            R(Key("cs-h/2, 6")),
-        "change speed ":
-            R(Key("%(speed_one_to_nine)s, %(speed_one_to_nine)s")),
-        "reverse [direction]":
-            R(Key("minus")),
-        "stop [scrolling]":
-            R(Key("escape")),
-
-        # cursor commands
-        # (must enable "you single key accelerators to access tools" by going to: edit -> preferences -> general)
-        "highlight":
-            R(Key("u")),
-        "hand tool":
-            R(Key("h")),
-        "select tool":
-            R(Key("v")),
-    }
-    extras = [
-        Dictation("dict"),
-        ShortIntegerRef("n", 1, 1000),
-        ShortIntegerRef("m", 1, 9),
-        ShortIntegerRef("speed_one_to_nine", 1, 9),
-    ]
-    defaults = {"n": 1, "dict": "nothing"}
-
-
-def get_rule():
-    return AcrobatRule, RuleDetails(name="acrobat", executable="acrobat")
diff --git a/castervoice/rules/apps/pdf/foxitreader.py b/castervoice/rules/apps/pdf/foxitreader.py
deleted file mode 100644
index a634d2a7b..000000000
--- a/castervoice/rules/apps/pdf/foxitreader.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from dragonfly import Repeat, Dictation, MappingRule, ShortIntegerRef
-
-from castervoice.lib.actions import Key
-
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.state.short import R
-
-
-class FoxitRule(MappingRule):
-    mapping = {
-        "next tab []": R(Key("c-tab"))*Repeat(extra="n"),
-        "prior tab []": R(Key("cs-tab"))*Repeat(extra="n"),
-        "close tab []": R(Key("c-f4/20"))*Repeat(extra="n"),
-    }
-    extras = [
-        Dictation("text"),
-        Dictation("mim"),
-        ShortIntegerRef("n", 1, 1000),
-    ]
-    defaults = {"n": 1, "mim": ""}
-
-
-def get_rule():
-    return FoxitRule, RuleDetails(name="fox it reader", title="Foxit Reader")
diff --git a/castervoice/rules/apps/speech_engine/__init__.py b/castervoice/rules/apps/speech_engine/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/castervoice/rules/apps/speech_engine/dragon_rules/__init__.py b/castervoice/rules/apps/speech_engine/dragon_rules/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/castervoice/rules/apps/speech_engine/dragon_rules/dragon.py b/castervoice/rules/apps/speech_engine/dragon_rules/dragon.py
deleted file mode 100644
index 3c8a7fd36..000000000
--- a/castervoice/rules/apps/speech_engine/dragon_rules/dragon.py
+++ /dev/null
@@ -1,89 +0,0 @@
-from dragonfly import Function, Playback, Mimic, WaitWindow, Repeat, Pause, MappingRule
-from castervoice.lib.actions import Key
-
-from castervoice.rules.apps.speech_engine.dragon_rules.dragon_support import fix_dragon_double, extras_for_whole_file, \
-    defaults_for_whole_file
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.state.short import R
-
-
-class DragonRule(MappingRule):
-    mapping = {
-        '(number|numbers) mode':
-            R(Playback([(["numbers", "mode", "on"], 0.0)])),
-        'spell mode':
-            R(Playback([(["spell", "mode", "on"], 0.0)])),
-        'dictation mode':
-            R(Playback([(["dictation", "mode", "on"], 0.0)])),
-        'normal mode':
-            R(Playback([(["normal", "mode", "on"], 0.0)])),
-        '(command mode | command on | com on)':
-            R(Playback([(["command", "mode", "on"], 0.0)])),
-        '(command off | com off)':
-            R(Playback([(["command", "mode", "off"], 0.0)])),
-        "fix dragon double":
-            R(Function(fix_dragon_double)),
-        "left point":
-            R(Playback([(["MouseGrid"], 0.1), (["four", "four"], 0.1),
-                        (["click"], 0.0)])),
-        "right point":
-            R(Playback([(["MouseGrid"], 0.1), (["six", "six"], 0.1), (["click"], 0.0)])),
-        "center point":
-            R(Playback([(["MouseGrid"], 0.1), (["click"], 0.0)]),
-              rdescript="Mouse: Center Point"),
-        
-        
-        "show windows": R(Mimic("list", "all", "windows"),  
-            rdescript="Dragon: emulate Dragon command for listing windows"),
-        "cory ": 
-            R(Mimic("correct", extra="text") + WaitWindow(title="spelling window") + Mimic("choose", "one"),
-                rdescript="Dragon: brings up the correction menu for the phrase spoken in the command and chooses the 1st choice"),
-        "cory that": 
-            R(Mimic("correct", "that") + WaitWindow(title="spelling window") + Mimic("choose", "one"), 
-                rdescript="Dragon: brings up the correction menu for the previously spoken phrase and chooses the first choice"),
-
-        "make that ": R(Mimic("scratch", "that") + Mimic(extra="text"), 
-             rdescript="Dragon: deletes the dictation generated by the previous utterance and replaces it with what you say next"),
-        "scratch []": R(Playback([(["scratch", "that"], 0.03)]), 
-            rdescript="Dragon: delete dictation from previous n utterances") * Repeat(extra="n10"),
-
-            # Users may want to adjust the wait time on the next few commands     
-        "train word": R(Mimic("train", "that") + Pause("75") + Key("a-r/250, s"),
-             rdescript="Dragon: quickly train word when you have it selected in a Dragon friendly text field"),
-        "word train": R(Key("c-c/20") + Mimic("edit", "vocabulary") + 
-            Key("c-v/5, tab, down, up, a-t/50, enter/50, a-r/250, s/50, escape"),
-             rdescript="train word quickly once you have it selected in non-full text control application"),
-        "(add train | train from add word)": R(Key("a-a/2, enter/300, a-s"),
-            rdescript="Dragon: quickly train word from the add word dialogbox"),
-    
-        "(train from vocab | cab train)": R(Key("a-t/50, enter/50, a-r/250, s"), 
-            rdescript="Dragon: quickly train word from Vocabulary Editor"),
-        "(train from vocab | cab train)": R(Key("a-t/50, enter/50, a-r/250, s"), 
-            rdescript="Dragon: quickly train word from Vocabulary Editor"),
-        "remove from vocab":
-            R(Key("c-c/5") + Mimic("edit", "vocabulary") + Pause("20") + 
-            Key("c-v/10, tab, down, up/5, a-d, y, escape/30, right"), 
-            rdescript="Dragon: remove selected word from vocabulary"),
-        "(add to vocab | vocab that)":
-            R(Key("c-c/5") + Mimic("add", "word") + Pause("20") +
-            Key("c-v, a-a/2, enter/300, a-s/30, right"),
-            rdescript="Dragon: add selected word to vocabulary and train it"),
-
-        "recognition history": 
-            R(Playback([(["view", "recognition", "history"], 0.03)]),
-             rdescript="Dragon: open Dragon recognition history"),
-        "peak [recognition] history": 
-            R(Playback([(["view", "recognition", "history"], 0.03)])
-                + Pause("300") + Key("escape"), 
-                    rdescript="Dragon: open Dragon recognition history then close it"),
-        "[dictation] sources": R(Mimic("manage", "dictation", "sources"), 
-            rdescript="Dragon: manage dictation sources"),
-        
-    }
-    # see above
-    extras = extras_for_whole_file()
-    defaults = defaults_for_whole_file()
-
-
-def get_rule():
-    return DragonRule, RuleDetails(name="dragon")
diff --git a/castervoice/rules/apps/speech_engine/dragon_rules/dragon2.py b/castervoice/rules/apps/speech_engine/dragon_rules/dragon2.py
deleted file mode 100644
index 2bff80a11..000000000
--- a/castervoice/rules/apps/speech_engine/dragon_rules/dragon2.py
+++ /dev/null
@@ -1,33 +0,0 @@
-from dragonfly import Mimic, MappingRule
-from castervoice.lib.actions import Key
-
-
-from castervoice.rules.apps.speech_engine.dragon_rules.dragon_support import extras_for_whole_file, defaults_for_whole_file
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.state.short import R
-
-
-class SpellingWindowRule(MappingRule):
-    mapping = {
-        # TODO: make these CCR
-
-        " word":
-            R(Key("home, c-right:%(first_second_third)d, cs-right"),
-              rdescript="Dragon: select the first second or third etc. word"),
-        "last [word]": R(Key("right, cs-left"), rdescript="Dragon: select the last word"),
-        "second [to] last word": R(Key("right, c-left:1, cs-left"), rdescript="Dragon: select the second to last word"),
-        "": R(Mimic("choose", extra="n10"),
-                   rdescript="Dragon: e.g. instead of having to say 'choose two' you can just say 'two'"),
-        # consider making the above command global so that it works when you say something like
-        # "insert before 'hello'" where there are multiple instances of 'hello'
-        # personally I think it's better just to have the setting where Dragon choose is the closest instance
-
-    }
-
-    # see above
-    extras = extras_for_whole_file()
-    defaults = defaults_for_whole_file()
-
-
-def get_rule():
-    return SpellingWindowRule, RuleDetails(name="dragon spelling window", executable="natspeak")
diff --git a/castervoice/rules/apps/speech_engine/dragon_rules/dragon_support.py b/castervoice/rules/apps/speech_engine/dragon_rules/dragon_support.py
deleted file mode 100644
index 68decfd67..000000000
--- a/castervoice/rules/apps/speech_engine/dragon_rules/dragon_support.py
+++ /dev/null
@@ -1,39 +0,0 @@
-from dragonfly import Dictation, Choice, ShortIntegerRef
-
-from castervoice.lib import utilities
-from castervoice.lib.actions import Text, Key
-from castervoice.lib.util import recognition_history
-
-_DBL_FIX_HISTORY = recognition_history.get_and_register_history(1)
-
-
-def fix_dragon_double():
-    try:
-        lr = _DBL_FIX_HISTORY[len(_DBL_FIX_HISTORY) - 1]
-        lu = " ".join(lr)
-        Key("left/5:" + str(len(lu)) + ", del").execute()
-    except Exception:
-        utilities.simple_log(False)
-
-# extras are common to both classes in this file
-def extras_for_whole_file():
-    return [
-        Dictation("text"),
-        ShortIntegerRef("n10", 1, 10),
-        Choice("first_second_third", {
-            "first": 0,
-            "second": 1,
-            "third": 2,
-            "fourth": 3,
-            "fifth": 4,
-            "six": 5,
-            "seventh": 6
-        }),
-    ]
-
-
-def defaults_for_whole_file():
-    return {
-        "n10": 1,
-        "text": "",
-    }
diff --git a/castervoice/rules/apps/speech_engine/wsr.py b/castervoice/rules/apps/speech_engine/wsr.py
deleted file mode 100644
index 5d2d76c50..000000000
--- a/castervoice/rules/apps/speech_engine/wsr.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from dragonfly import Function, MappingRule
-
-from castervoice.lib import utilities
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.state.short import R
-
-
-class WindowsSpeechRecognitionRule(MappingRule):
-
-    mapping = {
-        "reboot windows speech recognition":
-            R(Function(utilities.reboot, wsr=True)),
-    }
-    extras = []
-    defaults = {}
-
-
-def get_rule():
-    return WindowsSpeechRecognitionRule, RuleDetails(name="w s r")
diff --git a/castervoice/rules/apps/terminal/__init__.py b/castervoice/rules/apps/terminal/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/castervoice/rules/apps/terminal/gitbash.py b/castervoice/rules/apps/terminal/gitbash.py
deleted file mode 100644
index fd5b8000e..000000000
--- a/castervoice/rules/apps/terminal/gitbash.py
+++ /dev/null
@@ -1,124 +0,0 @@
-from dragonfly import Mimic, Function, MappingRule, ShortIntegerRef
-
-from castervoice.lib.actions import Key, Text
-
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.state.short import R
-
-
-def _apply(n):
-    if n != 0:
-        Text("stash@{" + str(int(n)) + "}").execute()
-
-
-class GitBashRule(MappingRule):
-    GIT_ADD_ALL = "g, i, t, space, a, d, d, space, minus, A"
-    GIT_COMMIT = "g, i, t, space, c, o, m, m, i, t, space, minus, m, space, quote, quote, left"
-    mapping = {
-        "(git|get) base":
-            Text("git "),
-        "(git|get) (initialize repository|init)":
-            Text("git init"),
-        "(git|get) add":
-            R(Key("g, i, t, space, a, d, d, space, dot")),
-        "(git|get) add all":
-            R(Key(GIT_ADD_ALL)),
-        "(git|get) commit all":
-            R(Key("%s, ;, space, %s" % (GIT_ADD_ALL, GIT_COMMIT))),
-        "(git|get) status":
-            R(Key("g, i, t, space, s, t, a, t, u, s")),
-        "(git|get) commit":
-            R(Key(GIT_COMMIT)),
-        "(git|get) bug fix commit ":
-            R(Mimic("get", "commit") + Text("fixes #%(n)d ") + Key("backspace")),
-        "(git|get) reference commit ":
-            R(Mimic("get", "commit") + Text("refs #%(n)d ") + Key("backspace")),
-        "(git|get) checkout":
-            R(Text("git checkout ")),
-        "(git|get) branch":
-            R(Text("git branch ")),
-        "(git|get) remote":
-            R(Text("git remote ")),
-        "(git|get) merge":
-            R(Text("git merge ")),
-        "(git|get) merge tool":
-            R(Text("git mergetool")),
-        "(git|get) fetch":
-            R(Text("git fetch ")),
-        "(git|get) push":
-            R(Text("git push ")),
-        "(git|get) pull":
-            R(Text("git pull ")),
-        "CD up":
-            R(Text("cd ..")),
-        "CD":
-            R(Text("cd ")),
-        "list":
-            R(Text("ls")),
-        "make directory":
-            R(Text("mkdir ")),
-        "undo [last] commit | (git|get) reset soft head":
-            R(Text("git reset --soft HEAD~1")),
-        "(undo changes | (git|get) reset hard)":
-            R(Text("git reset --hard")),
-        "stop tracking [file] | (git|get) remove":
-            R(Text("git rm --cached ")),
-        "preview remove untracked | (git|get) clean preview":
-            R(Text("git clean -nd")),
-        "remove untracked | (git|get) clean untracked":
-            R(Text("git clean -fd")),
-        "(git|get) visualize":
-            R(Text("gitk")),
-        "(git|get) visualize file":
-            R(Text("gitk -- PATH")),
-        "(git|get) visualize all":
-            R(Text("gitk --all")),
-        "(git|get) stash":
-            R(Text("git stash")),
-        "(git|get) stash apply []":
-            R(Text("git stash apply") + Function(_apply)),
-        "(git|get) stash list":
-            R(Text("git stash list")),
-        "(git|get) stash branch":
-            R(Text("git stash branch NAME")),
-        "(git|get) cherry pick":
-            R(Text("git cherry-pick ")),
-        "(git|get) (abort cherry pick | cherry pick abort)":
-            R(Text("git cherry-pick --abort")),
-        "(git|get) (GUI | gooey)":
-            R(Text("git gui")),
-        "(git|get) blame":
-            R(Text("git blame PATH -L FIRSTLINE,LASTLINE")),
-        "(git|get) gooey blame":
-            R(Text("git gui blame PATH")),
-        "search recursive":
-            R(Text("grep -rinH \"PATTERN\" *")),
-        "search recursive count":
-            R(Text("grep -rinH \"PATTERN\" * | wc -l")),
-        "search recursive file type":
-            R(Text("find . -name \"*.java\" -exec grep -rinH \"PATTERN\" {} \\;")),
-        "to file":
-            R(Text(" > FILENAME")),
-    }
-    extras = [
-        ShortIntegerRef("n", 1, 10000),
-    ]
-    defaults = {"n": 0}
-
-
-_executables = [
-    "\\sh.exe",
-    "\\bash.exe",
-    "\\cmd.exe",
-    "\\mintty.exe",
-    "\\powershell.exe",
-    "idea",
-    "idea64",
-    "studio64",
-    "pycharm"
-]
-
-
-def get_rule():
-    return GitBashRule, RuleDetails(name="git bash", executable=_executables)
-
diff --git a/castervoice/rules/apps/windows_os/__init__.py b/castervoice/rules/apps/windows_os/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/castervoice/rules/apps/windows_os/explorer.py b/castervoice/rules/apps/windows_os/explorer.py
deleted file mode 100644
index 8df5ae4e4..000000000
--- a/castervoice/rules/apps/windows_os/explorer.py
+++ /dev/null
@@ -1,45 +0,0 @@
-from dragonfly import Dictation, MappingRule, ShortIntegerRef
-
-from castervoice.lib.actions import Key, Text
-
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.state.short import R
-
-
-class IERule(MappingRule):
-    mapping = {
-        "address bar":
-            R(Key("a-d")),
-        "new folder":
-            R(Key("cs-n")),
-        "new file":
-            R(Key("a-f, w, t")),
-        "(show | file | folder) properties":
-            R(Key("a-enter")),
-        "get up":
-            R(Key("a-up")),
-        "get back":
-            R(Key("a-left")),
-        "get forward":
-            R(Key("a-right")),
-        "search []":
-            R(Key("a-d, tab:1") + Text("%(text)s")),
-        "(navigation | nav | left) pane":
-            R(Key("a-d, tab:2")),
-        "(center pane | (file | folder) (pane | list))":
-            R(Key("a-d, tab:3")),
-            # for the sort command below,
-            # once you've selected the relevant heading for sorting using the arrow keys, press enter
-        "sort [headings]":
-            R(Key("a-d, tab:4")),
-
-    }
-    extras = [
-        Dictation("text"),
-        ShortIntegerRef("n", 1, 1000),
-    ]
-    defaults = {"n": 1}
-
-
-def get_rule():
-    return IERule, RuleDetails(name="explorer", executable="explorer")
diff --git a/castervoice/rules/apps/windows_os/file_dialogue.py b/castervoice/rules/apps/windows_os/file_dialogue.py
deleted file mode 100644
index a79af093a..000000000
--- a/castervoice/rules/apps/windows_os/file_dialogue.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from dragonfly import Repeat, Dictation, MappingRule, ShortIntegerRef
-
-from castervoice.lib.actions import Key
-
-from castervoice.lib.actions import Text
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.state.short import R
-
-
-class FileDialogueRule(MappingRule):
-    mapping = {
-        "up []": R(Key("a-up"))*Repeat(extra="n"),
-        "back []": R(Key("a-left"))*Repeat(extra="n"),
-        "forward []": R(Key("a-right"))*Repeat(extra="n"),
-        "search []": R(Key("c-l, tab") + Text("%(text)s")),
-        "organize": R(Key("c-l, tab:2")),
-        "(left | navigation) pane": R(Key("c-l, tab:3")),
-        "(center|file|files|folder) (list | pane)": R(Key("c-l, tab:4")),
-        "sort [headings]": R(Key("c-l, tab:5")),
-        "[file] name": R(Key("a-n")),
-        "file type": R(Key("c-l, tab:7")),
-
-    }
-    extras = [ShortIntegerRef("n", 1, 10), Dictation("text")]
-    defaults = {
-        "n": 1,
-    }
-
-
-def get_rule():
-    return FileDialogueRule, RuleDetails(name="file dialogue", title=["open", "save", "select"])
diff --git a/castervoice/rules/apps/windows_os/winword.py b/castervoice/rules/apps/windows_os/winword.py
deleted file mode 100644
index df37c7bd7..000000000
--- a/castervoice/rules/apps/windows_os/winword.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from dragonfly import Dictation, MappingRule, ShortIntegerRef
-from castervoice.lib.actions import Key
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.state.short import R
-
-
-class MSWordRule(MappingRule):
-    mapping = {
-        "insert image": R(Key("alt, n, p")),
-    }
-    extras = [
-        Dictation("dict"),
-        ShortIntegerRef("n", 1, 100),
-    ]
-    defaults = {"n": 1, "dict": "nothing"}
-
-
-def get_rule():
-    details = RuleDetails(name="Microsoft Word", executable="winword")
-    return MSWordRule, details
diff --git a/castervoice/rules/ccr/__init__.py b/castervoice/rules/ccr/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/castervoice/rules/ccr/bash_rules/__init__.py b/castervoice/rules/ccr/bash_rules/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/castervoice/rules/ccr/bash_rules/bash.py b/castervoice/rules/ccr/bash_rules/bash.py
deleted file mode 100644
index a70329ff6..000000000
--- a/castervoice/rules/ccr/bash_rules/bash.py
+++ /dev/null
@@ -1,105 +0,0 @@
-'''
-Created on Sep 1, 2015
-@author: synkarius
-'''
-from castervoice.lib.actions import Text, Key
-from castervoice.rules.ccr.standard import SymbolSpecs
-from castervoice.lib.const import CCRType
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.mergerule import MergeRule
-from castervoice.lib.merge.state.short import R
-
-
-
-class Bash(MergeRule):
-    pronunciation = "bash"
-
-    mapping = {
-        SymbolSpecs.IF:
-            R(Text("if [[  ]]; ") + Key("left/5:5")),
-        SymbolSpecs.ELSE:
-            R(Text("else")),
-        #
-        SymbolSpecs.SWITCH:
-            R(Text("case TOKEN in")),
-        SymbolSpecs.CASE:
-            R(Text("TOKEN)  ;;") + Key("left/5:2")),
-        SymbolSpecs.BREAK:
-            R(Text("break")),
-        SymbolSpecs.DEFAULT:
-            R(Text("*)  ;;")),
-        #
-        SymbolSpecs.DO_LOOP:
-            R(Text("until [  ]; do") + Key("left/5:7")),
-        SymbolSpecs.WHILE_LOOP:
-            R(Text("while [  ]; do") + Key("left/5:7")),
-        SymbolSpecs.FOR_LOOP:
-            R(Text("for (( i=0; i<=TOKEN; i++ )); do")),
-        SymbolSpecs.FOR_EACH_LOOP:
-            R(Text("for TOKEN in TOKEN; do")),
-        #
-        # integers?
-        # strings?
-        # floats?
-        #
-        SymbolSpecs.AND:
-            R(Text(" && ")),
-        SymbolSpecs.OR:
-            R(Text(" || ")),
-        SymbolSpecs.NOT:
-            R(Text("!")),
-        #
-        SymbolSpecs.SYSOUT:
-            R(Text("echo ")),
-        #
-        SymbolSpecs.IMPORT:
-            R(Text(". /path/to/functions")),  # (top of file, under #!/bin/bash)
-        #
-        SymbolSpecs.FUNCTION:
-            R(Text("TOKEN(){}") + Key("left, enter/5:2")),
-        # classes?
-        #
-        SymbolSpecs.COMMENT:
-            R(Text("# ")),
-        # no multiline comment in bash
-        #
-        SymbolSpecs.NULL:
-            R(Text('-z "$var"') + Key("left/5:1")),
-        #
-        SymbolSpecs.RETURN:
-            R(Text("return ")),
-        #
-        SymbolSpecs.TRUE:
-            R(Text("true")),
-        SymbolSpecs.FALSE:
-            R(Text("false")),
-
-        # Bash specific
-        "key do":
-            R(Text("do")),
-        "key done":
-            R(Text("done")),
-        "key fee":
-            R(Text("fi")),
-        "shell iffae":
-            R(Text("elif [[  ]]; ") + Key("left/5:5")),
-        "sue iffae":
-            R(Text("[[  ]]") + Key("left/5:3")),
-        "length of":
-            R(Text("${#TOKEN[@]}")),
-        "push":
-            R(Text("TOKEN+=()")),
-        "continue":
-            R(Text("continue")),
-        "she bang":
-            R(Text("#!/bin/bash")),
-        "end switch":
-            R(Text("esac")),
-    }
-
-    extras = []
-    defaults = {}
-
-
-def get_rule():
-    return Bash, RuleDetails(ccrtype=CCRType.GLOBAL)
diff --git a/castervoice/rules/ccr/cpp_rules/__init__.py b/castervoice/rules/ccr/cpp_rules/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/castervoice/rules/ccr/cpp_rules/cpp.py b/castervoice/rules/ccr/cpp_rules/cpp.py
deleted file mode 100644
index 7205560a0..000000000
--- a/castervoice/rules/ccr/cpp_rules/cpp.py
+++ /dev/null
@@ -1,138 +0,0 @@
-'''
-Created on Sep 1, 2015
-
-@author: synkarius
-'''
-from dragonfly import Mimic
-
-from castervoice.lib.actions import Text, Key
-from castervoice.rules.ccr.standard import SymbolSpecs
-from castervoice.lib.const import CCRType
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.mergerule import MergeRule
-from castervoice.lib.merge.state.short import R
-
-
-class CPP(MergeRule):
-    pronunciation = "C plus plus"
-
-    mapping = {
-        SymbolSpecs.IF:
-            R(Key("i, f, lparen, rparen, leftbrace, enter,up,left")),
-        SymbolSpecs.ELSE:
-            R(Key("e, l, s, e, leftbrace, enter")),
-        #
-        SymbolSpecs.SWITCH:
-            R(Text("switch(){\ncase : break;\ndefault: break;") + Key("up,up,left,left")),
-        SymbolSpecs.CASE:
-            R(Text("case :") + Key("left")),
-        SymbolSpecs.BREAK:
-            R(Text("break;")),
-        SymbolSpecs.DEFAULT:
-            R(Text("default: ")),
-        #
-        SymbolSpecs.DO_LOOP:
-            R(Text("do {}") + Key("left, enter:2")),
-        SymbolSpecs.WHILE_LOOP:
-            R(Text("while ()") + Key("left")),
-        SymbolSpecs.FOR_LOOP:
-            R(Text("for (int i=0; i()") + Key("left")),
-        "static cast double":
-            R(Text("static_cast()") + Key("left")),
-        "([global] scope | name)":
-            R(Text("::")),
-        "Vic":
-            R(Text("vector")),
-        "pushback":
-            R(Text("push_back")),
-        "standard":
-            R(Text("std")),
-        "constant":
-            R(Text("const")),
-        "array":
-            R(Mimic("brackets")),
-
-        #http://www.learncpp.com/cpp-tutorial/67-introduction-to-pointers/
-        "(reference to | address of)":
-            R(Text("&")),
-        "(pointer | D reference)":
-            R(Text("*")),
-        "member":
-            R(Text("->")),
-        "new new":
-            R(Text("new ")),
-        "integer":
-            R(Text("int ")),
-        "double":
-            R(Text("double ")),
-        "character":
-            R(Text("char ")),
-        "big integer":
-            R(Text("Integer")),
-        "string":
-            R(Text("string ")),
-        "ternary":
-            R(Text("()?;") + (Key("left")*3)),
-    }
-
-    extras = []
-    defaults = {}
-
-
-def get_rule():
-    return CPP, RuleDetails(ccrtype=CCRType.GLOBAL)
diff --git a/castervoice/rules/ccr/csharp_rules/__init__.py b/castervoice/rules/ccr/csharp_rules/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/castervoice/rules/ccr/csharp_rules/csharp.py b/castervoice/rules/ccr/csharp_rules/csharp.py
deleted file mode 100644
index e37e03d95..000000000
--- a/castervoice/rules/ccr/csharp_rules/csharp.py
+++ /dev/null
@@ -1,129 +0,0 @@
-from dragonfly import Mimic
-
-from castervoice.lib.actions import Text, Key
-from castervoice.rules.ccr.standard import SymbolSpecs
-from castervoice.lib.const import CCRType
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.mergerule import MergeRule
-from castervoice.lib.merge.state.short import R
-
-
-class CSharp(MergeRule):
-    pronunciation = "C sharp"
-
-    mapping = {
-        SymbolSpecs.IF:
-            R(Key("i, f, lparen, rparen, leftbrace, enter,up,left")),
-        SymbolSpecs.ELSE:
-            R(Key("e, l, s, e, leftbrace, enter")),
-        #
-        SymbolSpecs.SWITCH:
-            R(Text("switch(){\ncase : break;\ndefault: break;") + Key("up,up,left,left")),
-        SymbolSpecs.CASE:
-            R(Text("case :") + Key("left")),
-        SymbolSpecs.BREAK:
-            R(Text("break;")),
-        SymbolSpecs.DEFAULT:
-            R(Text("default: ")),
-        #
-        SymbolSpecs.DO_LOOP:
-            R(Text("do {}") + Key("left, enter:2")),
-        SymbolSpecs.WHILE_LOOP:
-            R(Text("while ()") + Key("left")),
-        SymbolSpecs.FOR_LOOP:
-            R(Text("for (int i=0; i") + Key("left")),
-        "var":
-            R(Text("var TOKEN = TOKEN;")),
-        "(lambda|goes to)":
-            R(Text("=>")),
-        "new new":
-            R(Text("new ")),
-        "integer":
-            R(Text("int ")),
-        "double":
-            R(Text("double ")),
-        "character":
-            R(Text("char ")),
-        "big integer":
-            R(Text("Integer")),
-        "string":
-            R(Text("string ")),
-        "ternary":
-            R(Text("()?t:f") + (Key("left")*5)),
-    }
-
-    extras = []
-    defaults = {}
-
-
-def get_rule():
-    return CSharp, RuleDetails(ccrtype=CCRType.GLOBAL)
diff --git a/castervoice/rules/ccr/css_rules/__init__.py b/castervoice/rules/ccr/css_rules/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/castervoice/rules/ccr/css_rules/css.py b/castervoice/rules/ccr/css_rules/css.py
deleted file mode 100644
index e9c9ed238..000000000
--- a/castervoice/rules/ccr/css_rules/css.py
+++ /dev/null
@@ -1,427 +0,0 @@
-from dragonfly import ShortIntegerRef
-from castervoice.lib.actions import Key, Text
-from castervoice.lib import settings, printer
-from castervoice.lib.const import CCRType
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.context import AppContext
-
-from castervoice.lib.merge.mergerule import MergeRule
-from castervoice.lib.merge.state.short import R
-
-
-# HTML auto complete workaround for Jetbrains Products
-# If more applications have issues with auto complete may be moved to actions.py
-_context = AppContext(executable=["idea", "idea64", "studio64", "pycharm", "webstorm64", "webstorm"])
-
-if _context:
-    from dragonfly.actions.action_paste import Paste as Text
-    if settings.settings(["miscellaneous", "use_aenea"]):
-        try:
-            from aenea import Paste as Text
-        except ImportError:
-            printer.out("Unable to import aenea Paste actions. Dragonfly actions will be used "
-                  "instead.")
-else:
-    from castervoice.lib.actions import Text
-
-
-class CSS(MergeRule):
-    pronunciation = "css"
-
-    mapping = {
-        #Macros
-        "selector":
-            R(Text("{}") + Key("left/10:1") + Key("enter")),
-        "property":
-            R(Text(":;") + Key("left/10:1")),
-        #Measurements
-        " pixel |  PX":
-            R(Text("%(ln1)spx")),
-        " percentage |  percent":
-            R(Text("%(ln1)s") + Key("s-5")),
-        " centimeter |  CM":
-            R(Text("%(ln1)scm")),
-        " inch |  IN":
-            R(Text("%(ln1)sin")),
-        " millimeter |  MM":
-            R(Text("%(ln1)smm")),
-        " pica |  PC":
-            R(Text("%(ln1)spc")),
-        " point |  PT":
-            R(Text("%(ln1)spt")),
-        " CH":
-            R(Text("%(ln1)sch")),
-        " EM":
-            R(Text("%(ln1)sem")),
-        " EX":
-            R(Text("%(ln1)sex")),
-        " REM":
-            R(Text("%(ln1)srem")),
-        " viewport height |  VH":
-            R(Text("%(ln1)svh")),
-        " viewport width |  VW":
-            R(Text("%(ln1)svw")),
-        " millisecond |  MS":
-            R(Text("%(ln1)sms")),
-        " second |  S":
-            R(Text("%(ln1)ss")),
-        #background
-        "background image":
-            R(Text("background-image:;") + Key("left/10:1")),
-        "background position":
-            R(Text("background-position:;") + Key("left/10:1")),
-        "background size":
-            R(Text("background-size:;") + Key("left/10:1")),
-        "background repeat":
-            R(Text("background-repeat:;") + Key("left/10:1")),
-        "background attachment":
-            R(Text("background-attachment:;") + Key("left/10:1")),
-        "background origin":
-            R(Text("background-origin:;") + Key("left/10:1")),
-        "background clip":
-            R(Text("background-clip:;") + Key("left/10:1")),
-        "background color":
-            R(Text("background-color:;") + Key("left/10:1")),
-        "background attachment":
-            R(Text("background-attachment:;") + Key("left/10:1")),
-        "background origin":
-            R(Text("background-origin:;") + Key("left/10:1")),
-        "background clip":
-            R(Text("background-clip:;") + Key("left/10:1")),
-        #border
-        "border":
-            R(Text("border:;") + Key("left/10:1")),
-        "border top":
-            R(Text("border-top:;") + Key("left/10:1")),
-        "border bottom":
-            R(Text("border-bottom:;") + Key("left/10:1")),
-        "border left":
-            R(Text("border-left:;") + Key("left/10:1")),
-        "border right":
-            R(Text("border-right:;") + Key("left/10:1")),
-        "border width":
-            R(Text("border-width:;") + Key("left/10:1")),
-        "border style":
-            R(Text("border-style:;") + Key("left/10:1")),
-        "border color":
-            R(Text("border-color:;") + Key("left/10:1")),
-        "border break":
-            R(Text("border-break:;") + Key("left/10:1")),
-        "border image":
-            R(Text("border-image:;") + Key("left/10:1")),
-        "border radius":
-            R(Text("border-radius:;") + Key("left/10:1")),
-        #box model
-        "box shadow":
-            R(Text("box-shadow:;") + Key("left/10:1")),
-        "border-box":
-            R(Text("border-box")),
-        "height":
-            R(Text("height:;") + Key("left/10:1")),
-        "width":
-            R(Text("width:;") + Key("left/10:1")),
-        "min height":
-            R(Text("min-height:;") + Key("left/10:1")),
-        "max height":
-            R(Text("max-height:;") + Key("left/10:1")),
-        "min width":
-            R(Text("min-width:;") + Key("left/10:1")),
-        "max width":
-            R(Text("max-width:;") + Key("left/10:1")),
-        "padding box":
-            R(Text("padding-box")),
-        "content box":
-            R(Text("content-box")),
-        "margin":
-            R(Text("margin:;") + Key("left/10:1")),
-        "margin top":
-            R(Text("margin-top:;") + Key("left/10:1")),
-        "margin bottom":
-            R(Text("margin-bottom:;") + Key("left/10:1")),
-        "margin left":
-            R(Text("margin-left:;") + Key("left/10:1")),
-        "margin right":
-            R(Text("margin-right:;") + Key("left/10:1")),
-        "padding":
-            R(Text("padding:;") + Key("left/10:1")),
-        "padding top":
-            R(Text("padding-top:;") + Key("left/10:1")),
-        "padding bottom":
-            R(Text("padding-bottom:;") + Key("left/10:1")),
-        "padding left":
-            R(Text("padding-left:;") + Key("left/10:1")),
-        "padding right":
-            R(Text("padding-right:;") + Key("left/10:1")),
-        "display":
-            R(Text("display:;") + Key("left/10:1")),
-        "overflow":
-            R(Text("overflow:;") + Key("left/10:1")),
-        "overflow y":
-            R(Text("overflow-y:;") + Key("left/10:1")),
-        "overflow x":
-            R(Text("overflow-x:;") + Key("left/10:1")),
-        "overflow style":
-            R(Text("overflow-style:;") + Key("left/10:1")),
-        "visibility":
-            R(Text("visibility:;") + Key("left/10:1")),
-        "clear":
-            R(Text("clear:;") + Key("left/10:1")),
-        #Font
-        "font":
-            R(Text("font:;") + Key("left/10:1")),
-        "font style":
-            R(Text("font-style:;") + Key("left/10:1")),
-        "font variant":
-            R(Text("font-variant:;") + Key("left/10:1")),
-        "font weight":
-            R(Text("font-weight:;") + Key("left/10:1")),
-        "font size":
-            R(Text("font-size:;") + Key("left/10:1")),
-        "font family":
-            R(Text("font-family:;") + Key("left/10:1")),
-        #text
-        "direction":
-            R(Text("direction:;") + Key("left/10:1")),
-        "hanging punctuation":
-            R(Text("hanging-punctuation:;") + Key("left/10:1")),
-        "letter spacing":
-            R(Text("letter-spacing:;") + Key("left/10:1")),
-        "text outline":
-            R(Text("text-outline:;") + Key("left/10:1")),
-        "unicode bidi":
-            R(Text("unicode-bidi:;") + Key("left/10:1")),
-        "white space":
-            R(Text("white-space:;") + Key("left/10:1")),
-        "white space collapse":
-            R(Text("white-space-collapse:;") + Key("left/10:1")),
-        "punctuation trim":
-            R(Text("punctuation-trim:;") + Key("left/10:1")),
-        "text align":
-            R(Text("text-align:;") + Key("left/10:1")),
-        "text align last":
-            R(Text("text-align-last:;") + Key("left/10:1")),
-        "text decoration":
-            R(Text("text-decoration:;") + Key("left/10:1")),
-        "text shadow":
-            R(Text("text-shadow:;") + Key("left/10:1")),
-        "word break":
-            R(Text("word-break:;") + Key("left/10:1")),
-        "word wrap":
-            R(Text("word-wrap:;") + Key("left/10:1")),
-        "text emphasis":
-            R(Text("text-emphasis:;") + Key("left/10:1")),
-        "text indent":
-            R(Text("text-indent:;") + Key("left/10:1")),
-        "text justify":
-            R(Text("text-justify:;") + Key("left/10:1")),
-        "text transform":
-            R(Text("text-transform:;") + Key("left/10:1")),
-        "text wrap":
-            R(Text("text-wrap:;") + Key("left/10:1")),
-        "word spacing":
-            R(Text("word-spacing:;") + Key("left/10:1")),
-        #column
-        "column count":
-            R(Text("column-count:;") + Key("left/10:1")),
-        "column fill":
-            R(Text("column-fill:;") + Key("left/10:1")),
-        "column gap":
-            R(Text("column-gap:;") + Key("left/10:1")),
-        "column rule":
-            R(Text("column-rule:;") + Key("left/10:1")),
-        "column rule style":
-            R(Text("column-rule-style:;") + Key("left/10:1")),
-        "column":
-            R(Text("column:;") + Key("left/10:1")),
-        "column rule width":
-            R(Text("column-rule-width:;") + Key("left/10:1")),
-        "column span":
-            R(Text("column-span:;") + Key("left/10:1")),
-        "column width":
-            R(Text("column-width:;") + Key("left/10:1")),
-        #colors
-        "color":
-            R(Text("color:;") + Key("left/10:1")),
-        "opacity":
-            R(Text("opacity:;") + Key("left/10:1")),
-        #table
-        "border collapse":
-            R(Text("border-collapse:;") + Key("left/10:1")),
-        "empty cells":
-            R(Text("empty-cells:;") + Key("left/10:1")),
-        "border spacing":
-            R(Text("border-spacing:;") + Key("left/10:1")),
-        "table layout":
-            R(Text("table-layout:;") + Key("left/10:1")),
-        "caption side":
-            R(Text("caption-side:;") + Key("left/10:1")),
-        #List & Markers
-        "list style":
-            R(Text("list-style:;") + Key("left/10:1")),
-        "list style type":
-            R(Text("list-style-type:;") + Key("left/10:1")),
-        "list style position":
-            R(Text("list-style-position:;") + Key("left/10:1")),
-        "list style image":
-            R(Text("list-style-image:;") + Key("left/10:1")),
-        "marker offset":
-            R(Text("marker-offset:;") + Key("left/10:1")),
-        #Animations
-        "animations":
-            R(Text("animations:;") + Key("left/10:1")),
-        "animation name":
-            R(Text("animation-name:;") + Key("left/10:1")),
-        "animation duration":
-            R(Text("animation-duration:;") + Key("left/10:1")),
-        "animation timing function":
-            R(Text("animation-timing-function:;") + Key("left/10:1")),
-        "animation delay":
-            R(Text("animation-delay:;") + Key("left/10:1")),
-        "animation iteration count":
-            R(Text("animation-iteration-count:;") + Key("left/10:1")),
-        "animation direction":
-            R(Text("animation-direction:;") + Key("left/10:1")),
-        "animation play state":
-            R(Text("animation-play-state:;") + Key("left/10:1")),
-        #Transitions
-        "transitions":
-            R(Text("transitions:;") + Key("left/10:1")),
-        "transitions property":
-            R(Text("transitions-property:;") + Key("left/10:1")),
-        "transitions duration":
-            R(Text("transitions-duration:;") + Key("left/10:1")),
-        "transitions timing function":
-            R(Text("transitions-timing-function:;") + Key("left/10:1")),
-        "transitions delay":
-            R(Text("transitions-delay:;") + Key("left/10:1")),
-        "transitions property":
-            R(Text("transitions-property:;") + Key("left/10:1")),
-        #UI
-        "webkit appearance | appearance":
-            R(Text("-webkit-appearance:;") + Key("left/10:1")),
-        "cursor":
-            R(Text("cursor:;") + Key("left/10:1")),
-        "resize":
-            R(Text("resize:;") + Key("left/10:1")),
-        #Pseudo-Class
-        "active":
-            R(Text(":active")),
-        "focus":
-            R(Text(":focus")),
-        "hover":
-            R(Text(":hover")),
-        "link":
-            R(Text(":link")),
-        "disabled":
-            R(Text(":disabled")),
-        "enabled":
-            R(Text(":enabled")),
-        "checked":
-            R(Text(":checked")),
-        "selection":
-            R(Text(":selection")),
-        "lang":
-            R(Text(":lang")),
-        "nth child":
-            R(Text(":nth-child()") + Key("left/10:1")),
-        "nth last child":
-            R(Text(":nth-last-child()") + Key("left/10:1")),
-        "first child":
-            R(Text(":first-child")),
-        "last child":
-            R(Text(":last-child")),
-        "only-child":
-            R(Text(":only-child")),
-        "nth of type":
-            R(Text(":nth-of-type()") + Key("left/10:1")),
-        "nth last of type ":
-            R(Text(":nth-last-of-type() ") + Key("left/10:1")),
-        "last of type":
-            R(Text(":last-of-type")),
-        "first of type":
-            R(Text(":first-of-type")),
-        "only of type":
-            R(Text(":only-of-type")),
-        "empty":
-            R(Text(":empty")),
-        "root":
-            R(Text(":root")),
-        "not":
-            R(Text(":not()") + Key("left/10:1")),
-        "target":
-            R(Text(":target")),
-        "first letter":
-            R(Text("::first-letter")),
-        "first line":
-            R(Text("::first-line")),
-        "before":
-            R(Text("::before")),
-        "after":
-            R(Text("::after")),
-        #Outline
-        "outline":
-            R(Text("outline:;") + Key("left/10:1")),
-        "outline color":
-            R(Text("outline-color:;") + Key("left/10:1")),
-        "outline style":
-            R(Text("outline-style:;") + Key("left/10:1")),
-        "outline width":
-            R(Text("outline-width:;") + Key("left/10:1")),
-        "outline offset":
-            R(Text("outline-offset:;") + Key("left/10:1")),
-        #transform
-        "backface visibility":
-            R(Text("backface-visibility:;") + Key("left/10:1")),
-        "perspective":
-            R(Text("perspective:;") + Key("left/10:1")),
-        "perspective origin":
-            R(Text("perspective-origin:;") + Key("left/10:1")),
-        "transform":
-            R(Text("transform:;") + Key("left/10:1")),
-        "transform style":
-            R(Text("transform-style:;") + Key("left/10:1")),
-        #Positioning
-        "position":
-            R(Text("position:;") + Key("left/10:1")),
-        "clip":
-            R(Text("clip:;") + Key("left/10:1")),
-        "z index":
-            R(Text("z-index:;") + Key("left/10:1")),
-        #flex
-        "flex direction":
-            R(Text("flex-direction:;") + Key("left/10:1")),
-        "flex wrap":
-            R(Text("flex-wrap:;") + Key("left/10:1")),
-        "align items":
-            R(Text("align-items:;") + Key("left/10:1")),
-        "justify content":
-            R(Text("justify-content:;") + Key("left/10:1")),
-        "flex grow":
-            R(Text("flex-grow:;") + Key("left/10:1")),
-        "align self":
-            R(Text("align-self:;") + Key("left/10:1")),
-        "flex shrink":
-            R(Text("flex-shrink:;") + Key("left/10:1")),
-        "flex basis":
-            R(Text("flex-basis:;") + Key("left/10:1")),
-        "order":
-            R(Text("order:;") + Key("left/10:1")),
-
-
-        #values
-        "url":
-            R(Text("url()") + Key("left/10:1")),
-        "rgb":
-            R(Text("rgb(,,)") + Key("left/10:3")),
-        "rgba":
-            R(Text("rgba(,,,)") + Key("left/10:4")),
-        
-
-    }
-    extras = [
-        ShortIntegerRef("ln1", 1, 1000),
-    ]
-    defaults = {}
-
-def get_rule():
-    return CSS, RuleDetails(ccrtype=CCRType.GLOBAL)
\ No newline at end of file
diff --git a/castervoice/rules/ccr/dart_rules/__init__.py b/castervoice/rules/ccr/dart_rules/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/castervoice/rules/ccr/dart_rules/dart.py b/castervoice/rules/ccr/dart_rules/dart.py
deleted file mode 100644
index e8080ba18..000000000
--- a/castervoice/rules/ccr/dart_rules/dart.py
+++ /dev/null
@@ -1,128 +0,0 @@
-'''
-Created on 2018-05-27 from javascript.py
-@author: comodoro
-'''
-from dragonfly import Key
-
-from castervoice.lib.actions import Text
-from castervoice.rules.ccr.standard import SymbolSpecs
-from castervoice.lib.const import CCRType
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.mergerule import MergeRule
-from castervoice.lib.merge.state.short import R
-
-
-class Dart(MergeRule):
-    mapping = {
-
-        # CCR PROGRAMMING STANDARD
-        SymbolSpecs.IF:
-            R(Text("if () {}") + Key("left, enter:2, up")),
-        SymbolSpecs.ELSE:
-            R(Text("else {}") + Key("left, enter:2, up")),
-        #
-        SymbolSpecs.SWITCH:
-            R(Text("switch () {}") + Key("left, enter:2, up")),
-        SymbolSpecs.CASE:
-            R(Text("case :") + Key("left")),
-        SymbolSpecs.BREAK:
-            R(Text("break;")),
-        SymbolSpecs.DEFAULT:
-            R(Text("default: ")),
-        #
-        SymbolSpecs.DO_LOOP:
-            R(Text("do {}") + Key("left, enter:2")),
-        SymbolSpecs.WHILE_LOOP:
-            R(Text("while ()") + Key("left")),
-        SymbolSpecs.FOR_LOOP:
-            R(Text("for (var i = 0; i < TOKEN; i++)")),
-        SymbolSpecs.FOR_EACH_LOOP:
-            R(Text("for (TOKEN in TOKEN)")),
-        #
-        SymbolSpecs.TO_INTEGER:
-            R(Text("int.parse()") + Key("left")),
-        SymbolSpecs.TO_FLOAT:
-            R(Text("double.parse()") + Key("left")),
-        SymbolSpecs.TO_STRING:
-            R(Text(".toString()")),
-        #
-        SymbolSpecs.AND:
-            R(Text(" && ")),
-        SymbolSpecs.OR:
-            R(Text(" || ")),
-        SymbolSpecs.NOT:
-            R(Text("!")),
-        #
-        SymbolSpecs.SYSOUT:
-            R(Text("print()") + Key("left")),
-
-        SymbolSpecs.IMPORT:
-            R(Text("import ''") + Key("left")),
-
-        SymbolSpecs.FUNCTION:
-            R(Text("TOKEN() {}") + Key("left, enter")),
-
-        SymbolSpecs.CLASS:
-            R(Text("class {}") + Key("left/5:2")),
-        #
-        SymbolSpecs.COMMENT:
-            R(Text("//")),
-        SymbolSpecs.LONG_COMMENT:
-            R(Text("/**/") + Key("left,left")),
-        #
-        SymbolSpecs.NULL:
-            R(Text("null")),
-        #
-        SymbolSpecs.RETURN:
-            R(Text("return ")),
-        #
-        SymbolSpecs.TRUE:
-            R(Text("true")),
-        SymbolSpecs.FALSE:
-            R(Text("false")),
-
-        # Dart specific
-        "anon funk":
-            R(Text("() => {}") + Key("left:1, enter")),
-        "length":
-            R(Text("length")),
-        "self":
-            R(Text("self")),
-        "new new":
-            R(Text("new ")),
-        "continue":
-            R(Text("continue")),
-        "this":
-            R(Text("this")),
-        "try":
-            R(Text("try {}") + Key("left, enter:2, up")),
-        "catch":
-            R(Text("catch(e) {}") + Key("left, enter:2, up")),
-        "throw":
-            R(Text("throw ")),
-        "instance of":
-            R(Text("instanceof ")),
-        "const":
-            R(Text("const ")),
-        "equals if null":
-            R(Text(" ??= ")),
-        "a sink":
-            R(Text("async ")),
-        "await":
-            R(Text("await ")),
-        "yield":
-            R(Text("yield ")),
-        "cascade":
-            R(Key("enter") + Text("..")),
-        "dock string":
-            R(Text("/// ")),
-        "var":
-            R(Text("var TOKEN = ")),
-    }
-
-    extras = []
-    defaults = {}
-
-
-def get_rule():
-    return Dart, RuleDetails(ccrtype=CCRType.GLOBAL)
diff --git a/castervoice/rules/ccr/go_rules/__init__.py b/castervoice/rules/ccr/go_rules/__init__.py
deleted file mode 100644
index 8b1378917..000000000
--- a/castervoice/rules/ccr/go_rules/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/castervoice/rules/ccr/go_rules/go.py b/castervoice/rules/ccr/go_rules/go.py
deleted file mode 100644
index e907008b3..000000000
--- a/castervoice/rules/ccr/go_rules/go.py
+++ /dev/null
@@ -1,99 +0,0 @@
-'''
-Created November 2018
-@author: Mike Roberts
-'''
-from dragonfly import Key
-
-from castervoice.lib.actions import Text
-from castervoice.rules.ccr.standard import SymbolSpecs
-from castervoice.lib.const import CCRType
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.mergerule import MergeRule
-from castervoice.lib.merge.state.short import R
-
-
-class Go(MergeRule):
-
-    mapping = {
-        SymbolSpecs.IF:
-            R(Text("if  {}") + Key("left, enter, up, end, left:2")),
-        SymbolSpecs.ELSE:
-            R(Text("else {}") + Key("left, enter, up")),
-        #
-        SymbolSpecs.SWITCH:
-            R(Text("switch  {}") + Key("left, enter, up, end, left:2")),
-        SymbolSpecs.CASE:
-            R(Text("case :") + Key("left")),
-        SymbolSpecs.DEFAULT:
-            R(Text("default:") + Key("enter")),
-        SymbolSpecs.BREAK:
-            R(Text("break")),
-        #
-        SymbolSpecs.WHILE_LOOP:
-            R(Text("for  {}") + Key("left, enter, up, end, left:2")),
-        SymbolSpecs.FOR_LOOP:
-            R(Text("for i := 0; i<; i++ {}") + Key("left, enter, up, end, left:7")),
-        SymbolSpecs.FOR_EACH_LOOP:
-            R(Text("for  := range  {}") + Key("left, enter, up, home, right:4")),
-        #
-        SymbolSpecs.TO_INTEGER:
-            R(Text("strconv.Atoi()") + Key("left")),
-        SymbolSpecs.TO_STRING:
-            R(Text("strconv.Itoa()") + Key("left")),
-        #
-        SymbolSpecs.AND:
-            R(Text(" && ")),
-        SymbolSpecs.OR:
-            R(Text(" || ")),
-        SymbolSpecs.NOT:
-            R(Text("!")),
-        #
-        SymbolSpecs.SYSOUT:
-            R(Text("fmt.Println()") + Key("left")),
-        #
-        SymbolSpecs.IMPORT:
-            R(Text("import ()") + Key("left, enter")),
-        #
-        SymbolSpecs.FUNCTION:
-            R(Text("func ")),
-        SymbolSpecs.CLASS:
-            R(Text("type  struct {}") + Key("left, enter, up, home, right:5")),
-        #
-        SymbolSpecs.COMMENT:
-            R(Text("//")),
-        SymbolSpecs.LONG_COMMENT:
-            R(Text("/**/") + Key("left, left")),
-        #
-        SymbolSpecs.NULL:
-            R(Text("nil")),
-        #
-        SymbolSpecs.RETURN:
-            R(Text("return ")),
-        #
-        SymbolSpecs.TRUE:
-            R(Text("true")),
-        SymbolSpecs.FALSE:
-            R(Text("false")),
-        #
-        "[type] (inter | integer)":
-            R(Text("int")),
-        "[type] boolean":
-            R(Text("bool")),
-        "[type] string":
-            R(Text("string")),
-        "assign":
-            R(Text(" := ")),
-        "(function | funk) main":
-            R(Text("func main() {}") + Key("left, enter")),
-        "make map":
-            R(Text("make(map[])") + Key("left:2")),
-        "package":
-            R(Text("package ")),
-    }
-
-    extras = []
-    defaults = {}
-
-
-def get_rule():
-    return Go, RuleDetails(ccrtype=CCRType.GLOBAL)
diff --git a/castervoice/rules/ccr/haxe_rules/__init__.py b/castervoice/rules/ccr/haxe_rules/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/castervoice/rules/ccr/haxe_rules/haxe.py b/castervoice/rules/ccr/haxe_rules/haxe.py
deleted file mode 100644
index 033fd3c8b..000000000
--- a/castervoice/rules/ccr/haxe_rules/haxe.py
+++ /dev/null
@@ -1,123 +0,0 @@
-from castervoice.lib.actions import Text, Key
-from castervoice.rules.ccr.standard import SymbolSpecs
-from castervoice.lib.const import CCRType
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.merge.mergerule import MergeRule
-from castervoice.lib.merge.state.short import R
-
-
-class Haxe(MergeRule):
-    pronunciation = "hacks"
-
-    mapping = {
-        SymbolSpecs.IF:
-            R(Key("i, f, lparen, rparen, left")),
-        SymbolSpecs.ELSE:
-            R(Key("e, l, s, e")),
-        #
-        SymbolSpecs.SWITCH:
-            R(Text("switch(){\ncase : TOKEN;\ndefault: TOKEN;") + Key("up,up,left,left")),
-        SymbolSpecs.CASE:
-            R(Text("case :") + Key("left")),
-        SymbolSpecs.BREAK:
-            R(Text("break;")),
-        SymbolSpecs.DEFAULT:
-            R(Text("default: ")),
-        #
-        SymbolSpecs.DO_LOOP:
-            R(Text("do TOKEN while()") + Key("left, enter:2")),
-        SymbolSpecs.WHILE_LOOP:
-            R(Text("while ()") + Key("left")),
-        SymbolSpecs.FOR_LOOP:
-            R(Text("for (i in 0...TOKEN)")),
-        SymbolSpecs.FOR_EACH_LOOP:
-            R(Text("for (TOKEN in TOKEN)")),
-        #
-        SymbolSpecs.TO_INTEGER:
-            R(Text("Std.int()") + Key("left")),
-        SymbolSpecs.TO_FLOAT:
-            R(Text("Std.parseFloat()") + Key("left")),
-        SymbolSpecs.TO_STRING:
-            R(Text("Std.string()") + Key("left")),
-        #
-        SymbolSpecs.AND:
-            R(Text("&&")),
-        SymbolSpecs.OR:
-            R(Text("||")),
-        SymbolSpecs.NOT:
-            R(Text("!")),
-        #
-        SymbolSpecs.SYSOUT:
-            R(Text("trace()") + Key("left")),
-
-        #
-        SymbolSpecs.FUNCTION:
-            R(Text("function ")),
-        SymbolSpecs.CLASS:
-            R(Text("class ")),
-        #
-        SymbolSpecs.COMMENT:
-            R(Text("//")),
-        SymbolSpecs.LONG_COMMENT:
-            R(Text("/**/") + Key("left, left")),
-        #
-        SymbolSpecs.NULL:
-            R(Text("null")),
-        #
-        SymbolSpecs.RETURN:
-            R(Text("return ")),
-        #
-        SymbolSpecs.TRUE:
-            R(Text("true")),
-        SymbolSpecs.FALSE:
-            R(Text("false")),
-
-        # Haxe specific
-        "import":
-            R(Text("import ")),
-        "new new":
-            R(Text("new ")),
-        "instance of":
-            R(Text("Std.is()") + Key("left")),
-        "anon funk":
-            R(Text("->")),
-        "map of":
-            R(Text("Map()")),
-        "array of":
-            R(Text("Array()") + Key("left")),
-        "far | variable":
-            R(Text("var ")),
-        "boolean":
-            R(Text("Bool ")),
-        "integer":
-            R(Text("Int ")),
-        "double":
-            R(Text("Float ")),
-        "dynamic":
-            R(Text("Dynamic")),
-        "void":
-            R(Text("Void")),
-        "string":
-            R(Text("String ")),
-        "public":
-            R(Text("public ")),
-        "private":
-            R(Text("private ")),
-        "static":
-            R(Text("static ")),
-        "this":
-            R(Text("this")),
-        "safe cast":
-            R(Text("cast (TOKEN, TOKEN)")),
-        "get class":
-            R(Text("Type.getClass()") + Key("left")),
-        "get name":
-            R(Text("Type.getClassName()") + Key("left"))
-    }
-
-    extras = []
-    defaults = {}
-
-
-def get_rule():
-    return Haxe, RuleDetails(ccrtype=CCRType.GLOBAL)
diff --git a/castervoice/rules/ccr/html_rules/__init__.py b/castervoice/rules/ccr/html_rules/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/castervoice/rules/ccr/html_rules/html_rule.py b/castervoice/rules/ccr/html_rules/html_rule.py
deleted file mode 100644
index 27fdec90f..000000000
--- a/castervoice/rules/ccr/html_rules/html_rule.py
+++ /dev/null
@@ -1,309 +0,0 @@
-from castervoice.lib.actions import Key
-from castervoice.lib import settings, printer
-from castervoice.lib.const import CCRType
-from castervoice.lib.ctrl.mgr.rule_details import RuleDetails
-from castervoice.lib.context import AppContext
-
-from castervoice.lib.merge.mergerule import MergeRule
-from castervoice.lib.merge.state.short import R
-
-
-# HTML auto complete workaround for Jetbrains Products
-# If more applications have issues with auto complete may be moved to actions.py
-_context = AppContext(executable=["idea", "idea64", "studio64", "pycharm", "webstorm64", "webstorm"])
-
-if _context:
-    from dragonfly.actions.action_paste import Paste as Text
-    if settings.settings(["miscellaneous", "use_aenea"]):
-        try:
-            from aenea import Paste as Text
-        except ImportError:
-            printer.out("Unable to import aenea Paste actions. Dragonfly actions will be used "
-                  "instead.")
-else:
-    from castervoice.lib.actions import Text
-
-
-class HTML(MergeRule):
-    pronunciation = "html"
-
-    mapping = {
-        # A macro with ## is depreciated HTML.
-        #Macros
-        "make link":
-            R(Text("") + Key("left/10:6")),
-        "table macro":
-            R(
-                Text("") + Key("enter") + Text("") + Key("enter") +
-                Text("") + Key("enter") + Text("") + Key("enter") +
-                Text("
")), - "check box": - R(Text("")), - #HTML elements - #Basic or Root elements - "HTML": - R(Text("") + Key("enter") + Text("") + Key("up")), - "doc type": - R(Text("") + Key("enter")), - #Document metadata - "base": - R(Text("") + Key("left/10:1")), - "head": - R(Text("") + Key("enter") + Text("") + Key("up")), - "link": - R(Text("") + Key("left/10:1")), - "meta": - R(Text("") + Key("left/10:1")), - "style": - R(Text("")), - "title": - R(Text("") + Key("left/10:8")), - #Content sectioning - "address ": - R(Text("
") + Key("enter") + Text("
") + Key("up")), - "article ": - R(Text("
")), - "close article": - R(Text("
")), - "body": - R(Text("") + Key("enter") + Text("") + Key("up")), - "footer": - R(Text("
") + Key("enter") + Text("
") + Key("up")), - "header": - R(Text("
") + Key("enter") + Text("
") + Key("up")), - "H 1 | heading one": - R(Text("

") + Key("left/10:5")), - "H 2 | heading to": - R(Text("

") + Key("left/10:5")), - "H 3 | heading three": - R(Text("

") + Key("left/10:5")), - "H 4 | heading for": - R(Text("

") + Key("left/10:5")), - "H 5 | heading five": - R(Text("
") + Key("left/10:5")), - "H 6 | heading six": - R(Text("
") + Key("left/10:5")), - "H group | headings group": - R(Text("
") + Key("left/10:9")), - "navigation | navigate": - R(Text("") + Key("up")), - "section": - R(Text("
") + Key("enter") + Text("
") + Key("up")), - # Text content - "description | DD": - R(Text("
")), - "division": - R(Text("
") + Key("left/10:6")), - "list element | DL": - R(Text("
")), - "fig caption": - R(Text("
")), - "figure": - R(Text("
")), - "H are | HR": - R(Text("
")), - "list item | LI": - R(Text("
  • ") + Key("left/10:5")), - "main": - R(Text("
    ") + Key("enter") + Text("
    ") + Key("up")), - "ordered list | OL": - R(Text("
      ") + Key("enter") + Text("
    ") + Key("up")), - "paragraph": - R(Text("

    ") + Key("enter") + Text("

    ") + Key("up")), - "pre format": - R(Text("
    ") + Key("enter") + Text("
    ") + Key("up")), - "unordered list | UL": - R(Text("
      ") + Key("enter") + Text("
    ") + Key("up")), - #Inline text semantics - "anchor": - R(Text("") + Key("left/10:4")), - "abbreviation": - R(Text("") + Key("left/10:7")), - "bold": - R(Text("") + Key("left/10:4")), - "override": - R(Text("") + Key("left/10:6")), - "isolate | bi directional isolation": - R(Text("") + Key("left/10:6")), - "break | be are | BR": - R(Text("
    ") + Key("enter")), - "code": - R(Text("") + Key("left/10:7")), - "data": - R(Text("") + Key("left/10:7")), - "defining instance": - R(Text("") + Key("left/10:6")), - "emphasis | EM": - R(Text("") + Key("left/10:5")), - "semantics | italics": - R(Text("") + Key("left/10:4")), - "keyboard input": - R(Text("") + Key("left/10:6")), - "mark | highlight": - R(Text("") + Key("left/10:7")), - "quote": - R(Text("") + Key("left/10:4")), - "fall back parenthesis | RP": - R(Text("") + Key("left/10:5")), - "embraces pronunciation | RT": - R(Text("") + Key("left/10:5")), - "ruby | pronounce asian": - R(Text("") + Key("left/10:7")), - ##"strike through | strike": Text("")+ Key("left/10:4")), - "deleted text | deleted | replaced": - R(Text("") + Key("left/10:6")), - "sample output": - R(Text("") + Key("left/10:7")), - "small": - R(Text("") + Key("left/10:8")), - "span": - R(Text("") + Key("left/10:7")), - "strong": - R(Text("") + Key("left/10:9")), - "subscript": - R(Text("") + Key("left/10:6")), - "super script": - R(Text("") + Key("left/10:6")), - "time": - R(Text("") + Key("left/10:7")), - "underline": - R(Text("") + Key("left/10:4")), - "variable": - R(Text("") + Key("left/10:6")), - "optional break": - R(Text("") + Key("left/10:6")), - #Image & multimedia - "area": - R(Text("") + Key("left/10:2")), - "audio": - R(Text("") + Key("up")), - "image ": - R(Text("") + Key("left/10:6")), - "map": - R(Text("") + Key("enter") + Text("") + Key("up")), - "track": - R(Text("") + Key("left/10:1")), - "video": - R(Text("")), - #embedded content - "embedded": - R(Text("") + Key("left/10:1")), - "inline frame": - R(Text("") + Key("left/10:1")), - "object | embedded object": - R(Text("") + Key("left/10:1")), - "parameter ": - R(Text("") + Key("left/10:1")), - "source": - R(Text("") + Key("left/10:1")), - #Scripting - "canvas": - R(Text("") + Key("left/10:1")), - "canvas close": - R(Text("")), - "noscript": - R(Text("") + Key("up")), - "script": - R(Text("") + Key("left/10:9")), - #Edits - "inserted text | inserted": - R(Text("") + Key("left/10:6")), - #Table content - "table caption | tee caption": - R(Text("")), - "table column | tee column": - R(Text("")), - "table column group | tee group": - R(Text("")), - "table": - R(Text("")), - "table body": - R(Text("")), - "table cell | TD | tee D": - R(Text("") + Key("left/10:5")), - "table foot": - R(Text("")), - "table header | TH": - R(Text("")), - "table row | tee are": - R(Text("") + Key("left/10:5")), - #Forms - "button": - R(Text("") + Key("left/10:9")), - "data list": - R(Text("") + Key("enter") + Text("") + Key("up")), - "field set": - R(Text("
    ") + Key("enter") + Text("
    ") + Key("up")), - "field set close": - R(Text("")), - "form": - R(Text("") + Key("enter") + Text("") + Key("up")), - "input": - R(Text("") + Key("left/10:1")), - "key gen": - R(Text("") + Key("left/10:1")), - "label": - R(Text("")), - "legend": - R(Text("")), - "meter": - R(Text("") + Key("left/10:1")), - "meter close": - R(Text("")), - "opt group": - R(Text("") + Key("enter") + Text("") + Key("up")), - "option": - R(Text("")), - "output": - R(Text("") + Key("left/10:1")), - "output close": - R(Text("")), - "progress": - R(Text("") + Key("left/10:1")), - "select": - R(Text("") + Key("up")), - "text area": - R(Text("")), - #Interactive elements - "details": - R(Text("
    ")), - "dialog": - R(Text("")), - "menu": - R(Text("")), - "menu item": - R(Text("")), - "summary": - R(Text("")), - #Web Components: As defined in (W3C) - "content": - R(Text("")), - "decorator": - R(Text("")), - "element": - R(Text("")), - "shadow": - R(Text("")), - "template": - R(Text("
    ")), - "table head | thead": - R(Text("