diff --git a/.gitignore b/.gitignore
index 496ee2c..1ac4749 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,73 @@
-.DS_Store
\ No newline at end of file
+# Created by http://www.gitignore.io
+
+### OSX ###
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear on external disk
+.Spotlight-V100
+.Trashes
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+
+### Xcode ###
+build/
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata
+*.xccheckout
+*.moved-aside
+DerivedData
+*.xcuserstate
+
+
+### AppCode ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
+
+## Directory-based project format
+.idea/
+# if you remove the above rule, at least ignore user-specific stuff:
+# .idea/workspace.xml
+# .idea/tasks.xml
+# and these sensitive or high-churn files:
+# .idea/dataSources.ids
+# .idea/dataSources.xml
+# .idea/sqlDataSources.xml
+# .idea/dynamic.xml
+
+## File-based project format
+*.ipr
+*.iws
+*.iml
+
+## Additional for IntelliJ
+out/
+
+# generated by mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# generated by JIRA plugin
+atlassian-ide-plugin.xml
+
+# generated by Crashlytics plugin (for Android Studio and Intellij)
+com_crashlytics_export_strings.xml
diff --git a/Dash.iml b/Dash.iml
index a2a2b68..1dcc234 100644
--- a/Dash.iml
+++ b/Dash.iml
@@ -5,9 +5,10 @@
+
-
+
+
-
-
+
\ No newline at end of file
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..d3e20db
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) 2013-2018 Gerard Delmàs and contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/META-INF/plugin.xml b/META-INF/plugin.xml
index dd66d43..4a433a5 100644
--- a/META-INF/plugin.xml
+++ b/META-INF/plugin.xml
@@ -1,25 +1,84 @@
com.paperetto.dash
- Dash Launcher
- 1.0
- David Brittain
+ Dash
+ 3.3
+ Gerard Delmàs
- Dash is a Mac OSX utility that can be obtained from the Apple Store
- ]]>
+A smart and simple plugin that provides keyboard shortcut access for Dash, Velocity or Zeal in IntelliJ IDEA, RubyMine, WebStorm, PhpStorm, PyCharm, DataGrip, CLion, GoLand and Android Studio.
+
+Usage
+The default shortcut assigned to smart-search is Cmd-Shift-D (Mac OS X) or Ctrl-Shift-D (Windows, Linux).
+A menubar command named either "Smart-Search Documentation" can be found in the "Tools" menu.
+The plugin either searches for the statement at caret position or the current selection. It will identify the programming language in use and request filtered results accordingly. A non filtered search over all documentation entries can be invoked by adding the Alt modifier key to the shortcut. "Search all Documentation" is also available in the tools menu.
+
+
Configuration
+Shortcut
+You can change the shortcut at Preferences -> Keymap -> Plug-ins -> Dash.
+Toolbar Icon
+You can add a button to the toolbar. Right-click the menubar -> Customize […]. You will find the button under "Plug-ins -> Dash".
+
+Supported API Documentation Browsers
+Kapeli Dash (Mac OS X)
+Dash is an API Documentation Browser and Code Snippet Manager. Dash stores snippets of code and instantly searches offline documentation sets for 150+ APIs (for a full list, see below). You can even generate your own docsets or request docsets to be included. http://kapeli.com/dash
+Velocity (Windows)
+Velocity gives your Windows desktop offline access to over 150 API documentation sets (provided by Dash for OS X). https://velocity.silverlakesoftware.com
+Zeal (Linux & Windows)
+Zeal is a simple offline API documentation browser inspired by Dash (OS X app). http://zealdocs.org
+]]>
- ]]>
+
+3.3
+ - Added non-smart "Search all Documentation" option
+ - Java 9 SDK detection
+3.2.5
+ - Fixed Zeal Support
+ - Go, Elixir & Erlang support
+3.2.4
+ - Dockerfile support
+3.2.3
+ - Dash 2.3 Remote redirection support
+ - Clojure support
+3.2.2 ActionScript support
+3.2.1 Fixed an issue where
+ context filters would not work
+3.2
+ - Toolbar icon support
+ - Velocity support on Windows
+ - Zeal support on Linux
+3.1
+ - language detection support in strings
+ - project settings sql dialect will be used
+ to filter search results
+ - android project support
+ - java search results according to projects
+ sdk version
+ - python search results according to
+ projects sdk version
+ - added language support for: Bash, Go,
+ Haskell, Lua, Markdown, Scala, TypoScript
+ - extended language support for: angularjs,
+ momen, require, awsjs, jasmine, sinon,
+ tornado, sqlalchemy, numpy, scipy, salt,
+ polymerdart, angulardart
+ - performance and stability improvements
+3.0.1 Fixed missing Ruby context recognition
+3.0 Added Context aware search
+2.2 Compatibility and stability fixes
+2.1 Added Ruby syntax support, stability fixes
+2.0 Added Dash docset keyword support
+
+]]>
-
+
com.intellij.modules.lang
+ com.intellij.sql
@@ -31,14 +90,18 @@
-
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1c8ea06
--- /dev/null
+++ b/README.md
@@ -0,0 +1,44 @@
+A smart and simple plugin that provides keyboard shortcut access for Dash, Velocity or Zeal in IntelliJ IDEA, RubyMine, WebStorm, PhpStorm, PyCharm, DataGrip, CLion, GoLand and Android Studio.
+
+## Installation
+To install the plugin in your IDE go to **Preferences -> Plugins -> Browse repositories** and **search for "Dash"**.
+
+## Usage
+The default **shortcut** assigned to smart-search is **Cmd-Shift-D** (Mac OS X) or **Ctrl-Shift-D** (Windows, Linux).
+
+
+A **menubar command** named "**Smart-Search Documentation**" can be found in the "Tools" menu.
+
+
+The plugin either searches for the statement at caret position or the current selection. It will identify the programming language in use and request filtered results accordingly. A non filtered search over all documentation entries can be invoked by adding the **Alt** modifier key to the shortcut. "**Search all Documentation**" is also available in the tools menu.
+
+## Configuration
+### Shortcut
+You can change the shortcut at Preferences -> Keymap -> Plug-ins -> Dash.
+
+### Toolbar Icon
+You can add a button to the toolbar. Right-click the menubar -> Customize […]. You will find the button under "Plug-ins -> Dash".
+
+## Supported API Documentation Browsers
+### Kapeli Dash (Mac OS X)
+Dash is an API Documentation Browser and Code Snippet Manager. Dash stores snippets of code and instantly searches offline documentation sets for 150+ APIs (for a full list, see below). You can even generate your own docsets or request docsets to be included.
+[http://kapeli.com/dash](http://kapeli.com/dash)
+
+### Velocity (Windows)
+Velocity gives your Windows desktop offline access to over 150 API documentation sets (provided by Dash for OS X).
+[https://velocity.silverlakesoftware.com](https://velocity.silverlakesoftware.com)
+
+### Zeal (Linux & Windows)
+Zeal is a simple offline API documentation browser inspired by Dash (OS X app).
+[http://zealdocs.org](http://zealdocs.org)
+
+
+## Troubleshooting
+###### On Windows, when using Zeal the IDE shows `Failed to open dash-plugin://...` in the Event Log
+It looks like the URL handler has not been registered for Zeal. Please run `zeal.exe --register`.
+
+###### The plugin does not work on old IDEs
+Older IDE versions like **AppCode 1.x** are not supported anymore. Please manually install version 2.2 of the plugin: https://github.com/gdelmas/IntelliJDashPlugin/releases/tag/2.2
+
+###### In rare conditions the installation from the repositories does not work
+It looks like there is an IntelliJ/Java bug with OS X Mavericks which prevents to install plugins from the repositories. Please install the plugin manually from [here](https://github.com/gdelmas/IntelliJDashPlugin/releases). For additional information check [issue #13](https://github.com/gdelmas/IntelliJDashPlugin/issues/13).
diff --git a/README.txt b/README.txt
deleted file mode 100644
index a6e0d32..0000000
--- a/README.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-A simple plugin for AppCode (and other IntelliJ based IDEs) that provides keyboard shortcut access to Dash. This is necessary as the 'Services' menu is not populated in AppCode (apparently a Java limitation).
-
-Download Dash.jar from here: https://github.com/combinatorial/AppCodeDashSearch/releases/download/1.0/Dash.jar
-
-Install Dash.jar in this folder as a plugin.
-
-Dash is a Mac application for rapid search of developer documentation. It is free with nags to persuade you to pay and lose the nags. The free version is fully functional and super-useful. Get karma for buying and supporting the developer :) It can be downloaded here:
-
-http://itunes.apple.com/us/app/dash/id458034879?ls=1&mt=12
-
-The default shortcut assigned in the plugin is Mac-Shift-D. It either uses the current selection for the search, or the caret position.
-
-Please feel free to request improvements, or fork-it and make them yourself!
diff --git a/resources/dash.png b/resources/dash.png
new file mode 100644
index 0000000..6d3fb27
Binary files /dev/null and b/resources/dash.png differ
diff --git a/resources/dash@2x.png b/resources/dash@2x.png
new file mode 100644
index 0000000..70750bd
Binary files /dev/null and b/resources/dash@2x.png differ
diff --git a/src/com/paperetto/dash/DashLauncherAction.java b/src/com/paperetto/dash/DashLauncherAction.java
deleted file mode 100644
index 090cfad..0000000
--- a/src/com/paperetto/dash/DashLauncherAction.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.paperetto.dash;
-
-
-import com.intellij.execution.ExecutionException;
-import com.intellij.execution.configurations.GeneralCommandLine;
-import com.intellij.execution.util.ExecUtil;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.DataKeys;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.SelectionModel;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-
-public class DashLauncherAction extends AnAction {
-
- @Override
- public void update(AnActionEvent e) {
- e.getPresentation().setEnabled(PlatformDataKeys.EDITOR.getData(e.getDataContext()) != null);
- }
-
-
-
- private String getWordAtCursor(CharSequence editorText, int cursorOffset) {
- if(editorText.length() == 0) return null;
- if(cursorOffset > 0 && !Character.isJavaIdentifierPart(editorText.charAt(cursorOffset)) &&
- Character.isJavaIdentifierPart(editorText.charAt(cursorOffset - 1))) {
- cursorOffset--;
- }
-
- if(Character.isJavaIdentifierPart(editorText.charAt(cursorOffset))) {
- int start = cursorOffset;
- int end = cursorOffset;
-
- while(start > 0 && Character.isJavaIdentifierPart(editorText.charAt(start-1))) {
- start--;
- }
-
- while(end < editorText.length() && Character.isJavaIdentifierPart(editorText.charAt(end))) {
- end++;
- }
-
- return editorText.subSequence(start,end).toString();
- }
- return null;
- }
-
- public void actionPerformed(AnActionEvent e) {
-
- Editor editor = PlatformDataKeys.EDITOR.getData(e.getDataContext());
-
- //Editor editor = DataKeys.EDITOR.getData(e.getDataContext());
- int offset = editor.getCaretModel().getOffset();
- CharSequence editorText = editor.getDocument().getCharsSequence();
-
- String word = null;
-
- SelectionModel selectionModel = editor.getSelectionModel();
- if(selectionModel.hasSelection())
- {
- word = selectionModel.getSelectedText();
- }
- else
- {
- word = getWordAtCursor(editorText,offset);
- }
-
- if(word!=null) {
-
- String searchWord;
- try {
- searchWord = URLEncoder.encode(word, "UTF-8");
- } catch (UnsupportedEncodingException el){
- ///where do I print an error
- return;
- }
- //URLEncoder turns spaces in to '+' we need them to be %20
- searchWord = searchWord.replace("+", "%20");
-
- String request = "dash://" + searchWord;
-
- //now open the URL with the 'open' command
- String[] command = new String[]{ExecUtil.getOpenCommandPath()};
- try {
- final GeneralCommandLine commandLine = new GeneralCommandLine(command);
- commandLine.addParameter(request);
- commandLine.createProcess();
-
- }
- catch (ExecutionException ee) {
- ///where do I print an error
- return;
- }
- }
- }
-}
diff --git a/src/de/dreamlab/dash/AbstractMenuAction.java b/src/de/dreamlab/dash/AbstractMenuAction.java
new file mode 100644
index 0000000..cc9d23c
--- /dev/null
+++ b/src/de/dreamlab/dash/AbstractMenuAction.java
@@ -0,0 +1,57 @@
+package de.dreamlab.dash;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.util.IconLoader;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.swing.*;
+
+abstract public class AbstractMenuAction extends AnAction {
+ protected @Nonnull String title = "";
+ protected @Nonnull String description = "";
+ protected @Nullable String iconFilename = null;
+
+
+ private boolean isPresentationInitialized = false;
+
+ private void initPresentation()
+ {
+ String docAppName = "";
+
+ if ( SystemUtil.isIsOSMac() ) {
+ docAppName = " in Dash";
+ }
+
+ Presentation presentation = this.getTemplatePresentation();
+ presentation.setText(title + docAppName);
+ presentation.setDescription(description + docAppName);
+
+ if ( iconFilename != null ) {
+ Icon icon = IconLoader.getIcon("/" + iconFilename, AbstractMenuAction.class);
+ presentation.setIcon(icon);
+ }
+ }
+
+ @Override
+ public void update(AnActionEvent e) {
+ super.update(e);
+
+ Presentation presentation = e.getPresentation();
+
+ if ( !isPresentationInitialized ) {
+ isPresentationInitialized = true;
+ initPresentation();
+
+ Presentation templatePresentation = getTemplatePresentation();
+ presentation.setText(templatePresentation.getText());
+ presentation.setDescription(templatePresentation.getDescription());
+ presentation.setIcon(templatePresentation.getIcon());
+ }
+
+ presentation.setEnabled(PlatformDataKeys.EDITOR.getData(e.getDataContext()) != null);
+ }
+}
diff --git a/src/de/dreamlab/dash/KeywordLookup.java b/src/de/dreamlab/dash/KeywordLookup.java
new file mode 100644
index 0000000..172f60d
--- /dev/null
+++ b/src/de/dreamlab/dash/KeywordLookup.java
@@ -0,0 +1,176 @@
+package de.dreamlab.dash;
+
+import com.intellij.lang.Language;
+import com.intellij.notification.Notification;
+import com.intellij.notification.NotificationType;
+import com.intellij.notification.Notifications;
+import de.dreamlab.dash.keywords.*;
+
+import java.util.*;
+
+public class KeywordLookup {
+ private HashMap> languageMap;
+
+ public KeywordLookup()
+ {
+ languageMap = new HashMap>();
+
+ // IntelliJ Ultimate Edition 13.1, WebStorm 8.0, PhpStorm 7.1, RubyMine 6.3, PyCharm 3.1
+ setLanguage("HTML", "html", "angularjs");
+ setLanguage("XHTML", "html");
+ setLanguage("XML", "xml");
+ setLanguage("XPath", "xml"); // not RubyMine, not PyCharm
+ setLanguage("RegExp", "regex");
+
+ // IntelliJ Ultimate Edition 13.1, WebStorm 8.0, PhpStorm 7.1, RubyMine 6.3, PyCharm 3.1
+ setLanguage("CSS", "css");
+ setLanguage("JQuery-CSS", "css", "jquery", "jqueryui", "jquerym");
+ setLanguage("LESS", "less", "css");
+ setLanguage("SASS", "sass", "compass", "bourbon", "neat", "css");
+ setLanguage("SCSS", "sass", "compass", "bourbon", "neat", "css");
+ setLanguage("Stylus", "stylus", "css"); // not PhpStorm
+ setLanguage("HAML", "haml");
+ setLanguage("CoffeeScript", "coffee", "javascript", "jquery", "jqueryui", "jquerym", "backbone", "marionette", "meteor", "sproutcore", "moo", "prototype", "bootstrap", "foundation", "lodash", "underscore", "ember", "sencha", "extjs", "titanium", "knockout", "zepto", "yui", "d3", "dojo", "nodejs", "express", "grunt", "mongoose", "moment", "require", "awsjs", "jasmine", "sinon", "chai", "cordova", "phonegap"); // not IntelliJ
+
+ setLanguage("JavaScript", (Object[])FileTypeSpecificKeyword.createList(
+ new String[]{"javascript", "jquery", "jqueryui", "jquerym", "backbone", "marionette", "meteor", "sproutcore", "moo", "prototype", "bootstrap", "foundation", "lodash", "underscore", "ember", "sencha", "extjs", "titanium", "knockout", "zepto", "yui", "d3", "dojo", "nodejs", "express", "grunt", "mongoose", "moment", "require", "awsjs", "jasmine", "sinon", "chai", "cordova", "phonegap", "angularjs", "angularts", "angular"},
+ "ActionScript", new String[]{"actionscript"})
+ );
+
+ setLanguage("MySQL", "mysql"); // not WebStorm
+ setLanguage("SQLite", "sqlite"); // not WebStorm
+
+ // Products listed for each entry
+ final IKeyword javaVersionedKeyword = new JavaSdkVersionDependentKeyword("java6", "java7", "java8", "java9");
+ final IKeyword javaKeyword = new SdkTypeSpecificKeyword("java", "Android SDK", "android");
+ final IKeyword javaFxKeyword = new ExcludeSdkTypeKeyword("javafx", "Android SDK");
+ final IKeyword grailsKeyword = new ExcludeSdkTypeKeyword("grails", "Android SDK");
+ final IKeyword groovyKeyword = new ExcludeSdkTypeKeyword("groovy", "Android SDK");
+ final IKeyword playjavaKeyword = new ExcludeSdkTypeKeyword("playjava", "Android SDK");
+ final IKeyword springKeyword = new ExcludeSdkTypeKeyword("spring", "Android SDK");
+
+ setLanguage("Dart", "dartlang", "dartdocs", "polymerdart", "angulardart"); // WebStorm
+ setLanguage("DjangoTemplate", "django"); // PyCharm
+ setLanguage("Groovy", "groovy"); // IntelliJ
+ setLanguage("Jade", "jade"); // WebStorm
+ setLanguage("JAVA", javaVersionedKeyword, javaKeyword, javaFxKeyword, grailsKeyword, groovyKeyword, playjavaKeyword, springKeyword, "cvj", "processing", "javadoc"); // IntelliJ
+ setLanguage("JsInJade", "javascript", "jade"); // WebStorm
+ setLanguage("JSP", javaVersionedKeyword, javaKeyword, javaFxKeyword, grailsKeyword, groovyKeyword, playjavaKeyword, springKeyword, "cvj", "javadoc"); // IntelliJ, WebStorm, PhpStorm
+ setLanguage("JSPX", javaVersionedKeyword, javaKeyword, javaFxKeyword, grailsKeyword, groovyKeyword, playjavaKeyword, springKeyword, "cvj", "javadoc"); // IntelliJ, WebStorm, PhpStorm
+ setLanguage("Mxml", "actionscript"); // IntelliJ
+ setLanguage("PHP", "php", "wordpress", "drupal", "zend", "laravel", "yii", "joomla", "ee", "codeigniter", "cakephp", "phpunit", "symfony", "typo3", "twig", "smarty", "phpp"); // PhpStorm
+ setLanguage("Play", "playjava"); // IntelliJ; uncertain
+ setLanguage("Puppet", "puppet"); // RubyMine, PyCharm
+ setLanguage("Python", new PythonSdkVersionDependentKeyword("python2", "python3"), "python", "django", "twisted", "sphinx", "flask", "tornado", "sqlalchemy", "numpy", "scipy", "salt", "cvp", "matplotlib"); // PyCharm
+ setLanguage("ruby", "ruby", "rubygems", "rails"); // RubyMine
+ setLanguage("Smarty", "smarty"); // PhpStorm
+ setLanguage("SmartyConfig", "smarty"); // PhpStorm
+ setLanguage("Twig", "twig"); // PhpStorm
+ setLanguage("go", "go", "godoc"); // GoLand
+
+ // SQL
+ setLanguage("SQL", new SqlDialectDependentKeyword("mysql", "mysql", "sqlite", "psql"));
+ setLanguage("PostgreSQL", "psql");
+
+ // Jetbrains Plugins
+ setLanguage("Haskell", "haskell");
+ setLanguage("Scala", "scala", "akka", "playscala");
+ setLanguage("SSP", "scala", "akka", "playscala");
+ setLanguage("TypoScript", "typo3");
+ setLanguage("Dockerfile", "docker", "bash", "manpages");
+
+ // Third-party Plugins
+ setLanguage("Bash", "bash", "manpages");
+ setLanguage("Google Go", "go", "godoc");
+ setLanguage("Lua", "lua", "corona");
+ setLanguage("Markdown", "markdown");
+ setLanguage("Clojure", "clojure");
+ setLanguage("Erlang", "erlang");
+ setLanguage("Elixir", "elixir");
+
+
+ /*
+ use the following command to display all available languages in the event log. intended for development purposes.
+ listRegisteredLanguages();
+ */
+ }
+
+
+ private void listRegisteredLanguages() {
+ Collection languages = Language.getRegisteredLanguages();
+
+ ArrayList languageList = new ArrayList();
+
+ for ( Language language : languages ) {
+ String languageStr = language.getID();
+
+ Language baseLanguage = language.getBaseLanguage();
+ while ( baseLanguage != null ) {
+ languageStr += " <- " + baseLanguage.getID();
+ baseLanguage = baseLanguage.getBaseLanguage();
+ }
+
+ languageList.add(languageStr);
+ }
+
+ Collections.sort(languageList);
+
+ String message = "";
+ for ( String s : languageList ) {
+ message += s + "\n";
+ }
+
+ Notifications.Bus.notify(new Notification("Dash", "Dash: Registered Languages ", message, NotificationType.INFORMATION));
+ }
+
+ private void setLanguage(String language, Object... keywords)
+ {
+ ArrayList keywordList = new ArrayList();
+
+ for (Object keyword : keywords) {
+ if ( keyword instanceof String ) {
+ keywordList.add(new Keyword((String) keyword));
+ }
+ else if ( keyword instanceof IKeyword ) {
+ keywordList.add((IKeyword) keyword);
+ }
+ else {
+ throw new Error("Invalid keyword");
+ }
+
+ }
+
+ languageMap.put(language, keywordList);
+ }
+
+ public String findLanguageName(Language language)
+ {
+ while ( language != null ) {
+ if ( languageMap.containsKey(language.getID()) ) {
+ return language.getID();
+ }
+
+ language = language.getBaseLanguage();
+ }
+
+ return null;
+ }
+
+ public List findKeywords(final LookupInfoDictionary dict)
+ {
+ ArrayList result = new ArrayList();
+
+ String languageName = findLanguageName(dict.getLanguage());
+ if ( languageName != null ) {
+ for ( IKeyword keyword : languageMap.get(languageName) ) {
+ String name = keyword.getName(dict);
+
+ if ( name != null ) {
+ result.add(name);
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/src/de/dreamlab/dash/LookupInfoDictionary.java b/src/de/dreamlab/dash/LookupInfoDictionary.java
new file mode 100644
index 0000000..dd47923
--- /dev/null
+++ b/src/de/dreamlab/dash/LookupInfoDictionary.java
@@ -0,0 +1,98 @@
+package de.dreamlab.dash;
+
+import com.intellij.lang.Language;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+
+public class LookupInfoDictionary{
+ private Language language;
+ private PsiElement psiElement;
+ private Project project;
+ private PsiFile psiFile;
+ private VirtualFile virtualFile;
+
+ private boolean isSdk = false;
+ private Sdk sdk = null;
+
+ private boolean isFileSqlLanguage = false;
+ private Language fileSqlLanguage;
+
+
+ public LookupInfoDictionary(Language language, PsiElement psiElement, Project project, PsiFile psiFile, VirtualFile virtualFile) {
+ this.language = language;
+ this.psiElement = psiElement;
+ this.project = project;
+ this.psiFile = psiFile;
+ this.virtualFile = virtualFile;
+ }
+
+ // initially set values
+ public Language getLanguage() {
+ return language;
+ }
+
+ public PsiElement getPsiElement() {
+ return psiElement;
+ }
+
+ public Project getProject() {
+ return project;
+ }
+
+ public PsiFile getPsiFile() {
+ return psiFile;
+ }
+
+ public VirtualFile getVirtualFile() {
+ return virtualFile;
+ }
+
+ // optional sdk value
+ public boolean isSdk() {
+ return isSdk;
+ }
+
+ public Sdk getSdk() {
+ if ( !isSdk) {
+ throw new Error("sdk has not been set");
+ }
+
+ return sdk;
+ }
+
+ public void setSdk(Sdk sdk) {
+ if (isSdk) {
+ throw new Error("sdk can only be set once");
+ }
+
+ this.sdk = sdk;
+ this.isSdk = true;
+ }
+
+ // optional fileSqlLanguage value
+ public boolean isFileSqlLanguage() {
+ return isFileSqlLanguage;
+ }
+
+ public Language getFileSqlLanguage() {
+ if ( !isFileSqlLanguage) {
+ throw new Error("fileSqlLanguage has not been set");
+ }
+
+ return fileSqlLanguage;
+ }
+
+ public void setFileSqlLanguage(Language fileSqlLanguage) {
+ if (isFileSqlLanguage) {
+ throw new Error("fileSqlLanguage can only be set once");
+ }
+
+ this.fileSqlLanguage = fileSqlLanguage;
+ this.isFileSqlLanguage = true;
+ }
+
+
+}
diff --git a/src/de/dreamlab/dash/SearchAction.java b/src/de/dreamlab/dash/SearchAction.java
new file mode 100644
index 0000000..1bb8f46
--- /dev/null
+++ b/src/de/dreamlab/dash/SearchAction.java
@@ -0,0 +1,27 @@
+package de.dreamlab.dash;
+
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiFile;
+
+
+public class SearchAction extends AbstractMenuAction {
+ public SearchAction()
+ {
+ title = "Search all Documentation";
+ description = "Searches word under caret or selection in documentation";
+ }
+
+ public void actionPerformed(AnActionEvent e) {
+ final Editor editor = PlatformDataKeys.EDITOR.getData(e.getDataContext());
+ if ( editor == null ) {
+ return;
+ }
+
+ final Project project = e.getProject();
+ final PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE);
+
+ SearchService.getInstance().search(editor, project, psiFile);
+ }
+}
diff --git a/src/de/dreamlab/dash/SearchService.java b/src/de/dreamlab/dash/SearchService.java
new file mode 100644
index 0000000..407804d
--- /dev/null
+++ b/src/de/dreamlab/dash/SearchService.java
@@ -0,0 +1,217 @@
+package de.dreamlab.dash;
+
+import com.intellij.lang.Language;
+import com.intellij.lang.injection.InjectedLanguageManager;
+import com.intellij.notification.Notification;
+import com.intellij.notification.NotificationType;
+import com.intellij.notification.Notifications;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.SelectionModel;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.wm.impl.status.StatusBarUtil;
+import com.intellij.psi.PsiComment;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import de.dreamlab.dash.launcher.AbstractLauncher;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.ArrayList;
+
+public class SearchService {
+ // singleton
+ private static SearchService ourInstance = new SearchService();
+
+ public static SearchService getInstance()
+ {
+ return ourInstance;
+ }
+
+ // class instance
+ private static final String XML_LANGUAGE_ID = "XML";
+ private KeywordLookup keywordLookup;
+ private AbstractLauncher launcher;
+
+
+ private SearchService() {
+ keywordLookup = new KeywordLookup();
+ launcher = AbstractLauncher.createInstance();
+ }
+
+ private @Nullable PsiElement getPsiElementAtCursor(@Nonnull Editor editor, @Nullable Project project, @Nullable PsiFile psiFile)
+ {
+ if ( psiFile == null ) {
+ return null;
+ }
+
+ int caretOffset = editor.getCaretModel().getOffset();
+
+ if ( project != null ) {
+ InjectedLanguageManager injectedLanguageManager = InjectedLanguageManager.getInstance(project);
+
+ if ( injectedLanguageManager != null ) {
+ PsiElement injectedPsiElement = injectedLanguageManager.findInjectedElementAt(psiFile, caretOffset);
+
+ if ( injectedPsiElement != null ) {
+ return injectedPsiElement;
+ }
+ }
+ }
+
+ return psiFile.findElementAt(editor.getCaretModel().getOffset());
+ }
+
+ private @Nullable String getSearchQueryFromEditor(@Nonnull Editor editor, @Nullable PsiElement psiElement)
+ {
+ SelectionModel selectionModel = editor.getSelectionModel();
+ if ( selectionModel.hasSelection() ) {
+ return selectionModel.getSelectedText();
+ }
+
+ if ( psiElement == null || psiElement instanceof PsiComment ) {
+ return getWordAtCursor(editor);
+ }
+
+ return psiElement.getText();
+ }
+
+ public void search(@Nonnull Editor editor, @Nullable Project project, @Nullable PsiFile psiFile)
+ {
+ PsiElement psiElement = getPsiElementAtCursor(editor, project, psiFile);
+ String query = getSearchQueryFromEditor(editor, psiElement);
+
+ if ( query == null ) {
+ return;
+ }
+
+ // open dash
+ showStatusMessage(project, null, null);
+ launcher.search(new ArrayList<>(), query);
+ }
+
+ public void smartSearch(@Nonnull Editor editor, @Nullable Project project, @Nullable PsiFile psiFile, @Nullable VirtualFile virtualFile)
+ {
+ PsiElement psiElement = getPsiElementAtCursor(editor, project, psiFile);
+ Language language = elementLanguage(psiElement);
+ String resolvedLanguage = keywordLookup.findLanguageName(language);
+
+ if ( resolvedLanguage == null ) {
+ psiElement = null;
+ }
+
+ String query = getSearchQueryFromEditor(editor, psiElement);
+
+ if ( query == null ) {
+ return;
+ }
+
+ // open dash
+ showStatusMessage(project, resolvedLanguage, language);
+ launcher.search(keywordLookup.findKeywords(new LookupInfoDictionary(language, psiElement, project, psiFile, virtualFile)), query);
+
+ /*
+ use the following command to display information about the sdk in use in the event log. intended for development purposes.
+ showSdkDebug(AbstractSdkKeyword.findSdk(psiElement, project, psiFile, virtualFile));
+ */
+ }
+
+ private void showStatusMessage(final @Nullable Project project, final @Nullable String resolvedLanguage, final @Nullable Language language)
+ {
+ if ( project == null ) {
+ return;
+ }
+
+ // show status message for potential troubleshooting
+ final StringBuilder messageBuilder = new StringBuilder();
+
+ if ( resolvedLanguage == null ) {
+ messageBuilder.append("Searching all documentation");
+ }
+ else {
+ messageBuilder.append(String.format("Smart-Searching \"%s\" documentation", resolvedLanguage));
+ }
+
+ if ( language != null && !language.getID().equals(resolvedLanguage) ) {
+ messageBuilder.append(String.format(". Based on \"%s\" context.", language.getID()));
+ }
+
+ StatusBarUtil.setStatusBarInfo(project, messageBuilder.toString());
+ }
+
+ private void showSdkDebug(@Nullable Sdk sdk)
+ {
+ StringBuilder sdkMessage = new StringBuilder();
+
+ if ( sdk != null ) {
+ sdkMessage.append(String.format("Name: %s\n", sdk.getName()));
+ sdkMessage.append(String.format("SdkType: %s\n", sdk.getSdkType().getName()));
+ sdkMessage.append(String.format("VersionString: %s\n", sdk.getVersionString()));
+
+ }
+ else {
+ sdkMessage.append("not available");
+ }
+
+ Notifications.Bus.notify(new Notification("Dash", "Dash SDK: ", sdkMessage.toString(), NotificationType.INFORMATION));
+ }
+
+ private @Nullable Language elementLanguage(final @Nullable PsiElement element)
+ {
+ if ( element == null ) {
+ return null;
+ }
+
+ try {
+ if ( XML_LANGUAGE_ID.equals(element.getLanguage().getID()) ) {
+ PsiElement parent = element.getParent();
+
+ if ( !XML_LANGUAGE_ID.equals(parent.getLanguage().getID()) && XML_LANGUAGE_ID.equals(parent.getLanguage().getBaseLanguage().getID()) ) {
+ return parent.getLanguage();
+ }
+ }
+
+ return element.getLanguage();
+ }
+ catch ( NullPointerException e ) {
+ return null;
+ }
+ }
+
+ private @Nullable String getWordAtCursor(final @Nonnull Editor editor)
+ {
+ CharSequence editorText = editor.getDocument().getCharsSequence();
+ int cursorOffset = editor.getCaretModel().getOffset();
+ int editorTextLength = editorText.length();
+
+ if ( editorTextLength == 0 ) {
+ return null;
+ }
+
+ if ( (cursorOffset >= editorTextLength) || (cursorOffset > 1 && !isIdentifierPart(editorText.charAt(cursorOffset) ) && isIdentifierPart(editorText.charAt(cursorOffset - 1))) ) {
+ cursorOffset--;
+ }
+
+ if ( isIdentifierPart(editorText.charAt(cursorOffset)) ) {
+ int start = cursorOffset;
+ int end = cursorOffset;
+
+ while ( start > 0 && isIdentifierPart(editorText.charAt(start-1)) ) {
+ start--;
+ }
+
+ while ( end < editorTextLength && isIdentifierPart(editorText.charAt(end)) ) {
+ end++;
+ }
+
+ return editorText.subSequence(start, end).toString();
+ }
+ return null;
+ }
+
+ private boolean isIdentifierPart(final char ch)
+ {
+ return Character.isJavaIdentifierPart(ch);
+ }
+}
diff --git a/src/de/dreamlab/dash/SmartSearchAction.java b/src/de/dreamlab/dash/SmartSearchAction.java
new file mode 100644
index 0000000..51e3a53
--- /dev/null
+++ b/src/de/dreamlab/dash/SmartSearchAction.java
@@ -0,0 +1,33 @@
+package de.dreamlab.dash;
+
+
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+
+public class SmartSearchAction extends AbstractMenuAction {
+
+ public SmartSearchAction()
+ {
+ title = "Smart-Search Documentation";
+ description = "Searches word under caret or selection in documentation filtered by currently used language";
+ iconFilename = "dash.png";
+ }
+
+ public void actionPerformed(AnActionEvent e) {
+ final Editor editor = PlatformDataKeys.EDITOR.getData(e.getDataContext());
+ if ( editor == null ) {
+ return;
+ }
+
+ final Project project = e.getProject();
+ final PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE);
+ final VirtualFile virtualFile = e.getData(LangDataKeys.VIRTUAL_FILE);
+
+ SearchService.getInstance().smartSearch(editor, project, psiFile, virtualFile);
+ }
+}
diff --git a/src/de/dreamlab/dash/SystemUtil.java b/src/de/dreamlab/dash/SystemUtil.java
new file mode 100644
index 0000000..7214e7b
--- /dev/null
+++ b/src/de/dreamlab/dash/SystemUtil.java
@@ -0,0 +1,35 @@
+package de.dreamlab.dash;
+
+public class SystemUtil {
+ private static boolean isOSMac = false;
+ private static boolean isOSWindows = false;
+ private static boolean isOSLinux = false;
+
+ static {
+ try {
+ String osName = System.getProperty("os.name").toLowerCase();
+
+ if ( osName.startsWith("mac") ) {
+ isOSMac = true;
+ } else if ( osName.startsWith("windows") ) {
+ isOSWindows = true;
+ } else if ( osName.startsWith("linux") ) {
+ isOSLinux = true;
+ }
+ }
+ catch ( Throwable e ) {
+ }
+ }
+
+ public static boolean isIsOSMac() {
+ return isOSMac;
+ }
+
+ public static boolean isIsOSWindows() {
+ return isOSWindows;
+ }
+
+ public static boolean isIsOSLinux() {
+ return isOSLinux;
+ }
+}
diff --git a/src/de/dreamlab/dash/keywords/AbstractSdkKeyword.java b/src/de/dreamlab/dash/keywords/AbstractSdkKeyword.java
new file mode 100644
index 0000000..9d79e8c
--- /dev/null
+++ b/src/de/dreamlab/dash/keywords/AbstractSdkKeyword.java
@@ -0,0 +1,56 @@
+package de.dreamlab.dash.keywords;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import de.dreamlab.dash.LookupInfoDictionary;
+
+public abstract class AbstractSdkKeyword {
+
+ protected Sdk getSdk(LookupInfoDictionary dict)
+ {
+ if ( !dict.isSdk() ) {
+ dict.setSdk(findSdk(dict.getPsiElement(), dict.getProject(), dict.getPsiFile(), dict.getVirtualFile()));
+ }
+
+ return dict.getSdk();
+ }
+
+ public static Sdk findSdk(final PsiElement psiElement, final Project project, final PsiFile psiFile, final VirtualFile virtualFile)
+ {
+ Module module = null;
+
+ if ( psiFile != null ) {
+ module = ModuleUtil.findModuleForPsiElement(psiFile);
+
+ // Get the module associated with the PsiElement, if one is present.
+ if (module == null && psiElement != null) {
+ module = ModuleUtil.findModuleForPsiElement(psiElement);
+ }
+ }
+
+ // Get the module associated with the VIRTUAL_FILE, if one is present.
+ if ( module == null ) {
+ if ( virtualFile != null && project != null ) {
+ module = ModuleUtil.findModuleForFile(virtualFile, project);
+ }
+ }
+
+ // Get the SDK associated with the previously found module, or use the project-wide SDK if no module has been found.
+ if ( module != null ) {
+ return ModuleRootManager.getInstance(module).getSdk();
+ }
+ else if ( project != null) {
+ return ProjectRootManager.getInstance(project).getProjectSdk();
+ }
+ else {
+ return null;
+ }
+ }
+}
diff --git a/src/de/dreamlab/dash/keywords/ExcludeFileTypeKeyword.java b/src/de/dreamlab/dash/keywords/ExcludeFileTypeKeyword.java
new file mode 100644
index 0000000..89762e5
--- /dev/null
+++ b/src/de/dreamlab/dash/keywords/ExcludeFileTypeKeyword.java
@@ -0,0 +1,28 @@
+package de.dreamlab.dash.keywords;
+
+import de.dreamlab.dash.LookupInfoDictionary;
+
+public class ExcludeFileTypeKeyword implements IKeyword {
+ private String keyword;
+ private String fileType;
+
+
+ public ExcludeFileTypeKeyword(String keyword, String fileType)
+ {
+ this.keyword = keyword;
+ this.fileType = fileType;
+ }
+
+ @Override
+ public String getName(LookupInfoDictionary dict) {
+ try {
+ if (fileType.equals(dict.getPsiFile().getFileType().getName())) {
+ return null;
+ }
+ }
+ catch ( Throwable e ) {
+ }
+
+ return keyword;
+ }
+}
diff --git a/src/de/dreamlab/dash/keywords/ExcludeSdkTypeKeyword.java b/src/de/dreamlab/dash/keywords/ExcludeSdkTypeKeyword.java
new file mode 100644
index 0000000..f89caf3
--- /dev/null
+++ b/src/de/dreamlab/dash/keywords/ExcludeSdkTypeKeyword.java
@@ -0,0 +1,28 @@
+package de.dreamlab.dash.keywords;
+
+import com.intellij.openapi.projectRoots.Sdk;
+import de.dreamlab.dash.LookupInfoDictionary;
+
+public class ExcludeSdkTypeKeyword extends AbstractSdkKeyword implements IKeyword {
+ private String keyword;
+ private String sdkType;
+
+ public ExcludeSdkTypeKeyword(String keyword, String sdkType) {
+ this.keyword = keyword;
+ this.sdkType = sdkType;
+ }
+
+ public String getName(final LookupInfoDictionary dict) {
+ Sdk sdk = getSdk(dict);
+
+ if ( sdkType == null ) {
+ return null;
+ }
+ else if ( sdk != null && !sdkType.equals(sdk.getSdkType().getName()) ) {
+ return keyword;
+ }
+ else {
+ return null;
+ }
+ }
+}
diff --git a/src/de/dreamlab/dash/keywords/FileTypeSpecificKeyword.java b/src/de/dreamlab/dash/keywords/FileTypeSpecificKeyword.java
new file mode 100644
index 0000000..2c09bd1
--- /dev/null
+++ b/src/de/dreamlab/dash/keywords/FileTypeSpecificKeyword.java
@@ -0,0 +1,43 @@
+package de.dreamlab.dash.keywords;
+
+import de.dreamlab.dash.LookupInfoDictionary;
+
+import java.util.ArrayList;
+
+public class FileTypeSpecificKeyword implements IKeyword {
+ private String keyword;
+ private String fileType;
+
+
+ public FileTypeSpecificKeyword(String keyword, String fileType) {
+ this.keyword = keyword;
+ this.fileType = fileType;
+ }
+
+ @Override
+ public String getName(LookupInfoDictionary dict) {
+ try {
+ if (fileType.equals(dict.getPsiFile().getFileType().getName())) {
+ return keyword;
+ }
+ } catch (Throwable e) {
+ }
+
+ return null;
+ }
+
+ public static IKeyword[] createList(String[] defaultKeywords, String fileType, String[] fileTypeSpecificKeywords)
+ {
+ ArrayList result = new ArrayList();
+
+ for ( String defaultKeyword : defaultKeywords ) {
+ result.add(new ExcludeFileTypeKeyword(defaultKeyword, fileType));
+ }
+
+ for ( String fileTypeSpecificKeyword : fileTypeSpecificKeywords ) {
+ result.add(new FileTypeSpecificKeyword(fileTypeSpecificKeyword, fileType));
+ }
+
+ return result.toArray(new IKeyword[result.size()]);
+ }
+}
diff --git a/src/de/dreamlab/dash/keywords/IKeyword.java b/src/de/dreamlab/dash/keywords/IKeyword.java
new file mode 100644
index 0000000..e188261
--- /dev/null
+++ b/src/de/dreamlab/dash/keywords/IKeyword.java
@@ -0,0 +1,9 @@
+package de.dreamlab.dash.keywords;
+
+import com.sun.istack.internal.Nullable;
+import de.dreamlab.dash.LookupInfoDictionary;
+
+public interface IKeyword {
+ @Nullable
+ public String getName(final LookupInfoDictionary dict);
+}
diff --git a/src/de/dreamlab/dash/keywords/JavaSdkVersionDependentKeyword.java b/src/de/dreamlab/dash/keywords/JavaSdkVersionDependentKeyword.java
new file mode 100644
index 0000000..0fe1277
--- /dev/null
+++ b/src/de/dreamlab/dash/keywords/JavaSdkVersionDependentKeyword.java
@@ -0,0 +1,44 @@
+package de.dreamlab.dash.keywords;
+
+import com.intellij.openapi.projectRoots.Sdk;
+import de.dreamlab.dash.LookupInfoDictionary;
+
+public class JavaSdkVersionDependentKeyword extends AbstractSdkKeyword implements IKeyword {
+ private String java6Keyword;
+ private String java7Keyword;
+ private String java8Keyword;
+ private String java9Keyword;
+
+ public JavaSdkVersionDependentKeyword(String java6Keyword, String java7Keyword, String java8Keyword, String java9Keyword) {
+ this.java6Keyword = java6Keyword;
+ this.java7Keyword = java7Keyword;
+ this.java8Keyword = java8Keyword;
+ this.java9Keyword = java9Keyword;
+ }
+
+ @Override
+ public String getName(LookupInfoDictionary dict) {
+ Sdk sdk = getSdk(dict);
+
+ if ( sdk != null && sdk.getSdkType().getName().equals("JavaSDK") ) {
+ String versionString = sdk.getVersionString();
+
+ if ( versionString != null ) {
+ if ( versionString.contains("1.6.") ) {
+ return java6Keyword;
+ }
+ else if ( versionString.contains("1.7.") ) {
+ return java7Keyword;
+ }
+ else if ( versionString.contains("1.8.") ) {
+ return java8Keyword;
+ }
+ else if ( versionString.contains("1.9.") ) {
+ return java9Keyword;
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/de/dreamlab/dash/keywords/Keyword.java b/src/de/dreamlab/dash/keywords/Keyword.java
new file mode 100644
index 0000000..3766d8a
--- /dev/null
+++ b/src/de/dreamlab/dash/keywords/Keyword.java
@@ -0,0 +1,15 @@
+package de.dreamlab.dash.keywords;
+
+import de.dreamlab.dash.LookupInfoDictionary;
+
+public class Keyword implements IKeyword {
+ private String keyword;
+
+ public Keyword(String keyword) {
+ this.keyword = keyword;
+ }
+
+ public String getName(final LookupInfoDictionary dict) {
+ return keyword;
+ }
+}
diff --git a/src/de/dreamlab/dash/keywords/PythonSdkVersionDependentKeyword.java b/src/de/dreamlab/dash/keywords/PythonSdkVersionDependentKeyword.java
new file mode 100644
index 0000000..46f433b
--- /dev/null
+++ b/src/de/dreamlab/dash/keywords/PythonSdkVersionDependentKeyword.java
@@ -0,0 +1,34 @@
+package de.dreamlab.dash.keywords;
+
+import com.intellij.openapi.projectRoots.Sdk;
+import de.dreamlab.dash.LookupInfoDictionary;
+
+public class PythonSdkVersionDependentKeyword extends AbstractSdkKeyword implements IKeyword {
+ private String python2Keyword;
+ private String python3Keyword;
+
+ public PythonSdkVersionDependentKeyword(String python2Keyword, String python3Keyword) {
+ this.python2Keyword = python2Keyword;
+ this.python3Keyword = python3Keyword;
+ }
+
+ @Override
+ public String getName(LookupInfoDictionary dict) {
+ Sdk sdk = getSdk(dict);
+
+ if ( sdk != null && sdk.getSdkType().getName().equals("Python SDK") ) {
+ String versionString = sdk.getVersionString();
+
+ if ( versionString != null ) {
+ if ( versionString.contains("Python 2") ) {
+ return python2Keyword;
+ }
+ else if ( versionString.contains("Python 3") ) {
+ return python3Keyword;
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/de/dreamlab/dash/keywords/SdkTypeSpecificKeyword.java b/src/de/dreamlab/dash/keywords/SdkTypeSpecificKeyword.java
new file mode 100644
index 0000000..c7e8984
--- /dev/null
+++ b/src/de/dreamlab/dash/keywords/SdkTypeSpecificKeyword.java
@@ -0,0 +1,42 @@
+package de.dreamlab.dash.keywords;
+
+import com.intellij.openapi.projectRoots.Sdk;
+import de.dreamlab.dash.LookupInfoDictionary;
+
+import java.util.HashMap;
+
+
+public class SdkTypeSpecificKeyword extends AbstractSdkKeyword implements IKeyword {
+ private String defaultKeyword = null;
+ private HashMap sdkTypes;
+
+ public SdkTypeSpecificKeyword(String defaultKeyword, String... sdkTypesAndKeywords) {
+ if ( (sdkTypesAndKeywords.length % 2) != 0 ) {
+ throw new Error("Missing keyword for sdk: " + sdkTypesAndKeywords[sdkTypesAndKeywords.length - 1]);
+ }
+
+ this.defaultKeyword = defaultKeyword;
+
+ sdkTypes = new HashMap();
+
+ for ( int i = 0; i < sdkTypesAndKeywords.length; i += 2 ) {
+ sdkTypes.put(sdkTypesAndKeywords[0], sdkTypesAndKeywords[1]);
+ }
+ }
+
+ public SdkTypeSpecificKeyword(String keyword, String sdkType) {
+ sdkTypes = new HashMap();
+ sdkTypes.put(sdkType, keyword);
+ }
+
+ public String getName(final LookupInfoDictionary dict)
+ {
+ Sdk sdk = getSdk(dict);
+
+ if ( sdk != null && sdkTypes.containsKey(sdk.getSdkType().getName()) ) {
+ return sdkTypes.get(sdk.getSdkType().getName());
+ }
+
+ return defaultKeyword;
+ }
+}
\ No newline at end of file
diff --git a/src/de/dreamlab/dash/keywords/SqlDialectDependentKeyword.java b/src/de/dreamlab/dash/keywords/SqlDialectDependentKeyword.java
new file mode 100644
index 0000000..662dd10
--- /dev/null
+++ b/src/de/dreamlab/dash/keywords/SqlDialectDependentKeyword.java
@@ -0,0 +1,69 @@
+package de.dreamlab.dash.keywords;
+
+import com.intellij.lang.Language;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import de.dreamlab.dash.LookupInfoDictionary;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
+public class SqlDialectDependentKeyword implements IKeyword {
+ private HashMap languageMap;
+
+ public SqlDialectDependentKeyword(String defaultKeyword, String mySqlKeyword, String sqliteKeyword, String postgreSqlKeyword) {
+ languageMap = new HashMap();
+
+ languageMap.put("SQL", defaultKeyword);
+ languageMap.put("MySQL", mySqlKeyword);
+ languageMap.put("SQLite", sqliteKeyword);
+ languageMap.put("PostgreSQL", postgreSqlKeyword);
+ }
+
+ @Override
+ public String getName(final LookupInfoDictionary dict) {
+ if ( !dict.isFileSqlLanguage() ) {
+ setDictFileSqlLanguage(dict);
+ }
+
+ Language fileSqlLanguage = dict.getFileSqlLanguage();
+
+ if ( fileSqlLanguage != null ) {
+ return languageMap.get(findLanguageName(fileSqlLanguage));
+ }
+ else {
+ return null;
+ }
+ }
+
+ public String findLanguageName(Language language)
+ {
+ while ( language != null ) {
+ if ( languageMap.containsKey(language.getID()) ) {
+ return language.getID();
+ }
+
+ language = language.getBaseLanguage();
+ }
+
+ return null;
+ }
+
+ private void setDictFileSqlLanguage(LookupInfoDictionary dict)
+ {
+ Language language = null;
+
+ try {
+// using reflection for the following command, because of optional dependencies
+// language = com.intellij.sql.dialects.SqlDialectMappings.getMapping(dict.getProject(), dict.getVirtualFile());
+ Class sqlClass = Class.forName("com.intellij.sql.dialects.SqlDialectMappings");
+ Method getMappingMethod = sqlClass.getMethod("getMapping", Project.class, VirtualFile.class);
+ language = (Language)getMappingMethod.invoke(null, dict.getProject(), dict.getVirtualFile());
+ }
+ catch (Throwable e) {
+ }
+
+ dict.setFileSqlLanguage(language);
+ }
+
+}
diff --git a/src/de/dreamlab/dash/launcher/AbstractLauncher.java b/src/de/dreamlab/dash/launcher/AbstractLauncher.java
new file mode 100644
index 0000000..51e4ef8
--- /dev/null
+++ b/src/de/dreamlab/dash/launcher/AbstractLauncher.java
@@ -0,0 +1,51 @@
+package de.dreamlab.dash.launcher;
+
+import com.intellij.notification.Notification;
+import com.intellij.notification.NotificationType;
+import com.intellij.notification.Notifications;
+import de.dreamlab.dash.SystemUtil;
+
+import javax.annotation.Nonnull;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.List;
+
+public abstract class AbstractLauncher {
+
+ public static AbstractLauncher createInstance()
+ {
+ if ( SystemUtil.isIsOSMac() ) {
+ return new DashLauncher();
+ }
+ else {
+ return new DashPluginSchemeLauncher();
+ }
+ }
+
+ abstract protected void openUri(String uriStr) throws Exception;
+
+ public void search(final @Nonnull List keywords, final @Nonnull String query)
+ {
+ try {
+ String request = "dash-plugin://";
+
+ // keywords
+ if ( keywords.size() > 0 ) {
+ request += "keys=" + String.join(",", keywords) + "&";
+ }
+
+ // query
+ request += "query=" + urlEncode(query);
+
+ openUri(request);
+ }
+ catch ( Throwable e ) {
+ Notifications.Bus.notify(new Notification("Dash Plugin Error", "Dash Plugin Error", e.getMessage(), NotificationType.ERROR));
+ }
+ }
+
+ private String urlEncode(final @Nonnull String s) throws UnsupportedEncodingException
+ {
+ return URLEncoder.encode(s, "UTF-8").replace("+", "%20");
+ }
+}
diff --git a/src/de/dreamlab/dash/launcher/DashLauncher.java b/src/de/dreamlab/dash/launcher/DashLauncher.java
new file mode 100644
index 0000000..3212a15
--- /dev/null
+++ b/src/de/dreamlab/dash/launcher/DashLauncher.java
@@ -0,0 +1,21 @@
+/**
+ * Created by gerard on 12.04.15.
+ */
+
+package de.dreamlab.dash.launcher;
+
+import com.intellij.execution.configurations.GeneralCommandLine;
+
+import javax.annotation.Nonnull;
+
+public class DashLauncher extends AbstractLauncher {
+
+ protected void openUri(final @Nonnull String uriStr) throws Exception
+ {
+ final GeneralCommandLine commandLine = new GeneralCommandLine("open");
+ commandLine.addParameter("-g");
+ commandLine.addParameter(uriStr);
+ commandLine.createProcess();
+ }
+
+}
diff --git a/src/de/dreamlab/dash/launcher/DashPluginSchemeLauncher.java b/src/de/dreamlab/dash/launcher/DashPluginSchemeLauncher.java
new file mode 100644
index 0000000..42aa6c6
--- /dev/null
+++ b/src/de/dreamlab/dash/launcher/DashPluginSchemeLauncher.java
@@ -0,0 +1,20 @@
+/**
+ * Created by gerard on 04.04.14.
+ */
+
+package de.dreamlab.dash.launcher;
+
+import javax.annotation.Nonnull;
+import java.awt.*;
+import java.net.URI;
+
+public class DashPluginSchemeLauncher extends AbstractLauncher {
+
+ protected void openUri(final @Nonnull String uriStr) throws Exception
+ {
+ Desktop desktop = Desktop.getDesktop();
+ URI uri = new URI(uriStr);
+ desktop.browse(uri);
+ }
+
+}
\ No newline at end of file