├── .gitignore ├── .project ├── .settings └── org.eclipse.core.resources.prefs ├── .travis.yml ├── LICENSE ├── README.md ├── RELEASING ├── com.asparck.eclipse.multicursor.feature ├── .project ├── .settings │ └── org.eclipse.core.resources.prefs ├── build.properties ├── feature.xml └── pom.xml ├── com.asparck.eclipse.multicursor.p2updatesite ├── .project ├── .settings │ └── org.eclipse.core.resources.prefs ├── category.xml └── pom.xml ├── com.asparck.eclipse.multicursor.plugin ├── .classpath ├── .project ├── .settings │ ├── org.eclipse.core.resources.prefs │ ├── org.eclipse.jdt.core.prefs │ └── org.eclipse.jdt.ui.prefs ├── META-INF │ └── MANIFEST.MF ├── build.properties ├── plugin.xml ├── pom.xml └── src │ └── com │ └── asparck │ └── eclipse │ └── multicursor │ ├── Logger.java │ ├── MultiCursorPlugin.java │ ├── copied │ └── DeleteBlockingExitPolicy.java │ ├── hacks │ └── ISourceViewerFinder.java │ ├── handlers │ ├── SelectAllOccurrencesHandler.java │ └── SelectNextOccurrenceHandler.java │ └── util │ ├── CoordinatesUtil.java │ └── TextUtil.java ├── com.asparck.eclipse.multicursor.target ├── .project ├── com.asparck.eclipse.multicursor.target.target └── pom.xml ├── com.asparck.eclipse.multicursor.tests ├── .classpath ├── .project ├── .settings │ ├── org.eclipse.core.resources.prefs │ └── org.eclipse.jdt.core.prefs ├── META-INF │ └── MANIFEST.MF ├── build.properties ├── pom.xml └── src │ └── com │ └── asparck │ └── eclipse │ └── multicursor │ ├── tests │ └── Activator.java │ └── util │ └── TextUtilTest.java ├── pom.xml ├── redownload-p2-plugin-jars.sh └── release.sh /.gitignore: -------------------------------------------------------------------------------- 1 | */bin 2 | */target 3 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.asparck.eclipse.multicursor.parent 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 1395452751685 14 | 15 | 10 16 | 17 | org.eclipse.ui.ide.multiFilter 18 | 1.0-name-matches-false-false-com.asparck.eclipse.multicursor.* 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk7 4 | # set the install script to 'true' succeed in installing without doing anything 5 | install: true 6 | script: mvn verify 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Eclipse Public License - v 1.0 2 | 3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and 10 | b) in the case of each subsequent Contributor: 11 | i) changes to the Program, and 12 | ii) additions to the Program; 13 | where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. 14 | "Contributor" means any person or entity that distributes the Program. 15 | 16 | "Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. 17 | 18 | "Program" means the Contributions distributed in accordance with this Agreement. 19 | 20 | "Recipient" means anyone who receives the Program under this Agreement, including all Contributors. 21 | 22 | 2. GRANT OF RIGHTS 23 | 24 | a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. 25 | b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. 26 | c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. 27 | d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. 28 | 3. REQUIREMENTS 29 | 30 | A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: 31 | 32 | a) it complies with the terms and conditions of this Agreement; and 33 | b) its license agreement: 34 | i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; 35 | ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; 36 | iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and 37 | iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. 38 | When the Program is made available in source code form: 39 | 40 | a) it must be made available under this Agreement; and 41 | b) a copy of this Agreement must be included with each copy of the Program. 42 | Contributors may not remove or alter any copyright notices contained within the Program. 43 | 44 | Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. 45 | 46 | 4. COMMERCIAL DISTRIBUTION 47 | 48 | Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. 49 | 50 | For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. 51 | 52 | 5. NO WARRANTY 53 | 54 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. 55 | 56 | 6. DISCLAIMER OF LIABILITY 57 | 58 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 59 | 60 | 7. GENERAL 61 | 62 | If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. 63 | 64 | If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. 65 | 66 | All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. 67 | 68 | Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. 69 | 70 | This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | What is this? 2 | ============= 3 | 4 | An *aborted* attempt to provide Sublime-Text-like multi cursor support for text editors in the Eclipse IDE (3.7 and later). 5 | 6 | [![Build Status](https://travis-ci.org/caspark/eclipse-multicursor.svg?branch=master)](https://travis-ci.org/caspark/eclipse-multicursor) 7 | 8 | What works? 9 | ----------- 10 | 11 | I intended to implement full multi cursor behaviour in this plugin, but stopped using Eclipse before I got more than bits and pieces of that working. So at the moment this plugin is implemented under the covers by using Eclipse linked mode editing (similar to existing "rename in file" functionality), so **you can't move the cursors outside the initial selection areas, and all multiple-cursor-edited-text must be the same string.** 12 | 13 | Usage 14 | ----- 15 | 16 | * `Alt+J` (OSX: `Ctrl+G`): "Select Next Occurrence" of the selected text & start editing it. Repeat to select remaining occurrences. 17 | * `Alt+F3` (OSX: `Ctrl+Cmd+G`): "Select All Occurrences" of the selected text & start editing all of them at once. 18 | 19 | (If you haven't got anything selected, it'll expand your selection to the word under the cursor, or to the whole line if the cursor is in whitespace.) 20 | 21 | What's next? 22 | ------------ 23 | 24 | Nothing from me. I'm not using Eclipse any more and don't have much interest in continuing this project as a result. 25 | 26 | Ideally, I'd like to hand this project over to someone else, as I still believe it's very doable to create a real implementation (i.e. not using Eclipse linked mode). Open an issue if you're interested. 27 | 28 | Getting and installing it 29 | ------------------------- 30 | 31 | Get the latest release from the [releases page] and follow the install instructions below. 32 | 33 | You have 2 options for installing (pick one): 34 | 35 | *Option 1:* [Download](https://github.com/caspark/eclipse-multicursor/releases) the P2 update site (i.e. `com.asparck.eclipse.multicursor.p2updatesite-X.Y.Z.zip`), then in Eclipse choose Help >> Install New Software >> Add >> Archive >> choose the downloaded P2 update site >> tick the box to select Eclipse Multicursor >> go through the rest of the wizard >> ignore any warnings about unsigned content (just click OK) >> restart Eclipse when prompted. You can uninstall it later by going to Help >> About Eclipse >> Installation Details >> select "Eclipse Multicursor" >> Uninstall >> restart Eclipse when prompted. 36 | 37 | *Option 2:* [Download](https://github.com/caspark/eclipse-multicursor/releases) `com.asparck.eclipse.multicursor.plugin_X.Y.Z.jar` and put it in `eclipse/plugins/dropins`, then restart Eclipse. You can uninstall it by shutting down Eclipse and deleting the jar from the dropins directory. 38 | 39 | The former is the official recommended way of installing plugins & the latter is the quick and dirty way. 40 | 41 | After installing, look at the *what works?* section above to use it. 42 | 43 | Building from source 44 | -------------------- 45 | 46 | Uses [Tycho](https://eclipse.org/tycho/) for building via Maven 3: 47 | 48 | mvn verify 49 | 50 | This: 51 | 52 | * looks at `c.a.e.m.target/c.a.e.m.target.target` to find the repo to get Eclipse OSGi dependency bundles from 53 | * builds the plugin, feature, and update site in the target directories of `c.a.e.m.plugin`, `c.a.e.m.feature`, and `c.a.e.m.p2updatesite` 54 | * runs the tests in `c.a.e.m.tests` 55 | 56 | Installing after building 57 | ------------------------- 58 | 59 | After building, point your Eclipse at the update site in `c.a.e.m.p2updatesite\target` and install the feature contained therein. 60 | 61 | Developing 62 | ---------- 63 | 64 | Using Eclipse, with the Plugin Development Environment (PDE) plugins installed: 65 | 66 | 1. Import the projects from the repo as Existing Eclipse projects 67 | 2. Open `c.a.e.m.target/c.a.e.m.target.target` and click the "activate this target platform" link on the top right of the editor that opens 68 | 3. Right click on `c.a.e.m.plugin` and choose `Debug As` >> `Eclipse Application` 69 | 4. You can also right click on tests in `c.a.e.m.tests` to run them as either plugin tests or normal JUnit tests. 70 | 71 | Note that the target platform you activate this way is more restricted than the target platform that Tycho will build with when you `mvn verify`. Tycho only uses the `.target` file to find which P2 repo it should search, and it ignores any restrictions in the enabled features of the target platform. 72 | -------------------------------------------------------------------------------- /RELEASING: -------------------------------------------------------------------------------- 1 | Release Process 2 | =============== 3 | 4 | You do not need to follow these steps if you only want to build a version for personal use (see the README). 5 | 6 | Please do not release this project if you are not the current maintainer. 7 | 8 | Scripted 9 | -------- 10 | 11 | Use the release script and specify: the release version, the next development version, and the directory to copy the built artifacts to. For example, to release v0.1.1 and have the next version being developed be 0.1.2(-SNAPSHOT): 12 | 13 | mkdir -p ~/tmp/release && ./release.sh 0.1.1 0.1.2 ~/tmp/release && ls ~/tmp/release 14 | 15 | Manually 16 | -------- 17 | 18 | # Update the version in the pom files to the release version (e.g. 0.1.0): 19 | com.asparck.eclipse.multicursor.feature/pom.xml 20 | com.asparck.eclipse.multicursor.p2updatesite/pom.xml 21 | com.asparck.eclipse.multicursor.plugin/pom.xml 22 | com.asparck.eclipse.multicursor.target/pom.xml 23 | com.asparck.eclipse.multicursor.tests/pom.xml 24 | pom.xml 25 | 26 | # Update the OSGi manifest versions to the release version (e.g. 0.1.0): 27 | com.asparck.eclipse.multicursor.plugin/META-INF/MANIFEST.MF 28 | com.asparck.eclipse.multicursor.tests/META-INF/MANIFEST.MF 29 | 30 | # Update the feature version and the plugin version in the P2 feature definition to the release version (e.g. 0.1.0): 31 | com.asparck.eclipse.multicursor.feature/feature.xml 32 | 33 | # Update the feature version and filename in the P2 update site category definition to the release version and release filename (e.g. 0.1.0 and features/com.asparck.eclipse.multicursor.feature_0.1.0.jar) 34 | com.asparck.eclipse.multicursor.p2updatesite/category.xml 35 | 36 | # Build the release: 37 | mvn clean verify 38 | 39 | # Commit and tag the release: 40 | git commit -a -m "Release: prepare for v$RELEASE_VERSION release" 41 | git tag v$RELEASE_VERSION 42 | 43 | # Update the version in the pom files to the new Maven development version (e.g. 0.1.1-SNAPSHOT): 44 | com.asparck.eclipse.multicursor.feature/pom.xml 45 | com.asparck.eclipse.multicursor.p2updatesite/pom.xml 46 | com.asparck.eclipse.multicursor.plugin/pom.xml 47 | com.asparck.eclipse.multicursor.target/pom.xml 48 | com.asparck.eclipse.multicursor.tests/pom.xml 49 | pom.xml 50 | 51 | # Update the OSGi manifest versions to the new OSGi development version (e.g. 0.1.1.qualifier): 52 | com.asparck.eclipse.multicursor.plugin/META-INF/MANIFEST.MF 53 | com.asparck.eclipse.multicursor.tests/META-INF/MANIFEST.MF 54 | 55 | # Update the feature version and the plugin version in the P2 feature definition to the new OSGi development version (e.g. 0.1.1.qualifier): 56 | com.asparck.eclipse.multicursor.feature/feature.xml 57 | 58 | # Update the feature version and filename in the P2 update site category definition to the new OSGI development version and development filename (e.g. 0.1.1.qualifier and features/com.asparck.eclipse.multicursor.feature_0.1.1.qualifier.jar) 59 | com.asparck.eclipse.multicursor.p2updatesite/category.xml 60 | 61 | # Verify the development version works: 62 | mvn clean verify 63 | 64 | # Commit and push changes: 65 | git commit -a -m "Release: prepare for next development cycle" 66 | git push 67 | 68 | # Publish a release on github and upload the P2 update site + plugin jar as binaries. 69 | https://github.com/caspark/eclipse-multicursor/releases/new -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.feature/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.asparck.eclipse.multicursor.feature 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.pde.FeatureBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.pde.FeatureNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.feature/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.feature/build.properties: -------------------------------------------------------------------------------- 1 | bin.includes = feature.xml 2 | src.includes = feature.xml,\ 3 | build.properties,\ 4 | pom.xml 5 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.feature/feature.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | Provides multiple cursor support for Eclipse. 10 | 11 | 12 | 13 | Copyright Caspar Krieger 2013-2014 14 | 15 | 16 | 17 | Eclipse Public License - v 1.0 18 | 19 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 20 | 21 | 1. DEFINITIONS 22 | 23 | "Contribution" means: 24 | 25 | a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and 26 | b) in the case of each subsequent Contributor: 27 | i) changes to the Program, and 28 | ii) additions to the Program; 29 | where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. 30 | "Contributor" means any person or entity that distributes the Program. 31 | 32 | "Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. 33 | 34 | "Program" means the Contributions distributed in accordance with this Agreement. 35 | 36 | "Recipient" means anyone who receives the Program under this Agreement, including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. 41 | b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. 42 | c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. 43 | d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. 44 | 3. REQUIREMENTS 45 | 46 | A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: 47 | 48 | a) it complies with the terms and conditions of this Agreement; and 49 | b) its license agreement: 50 | i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; 51 | ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; 52 | iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and 53 | iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. 54 | When the Program is made available in source code form: 55 | 56 | a) it must be made available under this Agreement; and 57 | b) a copy of this Agreement must be included with each copy of the Program. 58 | Contributors may not remove or alter any copyright notices contained within the Program. 59 | 60 | Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. 61 | 62 | 4. COMMERCIAL DISTRIBUTION 63 | 64 | Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. 65 | 66 | For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. 67 | 68 | 5. NO WARRANTY 69 | 70 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. 71 | 72 | 6. DISCLAIMER OF LIABILITY 73 | 74 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 75 | 76 | 7. GENERAL 77 | 78 | If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. 79 | 80 | If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. 81 | 82 | All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. 83 | 84 | Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. 85 | 86 | This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. 87 | 88 | 89 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.feature/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | com.asparck.eclipse.multicursor 8 | parent 9 | 0.1.5-SNAPSHOT 10 | 11 | 12 | com.asparck.eclipse.multicursor.feature 13 | eclipse-feature 14 | 15 | 16 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.p2updatesite/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.asparck.eclipse.multicursor.p2updatesite 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.p2updatesite/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.p2updatesite/category.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Multiple Cursor support for Eclipse 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.p2updatesite/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | com.asparck.eclipse.multicursor 8 | parent 9 | 0.1.5-SNAPSHOT 10 | 11 | 12 | com.asparck.eclipse.multicursor.p2updatesite 13 | eclipse-repository 14 | 15 | 16 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.asparck.eclipse.multicursor.plugin 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.pde.ManifestBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.pde.SchemaBuilder 20 | 21 | 22 | 23 | 24 | 25 | org.eclipse.pde.PluginNature 26 | org.eclipse.jdt.core.javanature 27 | 28 | 29 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 4 | org.eclipse.jdt.core.compiler.compliance=1.6 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.source=1.6 8 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/.settings/org.eclipse.jdt.ui.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true 3 | sp_cleanup.add_default_serial_version_id=true 4 | sp_cleanup.add_generated_serial_version_id=false 5 | sp_cleanup.add_missing_annotations=true 6 | sp_cleanup.add_missing_deprecated_annotations=true 7 | sp_cleanup.add_missing_methods=false 8 | sp_cleanup.add_missing_nls_tags=false 9 | sp_cleanup.add_missing_override_annotations=true 10 | sp_cleanup.add_missing_override_annotations_interface_methods=true 11 | sp_cleanup.add_serial_version_id=false 12 | sp_cleanup.always_use_blocks=true 13 | sp_cleanup.always_use_parentheses_in_expressions=false 14 | sp_cleanup.always_use_this_for_non_static_field_access=false 15 | sp_cleanup.always_use_this_for_non_static_method_access=false 16 | sp_cleanup.convert_to_enhanced_for_loop=false 17 | sp_cleanup.correct_indentation=true 18 | sp_cleanup.format_source_code=false 19 | sp_cleanup.format_source_code_changes_only=false 20 | sp_cleanup.make_local_variable_final=false 21 | sp_cleanup.make_parameters_final=false 22 | sp_cleanup.make_private_fields_final=true 23 | sp_cleanup.make_type_abstract_if_missing_method=false 24 | sp_cleanup.make_variable_declarations_final=true 25 | sp_cleanup.never_use_blocks=false 26 | sp_cleanup.never_use_parentheses_in_expressions=true 27 | sp_cleanup.on_save_use_additional_actions=true 28 | sp_cleanup.organize_imports=false 29 | sp_cleanup.qualify_static_field_accesses_with_declaring_class=false 30 | sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true 31 | sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true 32 | sp_cleanup.qualify_static_member_accesses_with_declaring_class=false 33 | sp_cleanup.qualify_static_method_accesses_with_declaring_class=false 34 | sp_cleanup.remove_private_constructors=true 35 | sp_cleanup.remove_trailing_whitespaces=true 36 | sp_cleanup.remove_trailing_whitespaces_all=true 37 | sp_cleanup.remove_trailing_whitespaces_ignore_empty=false 38 | sp_cleanup.remove_unnecessary_casts=true 39 | sp_cleanup.remove_unnecessary_nls_tags=false 40 | sp_cleanup.remove_unused_imports=true 41 | sp_cleanup.remove_unused_local_variables=false 42 | sp_cleanup.remove_unused_private_fields=true 43 | sp_cleanup.remove_unused_private_members=false 44 | sp_cleanup.remove_unused_private_methods=true 45 | sp_cleanup.remove_unused_private_types=true 46 | sp_cleanup.sort_members=false 47 | sp_cleanup.sort_members_all=false 48 | sp_cleanup.use_blocks=false 49 | sp_cleanup.use_blocks_only_for_return_and_throw=false 50 | sp_cleanup.use_parentheses_in_expressions=false 51 | sp_cleanup.use_this_for_non_static_field_access=false 52 | sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true 53 | sp_cleanup.use_this_for_non_static_method_access=false 54 | sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true 55 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Bundle-ManifestVersion: 2 3 | Bundle-Name: Eclipse Multiple Cursor Support 4 | Bundle-SymbolicName: com.asparck.eclipse.multicursor.plugin;singleton:=true 5 | Bundle-Version: 0.1.5.qualifier 6 | Bundle-Activator: com.asparck.eclipse.multicursor.MultiCursorPlugin 7 | Bundle-Vendor: Caspar Krieger 8 | Require-Bundle: org.eclipse.ui;bundle-version="3.7.0", 9 | org.eclipse.core.runtime;bundle-version="3.7.0", 10 | org.eclipse.jface.text;bundle-version="3.7.0", 11 | org.eclipse.ui.workbench.texteditor;bundle-version="3.7.0" 12 | Bundle-RequiredExecutionEnvironment: JavaSE-1.6 13 | Bundle-ActivationPolicy: lazy 14 | Export-Package: com.asparck.eclipse.multicursor.util 15 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/build.properties: -------------------------------------------------------------------------------- 1 | source.. = src/ 2 | output.. = bin/ 3 | bin.includes = plugin.xml,\ 4 | META-INF/,\ 5 | . 6 | src.includes = pom.xml -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 34 | 35 | 40 | 41 | 46 | 47 | 52 | 53 | 58 | 59 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | com.asparck.eclipse.multicursor 8 | parent 9 | 0.1.5-SNAPSHOT 10 | 11 | 12 | com.asparck.eclipse.multicursor.plugin 13 | eclipse-plugin 14 | 15 | 16 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/src/com/asparck/eclipse/multicursor/Logger.java: -------------------------------------------------------------------------------- 1 | package com.asparck.eclipse.multicursor; 2 | 3 | import org.eclipse.core.runtime.ILog; 4 | import org.eclipse.core.runtime.IStatus; 5 | import org.eclipse.core.runtime.Status; 6 | 7 | public class Logger { 8 | public static Logger create(Class clazz) { 9 | return new Logger(clazz.getCanonicalName()); 10 | } 11 | 12 | private final ILog pluginLog = MultiCursorPlugin.getDefault().getLog(); 13 | 14 | private final String name; 15 | 16 | public Logger(String name) { 17 | this.name = name; 18 | } 19 | 20 | public void debug(String text) { 21 | System.out.println("DEBUG: " + formatMessage(text)); 22 | } 23 | 24 | public void info(String text) { 25 | logToEclipseLog(IStatus.INFO, text, null); 26 | } 27 | 28 | public void warning(String text) { 29 | logToEclipseLog(IStatus.WARNING, text, null); 30 | } 31 | 32 | public void error(String text, Throwable error) { 33 | logToEclipseLog(IStatus.ERROR, text, error); 34 | } 35 | 36 | private String formatMessage(String message) { 37 | return name + " " + message; 38 | } 39 | 40 | private void logToEclipseLog(int iStatusLogLevel, String message, Throwable error) { 41 | pluginLog.log(new Status(iStatusLogLevel, MultiCursorPlugin.PLUGIN_ID, formatMessage(message), error)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/src/com/asparck/eclipse/multicursor/MultiCursorPlugin.java: -------------------------------------------------------------------------------- 1 | package com.asparck.eclipse.multicursor; 2 | 3 | import org.eclipse.jface.resource.ImageDescriptor; 4 | import org.eclipse.ui.plugin.AbstractUIPlugin; 5 | import org.osgi.framework.BundleContext; 6 | 7 | /** 8 | * The activator class controls the plug-in life cycle 9 | */ 10 | public class MultiCursorPlugin extends AbstractUIPlugin { 11 | 12 | // The plug-in ID 13 | public static final String PLUGIN_ID = "com.asparck.eclipse.multicursor.plugin"; //$NON-NLS-1$ 14 | 15 | // The shared instance 16 | private static MultiCursorPlugin plugin; 17 | 18 | /** 19 | * The constructor 20 | */ 21 | public MultiCursorPlugin() { 22 | } 23 | 24 | /* 25 | * (non-Javadoc) 26 | * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) 27 | */ 28 | @Override 29 | public void start(BundleContext context) throws Exception { 30 | super.start(context); 31 | plugin = this; 32 | } 33 | 34 | /* 35 | * (non-Javadoc) 36 | * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) 37 | */ 38 | @Override 39 | public void stop(BundleContext context) throws Exception { 40 | plugin = null; 41 | super.stop(context); 42 | } 43 | 44 | /** 45 | * Returns the shared instance 46 | * 47 | * @return the shared instance 48 | */ 49 | public static MultiCursorPlugin getDefault() { 50 | return plugin; 51 | } 52 | 53 | /** 54 | * Returns an image descriptor for the image file at the given 55 | * plug-in relative path 56 | * 57 | * @param path the path 58 | * @return the image descriptor 59 | */ 60 | public static ImageDescriptor getImageDescriptor(String path) { 61 | return imageDescriptorFromPlugin(PLUGIN_ID, path); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/src/com/asparck/eclipse/multicursor/copied/DeleteBlockingExitPolicy.java: -------------------------------------------------------------------------------- 1 | package com.asparck.eclipse.multicursor.copied; 2 | 3 | import org.eclipse.jface.text.IDocument; 4 | import org.eclipse.jface.text.link.LinkedModeModel; 5 | import org.eclipse.jface.text.link.LinkedPosition; 6 | import org.eclipse.jface.text.link.LinkedPositionGroup; 7 | import org.eclipse.jface.text.link.LinkedModeUI.ExitFlags; 8 | import org.eclipse.jface.text.link.LinkedModeUI.IExitPolicy; 9 | import org.eclipse.swt.SWT; 10 | import org.eclipse.swt.events.VerifyEvent; 11 | 12 | /** 13 | * An exit policy that skips Backspace and Delete at the beginning and at the end 14 | * of a linked position, respectively. 15 | * 16 | * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=183925 . 17 | */ 18 | // Copied from org.eclipse.jdt.internal.ui.text.correction.proposals.LinkedNamesAssistProposal.DeleteBlockingExitPolicy 19 | public class DeleteBlockingExitPolicy implements IExitPolicy { 20 | private final IDocument fDocument; 21 | 22 | public DeleteBlockingExitPolicy(IDocument document) { 23 | fDocument= document; 24 | } 25 | 26 | @Override 27 | public ExitFlags doExit(LinkedModeModel model, VerifyEvent event, int offset, int length) { 28 | if (length == 0 && (event.character == SWT.BS || event.character == SWT.DEL)) { 29 | LinkedPosition position= model.findPosition(new LinkedPosition(fDocument, offset, 0, LinkedPositionGroup.NO_STOP)); 30 | if (position != null) { 31 | if (event.character == SWT.BS) { 32 | if (offset - 1 < position.getOffset()) { 33 | //skip backspace at beginning of linked position 34 | event.doit= false; 35 | } 36 | } else /* event.character == SWT.DEL */ { 37 | if (offset + 1 > position.getOffset() + position.getLength()) { 38 | //skip delete at end of linked position 39 | event.doit= false; 40 | } 41 | } 42 | } 43 | } 44 | 45 | return null; // don't change behavior 46 | } 47 | } -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/src/com/asparck/eclipse/multicursor/hacks/ISourceViewerFinder.java: -------------------------------------------------------------------------------- 1 | package com.asparck.eclipse.multicursor.hacks; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import org.eclipse.jface.text.source.ISourceViewer; 6 | import org.eclipse.ui.IEditorPart; 7 | import org.eclipse.ui.part.MultiPageEditorPart; 8 | import org.eclipse.ui.texteditor.AbstractTextEditor; 9 | 10 | import com.asparck.eclipse.multicursor.Logger; 11 | 12 | /** 13 | * Uses hacky reflection techniques to find the source viewer for a given thing. 14 | */ 15 | public class ISourceViewerFinder { 16 | private static final Logger logger = Logger.create(ISourceViewerFinder.class); 17 | 18 | public static ISourceViewer fromEditorPart(IEditorPart editorPart) { 19 | Object activeEditor = editorPart; 20 | if (editorPart instanceof MultiPageEditorPart) { 21 | MultiPageEditorPart multiPageEditorPart = (MultiPageEditorPart) editorPart; 22 | activeEditor = multiPageEditorPart.getSelectedPage(); 23 | } 24 | if (activeEditor instanceof AbstractTextEditor) { 25 | return fromAbstractTextEditor((AbstractTextEditor) activeEditor); 26 | } else { 27 | logger.info("Unable to get ISourceViewer from " + editorPart 28 | + " of type " + editorPart.getClass().getCanonicalName()); 29 | return null; 30 | } 31 | } 32 | 33 | /** 34 | * Relies on protected final method {@link AbstractTextEditor#getSourceViewer()}. 35 | */ 36 | private static ISourceViewer fromAbstractTextEditor(AbstractTextEditor editor) { 37 | try { 38 | Method getSourceViewerMethod = null; 39 | Class clazz = editor.getClass(); 40 | while (clazz != null && getSourceViewerMethod == null) { 41 | if (clazz.equals(AbstractTextEditor.class)) { 42 | getSourceViewerMethod = clazz.getDeclaredMethod("getSourceViewer"); 43 | } else { 44 | clazz = clazz.getSuperclass(); 45 | } 46 | } 47 | if (getSourceViewerMethod == null) { 48 | throw new RuntimeException(); 49 | } 50 | getSourceViewerMethod.setAccessible(true); 51 | ISourceViewer result = (ISourceViewer) getSourceViewerMethod.invoke(editor); 52 | return result; 53 | } catch (Exception e) { 54 | logger.error("Failed to acquire ISourceViewer via reflection", e); 55 | return null; 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/src/com/asparck/eclipse/multicursor/handlers/SelectAllOccurrencesHandler.java: -------------------------------------------------------------------------------- 1 | package com.asparck.eclipse.multicursor.handlers; 2 | 3 | import org.eclipse.core.commands.AbstractHandler; 4 | import org.eclipse.core.commands.ExecutionEvent; 5 | import org.eclipse.core.commands.ExecutionException; 6 | import org.eclipse.jface.text.BadLocationException; 7 | import org.eclipse.jface.text.FindReplaceDocumentAdapter; 8 | import org.eclipse.jface.text.IDocument; 9 | import org.eclipse.jface.text.IRegion; 10 | import org.eclipse.jface.text.link.LinkedModeModel; 11 | import org.eclipse.jface.text.link.LinkedModeUI; 12 | import org.eclipse.jface.text.link.LinkedPosition; 13 | import org.eclipse.jface.text.link.LinkedPositionGroup; 14 | import org.eclipse.jface.text.source.ISourceViewer; 15 | import org.eclipse.swt.graphics.Point; 16 | import org.eclipse.ui.IEditorPart; 17 | import org.eclipse.ui.handlers.HandlerUtil; 18 | import org.eclipse.ui.texteditor.link.EditorLinkedModeUI; 19 | 20 | import com.asparck.eclipse.multicursor.copied.DeleteBlockingExitPolicy; 21 | import com.asparck.eclipse.multicursor.hacks.ISourceViewerFinder; 22 | import com.asparck.eclipse.multicursor.util.CoordinatesUtil; 23 | import com.asparck.eclipse.multicursor.util.TextUtil; 24 | 25 | /** When triggered, any lines which are identical to the current line will start being edited. */ 26 | public class SelectAllOccurrencesHandler extends AbstractHandler { 27 | 28 | @Override 29 | public Object execute(ExecutionEvent event) throws ExecutionException { 30 | IEditorPart editor = HandlerUtil.getActiveEditorChecked(event); 31 | 32 | ISourceViewer viewer = ISourceViewerFinder.fromEditorPart(editor); 33 | if (viewer != null) { 34 | startEditing(viewer); 35 | } 36 | 37 | return null; 38 | } 39 | 40 | /** 41 | * Mostly based on code from {@link org.eclipse.jdt.internal.ui.text.correction.proposals.LinkedNamesAssistProposal} 42 | */ 43 | private void startEditing(ISourceViewer viewer) throws ExecutionException { 44 | Point selOffsetAndLen = viewer.getSelectedRange(); 45 | int selStart = CoordinatesUtil.fromOffsetAndLengthToStartAndEnd(selOffsetAndLen).x; 46 | 47 | IDocument document = viewer.getDocument(); 48 | try { 49 | String selectedText; 50 | if (selOffsetAndLen.y == 0) { // no characters selected 51 | String documentText = document.get(); 52 | Point wordOffsetAndLen = TextUtil.findWordSurrounding(documentText, selStart); 53 | if (wordOffsetAndLen != null) { 54 | selectedText = document.get(wordOffsetAndLen.x, wordOffsetAndLen.y); 55 | } else { 56 | IRegion selectedLine = document.getLineInformationOfOffset(selStart); 57 | selectedText = document.get(selectedLine.getOffset(), selectedLine.getLength()); 58 | } 59 | } else { 60 | selectedText = document.get(selOffsetAndLen.x, selOffsetAndLen.y); 61 | } 62 | 63 | LinkedPositionGroup linkedPositionGroup = new LinkedPositionGroup(); 64 | 65 | FindReplaceDocumentAdapter findReplaceAdaptor = new FindReplaceDocumentAdapter(document); 66 | IRegion matchingRegion = findReplaceAdaptor.find(0, selectedText, true, true, false, false); 67 | while (matchingRegion != null) { 68 | linkedPositionGroup.addPosition(new LinkedPosition(document, matchingRegion.getOffset(), matchingRegion 69 | .getLength())); 70 | 71 | matchingRegion = findReplaceAdaptor.find(matchingRegion.getOffset() + matchingRegion.getLength(), 72 | selectedText, true, true, false, false); 73 | } 74 | 75 | LinkedModeModel model = new LinkedModeModel(); 76 | model.addGroup(linkedPositionGroup); 77 | model.forceInstall(); 78 | 79 | LinkedModeUI ui = new EditorLinkedModeUI(model, viewer); 80 | ui.setExitPolicy(new DeleteBlockingExitPolicy(document)); 81 | ui.enter(); 82 | 83 | // by default the text being edited is selected so restore original selection 84 | viewer.setSelectedRange(selOffsetAndLen.x, selOffsetAndLen.y); 85 | } catch (BadLocationException e) { 86 | throw new ExecutionException("Editing failed", e); 87 | } 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/src/com/asparck/eclipse/multicursor/handlers/SelectNextOccurrenceHandler.java: -------------------------------------------------------------------------------- 1 | package com.asparck.eclipse.multicursor.handlers; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | import org.eclipse.core.commands.AbstractHandlerWithState; 8 | import org.eclipse.core.commands.ExecutionEvent; 9 | import org.eclipse.core.commands.ExecutionException; 10 | import org.eclipse.core.commands.State; 11 | import org.eclipse.jface.text.BadLocationException; 12 | import org.eclipse.jface.text.FindReplaceDocumentAdapter; 13 | import org.eclipse.jface.text.IDocument; 14 | import org.eclipse.jface.text.IRegion; 15 | import org.eclipse.jface.text.ITextViewer; 16 | import org.eclipse.jface.text.link.LinkedModeModel; 17 | import org.eclipse.jface.text.link.LinkedModeUI; 18 | import org.eclipse.jface.text.link.LinkedPosition; 19 | import org.eclipse.jface.text.link.LinkedPositionGroup; 20 | import org.eclipse.jface.text.source.ISourceViewer; 21 | import org.eclipse.swt.graphics.Point; 22 | import org.eclipse.ui.IEditorPart; 23 | import org.eclipse.ui.handlers.HandlerUtil; 24 | import org.eclipse.ui.texteditor.link.EditorLinkedModeUI; 25 | 26 | import com.asparck.eclipse.multicursor.copied.DeleteBlockingExitPolicy; 27 | import com.asparck.eclipse.multicursor.hacks.ISourceViewerFinder; 28 | import com.asparck.eclipse.multicursor.util.CoordinatesUtil; 29 | import com.asparck.eclipse.multicursor.util.TextUtil; 30 | 31 | public class SelectNextOccurrenceHandler extends AbstractHandlerWithState { 32 | private static final String ID_SELECTS_IN_PROGRESS = "SELECTS_IN_PROGRESS"; 33 | 34 | private static final class SelectInProgress { 35 | public final String searchText; 36 | public final List existingSelections; 37 | public final int nextOffset; 38 | private final Point startingSelection; 39 | 40 | public SelectInProgress(Point startingSelection, String selectedText, List existingSelections, int nextOffset) { 41 | this.startingSelection = startingSelection; 42 | this.searchText = selectedText; 43 | this.existingSelections = Collections.unmodifiableList(new ArrayList(existingSelections)); 44 | this.nextOffset = nextOffset; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return "[Find " + searchText + " at " + nextOffset + "; original=" + startingSelection + "]"; 50 | } 51 | } 52 | 53 | @Override 54 | public Object execute(ExecutionEvent event) throws ExecutionException { 55 | IEditorPart editor = HandlerUtil.getActiveEditorChecked(event); 56 | 57 | ISourceViewer viewer = ISourceViewerFinder.fromEditorPart(editor); 58 | if (viewer != null) { 59 | startEditing(viewer); 60 | } 61 | 62 | return null; 63 | } 64 | 65 | private void startEditing(ISourceViewer viewer) throws ExecutionException { 66 | final Point selOffsetAndLen = viewer.getSelectedRange(); 67 | final IDocument document = viewer.getDocument(); 68 | 69 | try { 70 | final String searchText; 71 | final int candidateSearchOffset; 72 | final int selStart = CoordinatesUtil.fromOffsetAndLengthToStartAndEnd(selOffsetAndLen).x; 73 | if (selOffsetAndLen.y == 0) { // no characters selected 74 | final String documentText = document.get(); 75 | final Point wordOffsetAndLen = TextUtil.findWordSurrounding(documentText, selStart); 76 | if (wordOffsetAndLen != null) { 77 | searchText = document.get(wordOffsetAndLen.x, wordOffsetAndLen.y); 78 | candidateSearchOffset = wordOffsetAndLen.x; 79 | } else { 80 | final IRegion selectedLine = document.getLineInformationOfOffset(selStart); 81 | searchText = document.get(selectedLine.getOffset(), selectedLine.getLength()); 82 | candidateSearchOffset = selectedLine.getOffset(); 83 | } 84 | } else { 85 | searchText = document.get(selOffsetAndLen.x, selOffsetAndLen.y); 86 | candidateSearchOffset = selOffsetAndLen.x; 87 | } 88 | 89 | final int searchOffset; 90 | final List selections; 91 | final Point startingSelection; 92 | 93 | final SelectInProgress currentState = getCurrentState(); 94 | if (LinkedModeModel.getModel(document, 0) != null && 95 | currentState != null 96 | && selOffsetAndLen.equals(currentState.startingSelection) 97 | && searchText.equals(currentState.searchText)) { 98 | startingSelection = currentState.startingSelection; 99 | selections = new ArrayList(currentState.existingSelections); 100 | searchOffset = currentState.nextOffset; 101 | } else { 102 | startingSelection = selOffsetAndLen; 103 | selections = new ArrayList(); 104 | searchOffset = candidateSearchOffset; 105 | } 106 | 107 | final IRegion matchingRegion = new FindReplaceDocumentAdapter(document).find(searchOffset, 108 | searchText, true, true, false, false); 109 | if (matchingRegion != null) { 110 | selections.add(matchingRegion); 111 | 112 | if (selections.size() == 1) { 113 | // select the next occurrence too; only selecting the current cursor pos isn't useful 114 | final IRegion secondMatchingRegion = new FindReplaceDocumentAdapter(document).find( 115 | matchingRegion.getOffset() + matchingRegion.getLength(), searchText, true, true, false, false); 116 | if (secondMatchingRegion != null) { 117 | selections.add(secondMatchingRegion); 118 | } 119 | } 120 | 121 | if (selections.size() > 1) { 122 | final IRegion lastSelection = selections.get(selections.size() - 1); 123 | saveCurrentState(new SelectInProgress(startingSelection, searchText, selections, 124 | lastSelection.getOffset() + lastSelection.getLength())); 125 | 126 | startLinkedEdit(selections, viewer, selOffsetAndLen); 127 | } 128 | } 129 | } catch (BadLocationException e) { 130 | throw new ExecutionException("Editing failed", e); 131 | } 132 | } 133 | 134 | 135 | // Reference: RenameLinkedMode class shows how linked mode is meant to be used 136 | private void startLinkedEdit(List selections, ITextViewer viewer, Point originalSelection) 137 | throws BadLocationException { 138 | final LinkedPositionGroup linkedPositionGroup = new LinkedPositionGroup(); 139 | for (IRegion selection : selections) { 140 | linkedPositionGroup.addPosition(new LinkedPosition(viewer.getDocument(), selection.getOffset(), selection 141 | .getLength())); 142 | } 143 | 144 | LinkedModeModel model = new LinkedModeModel(); 145 | model.addGroup(linkedPositionGroup); 146 | model.forceInstall(); 147 | //FIXME can add a listener here to listen for the end of linked mode 148 | //model.addLinkingListener(null); 149 | 150 | LinkedModeUI ui = new EditorLinkedModeUI(model, viewer); 151 | ui.setExitPolicy(new DeleteBlockingExitPolicy(viewer.getDocument())); 152 | ui.enter(); 153 | 154 | // by default the text being edited is selected so restore original selection 155 | viewer.setSelectedRange(originalSelection.x, originalSelection.y); 156 | } 157 | 158 | private SelectInProgress getCurrentState() { 159 | State state = getState(ID_SELECTS_IN_PROGRESS); 160 | if (state == null) { 161 | return null; 162 | } else { 163 | return (SelectInProgress) state.getValue(); 164 | } 165 | } 166 | 167 | private void saveCurrentState(SelectInProgress selectInProgress) { 168 | State state = new State(); 169 | state.setValue(selectInProgress); 170 | state.setId(ID_SELECTS_IN_PROGRESS); 171 | addState(ID_SELECTS_IN_PROGRESS, state); 172 | } 173 | 174 | @Override 175 | public void handleStateChange(State state, Object oldValue) { 176 | // logger.debug("State changed; new value=" + state.getId() + ":" + state.getValue() + " and old value=" 177 | // + oldValue); 178 | } 179 | 180 | } 181 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/src/com/asparck/eclipse/multicursor/util/CoordinatesUtil.java: -------------------------------------------------------------------------------- 1 | package com.asparck.eclipse.multicursor.util; 2 | 3 | import org.eclipse.swt.graphics.Point; 4 | 5 | public class CoordinatesUtil { 6 | /** 7 | * Converts offset and (possibly negative) length to absolute start and end positions. 8 | */ 9 | public static Point fromOffsetAndLengthToStartAndEnd(Point startAndOffset) { 10 | int selStart = Math.min(startAndOffset.x, startAndOffset.x + startAndOffset.y); 11 | int selEnd = Math.max(startAndOffset.x, startAndOffset.x + startAndOffset.y); 12 | return new Point(selStart, selEnd); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.plugin/src/com/asparck/eclipse/multicursor/util/TextUtil.java: -------------------------------------------------------------------------------- 1 | package com.asparck.eclipse.multicursor.util; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | import org.eclipse.swt.graphics.Point; 7 | 8 | public class TextUtil { 9 | private static final Pattern WORD_RE = Pattern.compile("\\w+"); 10 | 11 | /** 12 | * Scans backward from the given offset to identify a word which contains {@code offset}. 13 | * 14 | * @return position (x) and length (y) of the last word in {@code text} which contains {@code offset}, or null if no 15 | * word containing {@code offset} could be identified (i.e. offset is in whitespace) 16 | */ 17 | public static Point findWordSurrounding(String text, int offset) { 18 | int wordOffset = offset == 0 ? 0 : offset - 1; 19 | Point lastWordFound = null; 20 | Matcher matcher = WORD_RE.matcher(text); 21 | while (wordOffset >= 0) { 22 | boolean found = matcher.find(wordOffset); 23 | if (found && matcher.start() <= offset && matcher.end() >= offset) { 24 | lastWordFound = new Point(matcher.start(), matcher.end() - matcher.start()); 25 | wordOffset--; // see if there's another match behind 26 | } else { 27 | break; 28 | } 29 | } 30 | 31 | return lastWordFound; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.target/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.asparck.eclipse.multicursor.target 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.target/com.asparck.eclipse.multicursor.target.target: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.target/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | com.asparck.eclipse.multicursor 8 | parent 9 | 0.1.5-SNAPSHOT 10 | 11 | 12 | com.asparck.eclipse.multicursor.target 13 | eclipse-target-definition 14 | 15 | 16 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.tests/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.tests/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.asparck.eclipse.multicursor.tests 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.pde.ManifestBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.pde.SchemaBuilder 20 | 21 | 22 | 23 | 24 | 25 | org.eclipse.pde.PluginNature 26 | org.eclipse.jdt.core.javanature 27 | 28 | 29 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.tests/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.tests/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 4 | org.eclipse.jdt.core.compiler.compliance=1.6 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.source=1.6 8 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.tests/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Bundle-ManifestVersion: 2 3 | Bundle-Name: Tests 4 | Bundle-SymbolicName: com.asparck.eclipse.multicursor.tests 5 | Bundle-Version: 0.1.5.qualifier 6 | Bundle-Activator: com.asparck.eclipse.multicursor.tests.Activator 7 | Bundle-Vendor: Caspar Krieger 8 | Require-Bundle: org.eclipse.core.runtime, 9 | org.junit;bundle-version="4.8.1", 10 | com.asparck.eclipse.multicursor.plugin, 11 | org.eclipse.swt 12 | Bundle-RequiredExecutionEnvironment: JavaSE-1.6 13 | Bundle-ActivationPolicy: lazy 14 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.tests/build.properties: -------------------------------------------------------------------------------- 1 | source.. = src/ 2 | output.. = bin/ 3 | bin.includes = META-INF/,\ 4 | . 5 | src.includes = pom.xml 6 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.tests/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | com.asparck.eclipse.multicursor 8 | parent 9 | 0.1.5-SNAPSHOT 10 | 11 | 12 | com.asparck.eclipse.multicursor.tests 13 | eclipse-test-plugin 14 | 15 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.tests/src/com/asparck/eclipse/multicursor/tests/Activator.java: -------------------------------------------------------------------------------- 1 | package com.asparck.eclipse.multicursor.tests; 2 | 3 | import org.osgi.framework.BundleActivator; 4 | import org.osgi.framework.BundleContext; 5 | 6 | public class Activator implements BundleActivator { 7 | 8 | private static BundleContext context; 9 | 10 | static BundleContext getContext() { 11 | return context; 12 | } 13 | 14 | /* 15 | * (non-Javadoc) 16 | * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) 17 | */ 18 | public void start(BundleContext bundleContext) throws Exception { 19 | Activator.context = bundleContext; 20 | } 21 | 22 | /* 23 | * (non-Javadoc) 24 | * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) 25 | */ 26 | public void stop(BundleContext bundleContext) throws Exception { 27 | Activator.context = null; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /com.asparck.eclipse.multicursor.tests/src/com/asparck/eclipse/multicursor/util/TextUtilTest.java: -------------------------------------------------------------------------------- 1 | package com.asparck.eclipse.multicursor.util; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.eclipse.swt.graphics.Point; 6 | import org.junit.Test; 7 | 8 | public class TextUtilTest { 9 | 10 | @Test 11 | public void findWordSurroundingShouldFindWordSurroundingGivenOffset() { 12 | String str = "my name is bob"; 13 | Point word = TextUtil.findWordSurrounding(str, 5); 14 | 15 | assertEquals("name", str.substring(word.x, word.x + word.y)); 16 | } 17 | 18 | @Test 19 | public void findWordSurroundingShouldFindWordWhenOffsetIsAtStartOfWord() { 20 | String str = "my name is bob"; 21 | Point word = TextUtil.findWordSurrounding(str, 3); 22 | 23 | assertEquals("name", str.substring(word.x, word.x + word.y)); 24 | } 25 | 26 | @Test 27 | public void findWordSurroundingShouldFindWordWhenOffsetIsAtEndOfWord() { 28 | String str = "my name is bob"; 29 | Point word = TextUtil.findWordSurrounding(str, 7); 30 | 31 | assertEquals("name", str.substring(word.x, word.x + word.y)); 32 | } 33 | 34 | @Test 35 | public void findWordSurroundingShouldFindWordWhenOffsetIsAtStartOfString() { 36 | String str = "my name is bob"; 37 | Point word = TextUtil.findWordSurrounding(str, 0); 38 | 39 | assertEquals("my", str.substring(word.x, word.x + word.y)); 40 | } 41 | 42 | @Test 43 | public void findWordSurroundingShouldFindWordWhenOffsetIsAtEndOfString() { 44 | String str = "my name is bob"; 45 | Point word = TextUtil.findWordSurrounding(str, str.length()); 46 | 47 | assertEquals("bob", str.substring(word.x, word.x + word.y)); 48 | } 49 | 50 | @Test 51 | public void findWordSurroundingShouldReturnNullIfOffsetIsInEmptyString() { 52 | Point word = TextUtil.findWordSurrounding("", 0); 53 | 54 | assertNull(word); 55 | } 56 | 57 | @Test 58 | public void findWordSurroundingShouldReturnNullIfOffsetIsInWhitespace() { 59 | Point word = TextUtil.findWordSurrounding("hello world", 6); 60 | 61 | assertNull(word); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.asparck.eclipse.multicursor 7 | parent 8 | 0.1.5-SNAPSHOT 9 | pom 10 | 11 | 12 | com.asparck.eclipse.multicursor.target 13 | com.asparck.eclipse.multicursor.plugin 14 | com.asparck.eclipse.multicursor.feature 15 | com.asparck.eclipse.multicursor.p2updatesite 16 | com.asparck.eclipse.multicursor.tests 17 | 18 | 19 | 20 | 0.20.0 21 | 22 | UTF-8 23 | 24 | 25 | 26 | 27 | 28 | org.eclipse.tycho 29 | tycho-maven-plugin 30 | ${tycho.version} 31 | true 32 | 33 | 34 | 35 | org.eclipse.tycho 36 | tycho-compiler-plugin 37 | ${tycho.version} 38 | 39 | 1.6 40 | 1.6 41 | 42 | 43 | 44 | 45 | org.eclipse.tycho 46 | target-platform-configuration 47 | ${tycho.version} 48 | 49 | 50 | 51 | ${project.groupId} 52 | com.asparck.eclipse.multicursor.target 53 | ${project.version} 54 | 55 | 56 | 57 | 58 | linux 59 | gtk 60 | x86 61 | 62 | 63 | linux 64 | gtk 65 | x86_64 66 | 67 | 68 | win32 69 | win32 70 | x86 71 | 72 | 73 | win32 74 | win32 75 | x86_64 76 | 77 | 78 | macosx 79 | cocoa 80 | x86_64 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /redownload-p2-plugin-jars.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # If, when setting the target platform, Eclipse gets a bunch of errors about being unable to parse 4 | # manifests and it turns out that each of the jars it complains about is not a valid zip file, you 5 | # can use this to download the correct jars in the pack.gz forms (and then unpacking them; the 6 | # .pack.gz versions of the jars aren't corrupted, in my experience). 7 | # 8 | # This script will download the jars from the 3.7.2 update site; you can plug in another update 9 | # site by editing the script below (we're defaulting to 3.7.2 because at time of writing, that's 10 | # the lowest version of Eclipse that we support). 11 | # 12 | # Usage: cd to your Eclipse workspace (containing the .metadata directory), and then run this 13 | # script from there. 14 | 15 | set -e 16 | 17 | #UPDATE_SITE_BASE_URL=http://download.eclipse.org/eclipse/updates/3.8/R-3.8.2-201301310800/plugins/ 18 | #UPDATE_SITE_BASE_URL=http://download.eclipse.org/eclipse/updates/3.7/R-3.7.2-201202080800/plugins/ 19 | UPDATE_SITE_BASE_URL=http://download.eclipse.org/releases/indigo/201202240900/aggregate/plugins/ 20 | 21 | # PDE downloads its plugins to here 22 | cd .metadata/.plugins/org.eclipse.pde.core/.bundle_pool/plugins 23 | 24 | for f in *.jar; do 25 | # echo "Processing ${f}" 26 | echo -n . 27 | if ! unzip -t ${f} 2>&1 > /dev/null ; then 28 | echo "*** ${f} appears corrupt, redownloading" 29 | curl -Ov "${UPDATE_SITE_BASE_URL}${f}.pack.gz" 30 | unpack200 -r "${f}.pack.gz" "${f}" 31 | fi 32 | done 33 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # See RELEASING 4 | 5 | if [ "$#" -ne 3 ]; then 6 | echo "Expected: 3 parameters:" 7 | echo "- release version" 8 | echo "- development version" 9 | echo "- release artifact destination directory" 10 | exit 1 11 | fi 12 | 13 | function fail_with_msg { 14 | echo $1 15 | exit 1 16 | } 17 | 18 | function set_maven_version { 19 | NEW_MAVEN_VERSION=$1 20 | 21 | echo "Using maven to update pom.xml versions to ${NEW_MAVEN_VERSION}" 22 | mvn org.codehaus.mojo:versions-maven-plugin:2.1:set -DnewVersion=${NEW_MAVEN_VERSION} > /dev/null || fail_with_msg "Setting versions failed; aborting" 23 | find . -name 'pom.xml.versionsBackup' -delete || fail_with_msg "Deleting temp files failed; aborting" 24 | } 25 | 26 | function set_osgi_version { 27 | OLD_OSGI_VERSION=$1 28 | NEW_OSGI_VERSION=$2 29 | 30 | echo "Updating OSGI manifest versions from ${OLD_OSGI_VERSION} to ${NEW_OSGI_VERSION}" 31 | find . -name "MANIFEST.MF" -exec sed -i "s/Bundle-Version: ${OLD_OSGI_VERSION}/Bundle-Version: ${NEW_OSGI_VERSION}/g" '{}' \; || fail_with_msg "Error; aborting" 32 | 33 | echo "Updating Eclipse feature version and referenced plugin version in the P2 feature definition from ${OLD_OSGI_VERSION} to ${NEW_OSGI_VERSION}" 34 | # using /g to make update both occurrences as per message above 35 | sed -i "s/version=\"${OLD_OSGI_VERSION}\"/version=\"${NEW_OSGI_VERSION}\"/g" com.asparck.eclipse.multicursor.feature/feature.xml || fail_with_msg "Error; aborting" 36 | 37 | echo "Updating Eclipse feature version and filename in the P2 update site category definition from ${OLD_OSGI_VERSION} to ${NEW_OSGI_VERSION}" 38 | sed -i "s/com.asparck.eclipse.multicursor.feature_${OLD_OSGI_VERSION}.jar/com.asparck.eclipse.multicursor.feature_${NEW_OSGI_VERSION}.jar/" com.asparck.eclipse.multicursor.p2updatesite/category.xml || fail_with_msg "Error; aborting" 39 | sed -i "s/version=\"${OLD_OSGI_VERSION}\">/version=\"${NEW_OSGI_VERSION}\">/" com.asparck.eclipse.multicursor.p2updatesite/category.xml || fail_with_msg "Error; aborting" 40 | } 41 | 42 | function verify_only_expected_files_are_dirty { 43 | UNEXPECTED_DIRTY=$(git status --porcelain | grep -v pom.xml | grep -v category.xml | grep -v MANIFEST.MF | grep -v feature.xml) 44 | if [[ ! -z ${UNEXPECTED_DIRTY} ]]; then 45 | echo "Unexpected files are dirty:" 46 | echo ${UNEXPECTED_DIRTY} 47 | exit 1 48 | fi 49 | } 50 | 51 | function git_commit_all_with_msg { 52 | echo "*** Committing with message '${1}'" 53 | git commit -a -m "${1}" || fail_with_msg "Error committing; aborting" 54 | } 55 | 56 | 57 | echo "Determining project development version from maven" 58 | CURRENT_DEVELOPMENT_VERSION_MAVEN=$(mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | grep -Ev '(^\[|Download\w+:)') 59 | #CURRENT_DEVELOPMENT_VERSION_MAVEN="0.1.1-SNAPSHOT" 60 | EXPECTED_CURRENT_DEVELOPMENT_VERSION_MAVEN_RE="([0-9]+\.[0-9]+\.[0-9]+)-SNAPSHOT" 61 | 62 | if [[ ${CURRENT_DEVELOPMENT_VERSION_MAVEN} =~ ${EXPECTED_CURRENT_DEVELOPMENT_VERSION_MAVEN_RE} ]]; then 63 | CURRENT_DEVELOPMENT_VERSION=${BASH_REMATCH[1]} 64 | else 65 | fail_with_msg "Maven development version of ${CURRENT_DEVELOPMENT_VERSION_MAVEN} does not match expected format of ${EXPECTED_CURRENT_DEVELOPMENT_VERSION_MAVEN_RE}" 66 | fi 67 | 68 | CURRENT_DEVELOPMENT_VERSION_OSGI=${CURRENT_DEVELOPMENT_VERSION}.qualifier 69 | RELEASE_VERSION=$1 70 | RELEASE_GIT_COMMIT_MSG="Release: v${RELEASE_VERSION}" 71 | RELEASE_GIT_TAG="v${RELEASE_VERSION}" 72 | NEXT_DEVELOPMENT_VERSION=${2} 73 | NEXT_DEVELOPMENT_VERSION_MAVEN=${NEXT_DEVELOPMENT_VERSION}-SNAPSHOT 74 | NEXT_DEVELOPMENT_VERSION_OSGI=${NEXT_DEVELOPMENT_VERSION}.qualifier 75 | NEXT_DEVELOPMENT_GIT_COMMIT_MSG="Release: prepare for next development cycle" 76 | RELEASE_ARTIFACT_DIR=$(readlink -m $3) 77 | 78 | echo "CURRENT_DEVELOPMENT_VERSION_MAVEN=${CURRENT_DEVELOPMENT_VERSION_MAVEN}" 79 | echo "CURRENT_DEVELOPMENT_VERSION_OSGI=${CURRENT_DEVELOPMENT_VERSION_OSGI} (assumed from Maven version)" 80 | echo "RELEASE_VERSION=${RELEASE_VERSION}" 81 | echo "RELEASE_GIT_COMMIT_MSG=${RELEASE_GIT_COMMIT_MSG}" 82 | echo "RELEASE_GIT_TAG=${RELEASE_GIT_TAG}" 83 | echo "NEXT_DEVELOPMENT_VERSION_MAVEN=${NEXT_DEVELOPMENT_VERSION_MAVEN}" 84 | echo "NEXT_DEVELOPMENT_VERSION_OSGI=${NEXT_DEVELOPMENT_VERSION_OSGI}" 85 | echo "NEXT_DEVELOPMENT_GIT_COMMIT_MSG=${NEXT_DEVELOPMENT_GIT_COMMIT_MSG}" 86 | echo "RELEASE_ARTIFACT_DIR=${RELEASE_ARTIFACT_DIR}" 87 | 88 | read -p "Continue with release? [y/n] " -n 1 -r 89 | echo # move to a new line 90 | if [[ ! ${REPLY} =~ ^[Yy]$ ]] 91 | then 92 | echo "Release cancelled; aborting." 93 | exit 1 94 | fi 95 | 96 | echo "*** Preparing for release by setting versions to ${RELEASE_VERSION}" 97 | set_maven_version ${RELEASE_VERSION} 98 | set_osgi_version ${CURRENT_DEVELOPMENT_VERSION_OSGI} ${RELEASE_VERSION} 99 | 100 | echo "*** Building release" 101 | mvn clean verify || fail_with_msg "Error building release; aborting" 102 | 103 | echo "*** Copying release artifacts to ${RELEASE_ARTIFACT_DIR}" 104 | cp com.asparck.eclipse.multicursor.plugin/target/com.asparck.eclipse.multicursor.plugin-${RELEASE_VERSION}.jar \ 105 | com.asparck.eclipse.multicursor.p2updatesite/target/com.asparck.eclipse.multicursor.p2updatesite-${RELEASE_VERSION}.zip \ 106 | "${RELEASE_ARTIFACT_DIR}" 107 | 108 | verify_only_expected_files_are_dirty 109 | git_commit_all_with_msg "${RELEASE_GIT_COMMIT_MSG}" 110 | 111 | echo "*** Tagging release with tag '${RELEASE_GIT_TAG}'" 112 | git tag "${RELEASE_GIT_TAG}" || fail_with_msg "Error tagging; aborting" 113 | 114 | echo "*** Preparing for next development version by setting versions to ${NEXT_DEVELOPMENT_VERSION}" 115 | set_maven_version ${NEXT_DEVELOPMENT_VERSION_MAVEN} 116 | set_osgi_version ${RELEASE_VERSION} ${NEXT_DEVELOPMENT_VERSION_OSGI} 117 | 118 | echo "*** Building next development version to make sure it isn't broken" 119 | mvn clean verify || fail_with_msg "Error building next development version; aborting" 120 | 121 | verify_only_expected_files_are_dirty 122 | git_commit_all_with_msg "${NEXT_DEVELOPMENT_GIT_COMMIT_MSG}" 123 | 124 | echo "*** Release completed; next steps:" 125 | echo "- Check the git commit history and then 'git push --tags'" 126 | echo "- Upload artifacts from ${RELEASE_ARTIFACT_DIR} to a new github release: https://github.com/caspark/eclipse-multicursor/releases/new" 127 | --------------------------------------------------------------------------------