PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/ccw.core/src/java/ccw/CCWPlugin.java

https://gitlab.com/klauer/ccw
Java | 389 lines | 274 code | 63 blank | 52 comment | 36 complexity | 9d535ba626dfd531d284d9d7e89a7d1e MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright (c) 2009 Casey Marshall and others.
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * http://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors:
  9. * Casey Marshall - initial API and implementation
  10. * Thomas Ettinger - paren matching generic code
  11. * Stephan Muehlstrasser - preference support for syntax coloring
  12. *******************************************************************************/
  13. package ccw;
  14. import java.io.IOException;
  15. import java.net.ServerSocket;
  16. import java.util.Map;
  17. import org.eclipse.core.resources.IProject;
  18. import org.eclipse.core.runtime.CoreException;
  19. import org.eclipse.core.runtime.IStatus;
  20. import org.eclipse.core.runtime.Status;
  21. import org.eclipse.debug.core.ILaunch;
  22. import org.eclipse.jface.preference.IPreferenceStore;
  23. import org.eclipse.jface.preference.PreferenceConverter;
  24. import org.eclipse.jface.resource.ColorRegistry;
  25. import org.eclipse.jface.resource.FontRegistry;
  26. import org.eclipse.jface.resource.ImageDescriptor;
  27. import org.eclipse.jface.resource.ImageRegistry;
  28. import org.eclipse.jface.resource.StringConverter;
  29. import org.eclipse.swt.graphics.Color;
  30. import org.eclipse.swt.graphics.Font;
  31. import org.eclipse.swt.graphics.RGB;
  32. import org.eclipse.swt.widgets.Display;
  33. import org.eclipse.ui.IViewPart;
  34. import org.eclipse.ui.IViewReference;
  35. import org.eclipse.ui.IWorkbenchPage;
  36. import org.eclipse.ui.IWorkbenchWindow;
  37. import org.eclipse.ui.PlatformUI;
  38. import org.eclipse.ui.editors.text.EditorsUI;
  39. import org.eclipse.ui.plugin.AbstractUIPlugin;
  40. import org.eclipse.ui.texteditor.ChainedPreferenceStore;
  41. import org.osgi.framework.BundleContext;
  42. import ccw.editors.clojure.IScanContext;
  43. import ccw.launching.LaunchUtils;
  44. import ccw.nature.AutomaticNatureAdder;
  45. import ccw.preferences.PreferenceConstants;
  46. import ccw.preferences.SyntaxColoringPreferencePage;
  47. import ccw.repl.REPLView;
  48. import ccw.util.BundleUtils;
  49. import ccw.util.DisplayUtil;
  50. import clojure.lang.Agent;
  51. import clojure.lang.Keyword;
  52. import clojure.lang.Var;
  53. import clojure.osgi.ClojureOSGi;
  54. import clojure.tools.nrepl.Connection;
  55. /**
  56. * The activator class controls the plug-in life cycle
  57. */
  58. public class CCWPlugin extends AbstractUIPlugin {
  59. /** The plug-in ID */
  60. public static final String PLUGIN_ID = "ccw.core";
  61. /**
  62. * @param swtKey a key from SWT.COLOR_xxx
  63. * @return a system managed color (callers must not dispose
  64. * the color themselves)
  65. */
  66. public static Color getSystemColor(int swtKey) {
  67. return Display.getDefault().getSystemColor(swtKey);
  68. }
  69. /** The shared instance */
  70. private static CCWPlugin plugin;
  71. private ColorRegistry colorCache;
  72. private FontRegistry fontRegistry;
  73. private ServerSocket ackREPLServer;
  74. private AutomaticNatureAdder natureAdapter = new AutomaticNatureAdder();
  75. public synchronized void startREPLServer() throws CoreException {
  76. if (ackREPLServer == null) {
  77. try {
  78. Var startServer = BundleUtils.requireAndGetVar(getBundle().getSymbolicName(), "clojure.tools.nrepl.server/start-server");
  79. Object defaultHandler = BundleUtils.requireAndGetVar(
  80. getBundle().getSymbolicName(),
  81. "clojure.tools.nrepl.server/default-handler").invoke();
  82. Object handler = BundleUtils.requireAndGetVar(
  83. getBundle().getSymbolicName(),
  84. "clojure.tools.nrepl.ack/handle-ack").invoke(defaultHandler);
  85. ackREPLServer = (ServerSocket)((Map)((Agent)startServer.invoke(Keyword.intern("handler"), handler)).deref()).get(Keyword.intern("ss"));
  86. CCWPlugin.log("Started ccw nREPL server: nrepl://localhost:" + ackREPLServer.getLocalPort());
  87. } catch (Exception e) {
  88. CCWPlugin.logError("Could not start plugin-hosted REPL server", e);
  89. throw new CoreException(createErrorStatus("Could not start plugin-hosted REPL server", e));
  90. }
  91. }
  92. }
  93. public int getREPLServerPort() throws CoreException {
  94. if (ackREPLServer == null) {
  95. startREPLServer();
  96. }
  97. return ackREPLServer.getLocalPort();
  98. }
  99. public CCWPlugin() {
  100. // System.out.println("CCWPlugin instanciated");
  101. }
  102. public void start(BundleContext context) throws Exception {
  103. // System.out.println("CCWPlugin start() starts");
  104. super.start(context);
  105. plugin = this;
  106. startClojureCode(context);
  107. if (System.getProperty("ccw.autostartnrepl") != null) {
  108. startREPLServer();
  109. }
  110. this.natureAdapter.start();
  111. // System.out.println("CCWPlugin start() ends");
  112. }
  113. private synchronized void createColorCache() {
  114. if (colorCache == null) {
  115. colorCache = new ColorRegistry(getWorkbench().getDisplay());
  116. colorCache.put("ccw.repl.expressionBackground", new RGB(0xf0, 0xf0, 0xf0));
  117. }
  118. }
  119. /**
  120. * Must be called from the UI thread only
  121. */
  122. public ColorRegistry getColorCache() {
  123. if (colorCache == null) {
  124. createColorCache();
  125. }
  126. return colorCache;
  127. }
  128. private synchronized void createFontRegistry() {
  129. if (fontRegistry == null) {
  130. DisplayUtil.syncExec(new Runnable() {
  131. public void run() {
  132. fontRegistry = new FontRegistry(getWorkbench().getDisplay());
  133. // Forces initializations
  134. fontRegistry.getItalic(""); // readOnlyFont
  135. fontRegistry.getBold(""); // abstractFont
  136. }
  137. });
  138. }
  139. }
  140. private FontRegistry getFontRegistry() {
  141. if (fontRegistry == null) {
  142. createFontRegistry();
  143. }
  144. return fontRegistry;
  145. }
  146. public final Font getJavaSymbolFont() {
  147. return getFontRegistry().getItalic("");
  148. }
  149. private IPreferenceStore prefs;
  150. /**
  151. * Create a preference store combined from the Clojure, the EditorsUI and
  152. * the PlatformUI preference stores to inherit all the default text editor
  153. * settings from the Eclipse preferences.
  154. *
  155. * @return the combined preference store.
  156. */
  157. public IPreferenceStore getCombinedPreferenceStore() {
  158. if (prefs == null) {
  159. prefs = new ChainedPreferenceStore(new IPreferenceStore[] {
  160. CCWPlugin.getDefault().getPreferenceStore(),
  161. EditorsUI.getPreferenceStore(),
  162. PlatformUI.getPreferenceStore()});
  163. }
  164. return prefs;
  165. }
  166. private void startClojureCode(BundleContext bundleContext) throws Exception {
  167. // ClojureOSGi.loadAOTClass(bundleContext, "ccw.editors.clojure.ClojureFormat");
  168. ClojureOSGi.require(bundleContext, "ccw.editors.clojure.hyperlink");
  169. ClojureOSGi.require(bundleContext, "ccw.editors.clojure.editor-support");
  170. ClojureOSGi.require(bundleContext, "ccw.editors.clojure.ClojureTopLevelFormsDamagerImpl");
  171. ClojureOSGi.require(bundleContext, "ccw.editors.clojure.PareditAutoEditStrategyImpl");
  172. ClojureOSGi.require(bundleContext, "ccw.debug.clientrepl");
  173. ClojureOSGi.require(bundleContext, "ccw.debug.serverrepl"); // <= to enable REPLView
  174. // server-side tooling
  175. ClojureOSGi.require(bundleContext, "ccw.static-analysis");
  176. }
  177. public void stop(BundleContext context) throws Exception {
  178. // We don't remove colors when deregistered, because, well, we don't have a
  179. // corresponding method on the ColorRegistry instance!
  180. // We also don't remove fonts when deregistered
  181. stopREPLServer();
  182. this.natureAdapter.stop();
  183. plugin = null;
  184. super.stop(context);
  185. }
  186. private void stopREPLServer() {
  187. if (ackREPLServer != null) {
  188. try {
  189. ackREPLServer.close();
  190. } catch (IOException e) {
  191. logError("Error while trying to close ccw internal nrepl server", e);
  192. }
  193. }
  194. }
  195. /**
  196. * @return the shared instance
  197. */
  198. public static CCWPlugin getDefault() {
  199. return plugin;
  200. }
  201. public static void logError(String msg) {
  202. plugin.getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, msg));
  203. }
  204. public static void logError(String msg, Throwable e) {
  205. plugin.getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, msg, e));
  206. }
  207. public static void logError(Throwable e) {
  208. plugin.getLog().log(
  209. new Status(IStatus.ERROR, PLUGIN_ID, e.getMessage(), e));
  210. }
  211. public static IStatus createErrorStatus(String message, Throwable e) {
  212. return new Status(IStatus.ERROR, PLUGIN_ID, message, e);
  213. }
  214. public static IStatus createErrorStatus(String message) {
  215. return new Status(IStatus.ERROR, PLUGIN_ID, message);
  216. }
  217. public static void logWarning(String msg) {
  218. plugin.getLog().log(new Status(IStatus.WARNING, PLUGIN_ID, msg));
  219. }
  220. public static void logWarning(String msg, Throwable e) {
  221. plugin.getLog().log(new Status(IStatus.WARNING, PLUGIN_ID, msg, e));
  222. }
  223. public static void logWarning(Throwable e) {
  224. plugin.getLog().log(
  225. new Status(IStatus.WARNING, PLUGIN_ID, e.getMessage(), e));
  226. }
  227. public static void log (String msg) {
  228. plugin.getLog().log(new Status(IStatus.INFO, PLUGIN_ID, msg));
  229. }
  230. @Override
  231. protected void initializeImageRegistry(ImageRegistry reg) {
  232. reg.put(NS, ImageDescriptor.createFromURL(getBundle().getEntry("/icons/jdt/package_obj.gif")));
  233. reg.put(PUBLIC_FUNCTION, ImageDescriptor.createFromURL(getBundle().getEntry("/icons/jdt/methpub_obj.gif")));
  234. reg.put(PRIVATE_FUNCTION, ImageDescriptor.createFromURL(getBundle().getEntry("/icons/jdt/methpri_obj.gif")));
  235. reg.put(CLASS, ImageDescriptor.createFromURL(getBundle().getEntry("/icons/jdt/class_obj.gif")));
  236. reg.put(SORT, ImageDescriptor.createFromURL(getBundle().getEntry("/icons/jdt/alphab_sort_co.gif")));
  237. }
  238. public static final String NS = "icon.namespace";
  239. public static final String PUBLIC_FUNCTION = "icon.function.public";
  240. public static final String PRIVATE_FUNCTION = "icon.function.private";
  241. public static final String CLASS = "class_obj.gif";
  242. public static final String SORT = "alphab_sort_co.gif";
  243. public static boolean isAutoReloadEnabled(ILaunch launch) {
  244. return (Boolean.parseBoolean(launch.getAttribute(LaunchUtils.ATTR_IS_AUTO_RELOAD_ENABLED)));
  245. }
  246. public REPLView getProjectREPL (final IProject project) {
  247. final REPLView[] ret = new REPLView[1];
  248. DisplayUtil.syncExec(new Runnable() {
  249. public void run() {
  250. IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
  251. if (window != null) {
  252. IWorkbenchPage page = window.getActivePage();
  253. if (page != null) {
  254. for (IViewReference r : page.getViewReferences()) {
  255. IViewPart v = r.getView(false);
  256. if (REPLView.class.isInstance(v)) {
  257. REPLView replView = (REPLView)v;
  258. ILaunch launch = replView.getLaunch();
  259. if (launch!=null && !launch.isTerminated()) {
  260. String launchProject = launch.getAttribute(LaunchUtils.ATTR_PROJECT_NAME);
  261. if (launchProject != null && launchProject.equals(project.getName())) {
  262. ret[0] = replView;
  263. return;
  264. }
  265. }
  266. }
  267. }
  268. }
  269. }
  270. }
  271. });
  272. return ret[0];
  273. }
  274. public Connection getProjectREPLConnection (IProject project) {
  275. REPLView repl = getProjectREPL(project);
  276. return repl == null ? null : repl.getToolingConnection();
  277. }
  278. private IScanContext scanContext;
  279. public synchronized IScanContext getDefaultScanContext() {
  280. if (scanContext == null) {
  281. scanContext = new StaticScanContext();
  282. }
  283. return scanContext;
  284. }
  285. public static RGB getPreferenceRGB(IPreferenceStore store, String preferenceKey, RGB defaultColor) {
  286. return
  287. store.getBoolean(SyntaxColoringPreferencePage.getEnabledPreferenceKey(preferenceKey))
  288. ? PreferenceConverter.getColor(store, preferenceKey)
  289. : defaultColor;
  290. }
  291. /**
  292. * Not thread safe, but should only be called from the UI Thread, so it's
  293. * not really a problem.
  294. * @param rgb
  295. * @return The <code>Color</code> instance cached for this rgb value, creating
  296. * it along the way if required.
  297. */
  298. public static Color getColor(RGB rgb) {
  299. ColorRegistry r = getDefault().getColorCache();
  300. String rgbString = StringConverter.asString(rgb);
  301. if (!r.hasValueFor(rgbString)) {
  302. r.put(rgbString, rgb);
  303. }
  304. return r.get(rgbString);
  305. }
  306. public static Color getPreferenceColor(IPreferenceStore store, String preferenceKey, RGB defaultColor) {
  307. return getColor(getPreferenceRGB(store, preferenceKey, defaultColor));
  308. }
  309. public static void registerEditorColors(IPreferenceStore store, RGB foregroundColor) {
  310. final ColorRegistry colorCache = getDefault().getColorCache();
  311. for (Keyword token: PreferenceConstants.colorizableTokens) {
  312. PreferenceConstants.ColorizableToken tokenStyle = PreferenceConstants.getColorizableToken(store, token, foregroundColor);
  313. colorCache.put(tokenStyle.rgb.toString(), tokenStyle.rgb);
  314. }
  315. }
  316. public static IWorkbenchPage getActivePage() {
  317. return getDefault().internalGetActivePage();
  318. }
  319. // copied from JavaPlugin
  320. private IWorkbenchPage internalGetActivePage() {
  321. IWorkbenchWindow window= getWorkbench().getActiveWorkbenchWindow();
  322. if (window == null)
  323. return null;
  324. return window.getActivePage();
  325. }
  326. }