Fork me on GitHub

I haven't published the intellij plugin just yet as I would like some folks to try it out first before it's available in the plugin repository. If you are an intellij user, you can pull down the and install it manually from disk. Feedback welcome!


Another major highlight is multi-select which enables n-arity commands. To perform a multil-select, hold down cmd on osx and click multiple values (haven't tried this on windows yet). You can now select any two items and diff them directly via lambdaisland.deep-diff2/diff! This also works for any user supplied commands.


To launch the UI in intellij, do (def idea (p/open {:launcher :intellij})) . Documentation will be updated soon.


I have installed the intellij plugin from the zip and I have confirmed the plugin is active but I don't see any new viewer. How can I get to the portal viewer?


That was it. My clojure project is a directory within a larger IntelliJ project.


When I create a new IntelliJ project pointing to the correct subdirectory, I have the Portal tool viewer.

awesome 1

I could remove this limitation, just thought most people would be annoyed to see the portal tool window if it wasn't a clojure project.


would be nice to have the option, in my case I also have a problem with multiple modules inside


altough I just tried in one that's a simple clojure project, I still can't see the portal tool window


Is the repl process running inside the project?


> I could remove this limitation, just thought most people would be annoyed to see the portal tool window if it wasn't a clojure project. My opinion: If you don't want to see the portal viewer, simply close it in IntelliJ. I suspect the isApplicable guard will be more annoying than useful

๐Ÿ‘ 1

@U2845S9KL agreed ๐Ÿ’ฏ

๐Ÿ‘ 1

yes, REPL running inside the project


is this something I have to do myself? Im on latest stable intellij, and didn't remember changing anything related to JCEF


I got some errors in the log


com.intellij.diagnostic.PluginException: Cannot create class portal.extensions.intellij.Factory (classloader=PluginClassLoader(plugin=PluginDescriptor(name=portal, id=djblue.portal-extension-intellij, descriptorPath=plugin.xml, path=~/Library/Application Support/JetBrains/IntelliJIdea2021.2/plugins/portal-extension-intellij-0.17.0.jar, version=0.17.0, package=null), packagePrefix=null, instanceId=5, state=active))
	at com.intellij.serviceContainer.ComponentManagerImpl.instantiateClass(ComponentManagerImpl.kt:870)
	at com.intellij.serviceContainer.ComponentManagerImpl.instantiateClass(ComponentManagerImpl.kt:887)
	at com.intellij.openapi.wm.ToolWindowEP.getToolWindowFactory(
	at com.intellij.openapi.wm.impl.ToolWindowManagerImpl$$special$$inlined$processDescriptors$1.accept(ToolWindowManagerImpl.kt:2317)
	at com.intellij.openapi.wm.impl.ToolWindowManagerImpl$$special$$inlined$processDescriptors$1.accept(ToolWindowManagerImpl.kt:88)
	at com.intellij.openapi.extensions.impl.ExtensionPointImpl.processWithPluginDescriptor(
	at com.intellij.openapi.extensions.ExtensionPointName.processWithPluginDescriptor(
	at com.intellij.openapi.wm.impl.ToolWindowManagerImpl.<init>(ToolWindowManagerImpl.kt:2362)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(
	at java.base/java.lang.reflect.Constructor.newInstance(
	at com.intellij.serviceContainer.ConstructorInjectionKt.instantiateUsingPicoContainer(constructorInjection.kt:52)
	at com.intellij.serviceContainer.ComponentManagerImpl.instantiateClassWithConstructorInjection(ComponentManagerImpl.kt:877)
	at com.intellij.serviceContainer.ServiceComponentAdapter.createAndInitialize(ServiceComponentAdapter.kt:48)
	at com.intellij.serviceContainer.ServiceComponentAdapter.doCreateInstance(ServiceComponentAdapter.kt:36)
	at com.intellij.serviceContainer.BaseComponentAdapter.getInstanceUncached(BaseComponentAdapter.kt:113)
	at com.intellij.serviceContainer.BaseComponentAdapter.getInstance(BaseComponentAdapter.kt:67)
	at com.intellij.serviceContainer.BaseComponentAdapter.getInstance$default(BaseComponentAdapter.kt:60)
	at com.intellij.serviceContainer.ComponentManagerImpl.instantiateService(ComponentManagerImpl.kt:1084)
	at com.intellij.serviceContainer.ComponentManagerImpl$preloadServices$1.invoke(ComponentManagerImpl.kt:1056)
	at com.intellij.serviceContainer.ComponentManagerImpl$preloadServices$
	at java.base/java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(
	at java.base/java.util.concurrent.ForkJoinTask.doExec(
	at java.base/java.util.concurrent.ForkJoinTask.doInvoke(
	at java.base/java.util.concurrent.ForkJoinTask.invokeAll(
	at com.intellij.serviceContainer.ComponentManagerImpl$preloadServices$
	at java.base/java.util.concurrent.CompletableFuture$
	at java.base/java.util.concurrent.CompletableFuture$AsyncRun.exec(
	at java.base/java.util.concurrent.ForkJoinTask.doExec(
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(
	at java.base/java.util.concurrent.ForkJoinPool.scan(
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(
	at java.base/
Caused by: java.lang.NoClassDefFoundError: clojure/lang/Var
	at portal.extensions.intellij.Factory.<clinit>(Unknown Source)
	at java.base/jdk.internal.misc.Unsafe.allocateInstance(Native Method)
	at java.base/java.lang.invoke.DirectMethodHandle.allocateInstance(
	at com.intellij.serviceContainer.ComponentManagerImpl.instantiateClass(ComponentManagerImpl.kt:830)
	... 33 more
Caused by: java.lang.ClassNotFoundException: clojure.lang.Var PluginClassLoader(plugin=PluginDescriptor(name=portal, id=djblue.portal-extension-intellij, descriptorPath=plugin.xml, path=~/Library/Application Support/JetBrains/IntelliJIdea2021.2/plugins/portal-extension-intellij-0.17.0.jar, version=0.17.0, package=null), packagePrefix=null, instanceId=5, state=active)
	at java.base/java.lang.ClassLoader.loadClass(
	... 37 more


That's an interesting stacktrace, not sure why Caused by: java.lang.NoClassDefFoundError: clojure/lang/Var would happen, especially since the clojure jar is part of the distribution zip :thinking_face:


@U066U8JQJ, I can reproduce if I crack open the zip and install lib/portal-extension-intellij-0.17.0.jar. Is that how you are installing the plugin? If so, try installing the .zip archive directly.


ah facepalm that is it


trying to reinstall now


working, its awesome, thank you very much!

โค๏ธ 1

@djblue The README says:

;; optional json support
  cheshire/cheshire {:mvn/version "5.10.0"}
Is that still true, given the adoption of data.json in 0.16.3?


You are correct, I forgot to update the readme after the switch. Although I don't know why I have json listed as an optional dependency since it's a direct dependency. I should delete that entirely. Sorry for the confusion.


I think that was when json was an optional dep and I was using transit as the serialization format. Now json is directly required for portal to function.


The yaml stuff is still optional tho' right?

๐Ÿ‘ 1

Yeah, I never added that as a dep to portal. Although it would work directly in bb since it's included by default.


I used to have it in my :rebl alias but I've a feeling it's in our dep tree at work due to something else...

๐Ÿ’ฏ 1

Transitive deps are always fun ๐Ÿ’ฏ


...hmm, nope, apparently. clojure -Stree -A:dev:everything has nearly 1,000 lines though... ๐Ÿ‘€




Also to be fair my work repo has 451 lines for our deps tree ๐Ÿ˜†


$ clojure -X:deps list :aliases '[:dev :everything]'|wc
    331     662   16314
using the latest CLI.


What is that computing exactly? All the deps for all the aliases?


It's the unique, sorted list of final, selected dependencies.


But it also includes local deps which is a bit misleading in our case...


Is the output lines, words, chars?


So we have 97 local deps. So that's 234 external deps.


When I do clj -Stree -A:dev:test:nrepl:cljs-deps | sort | uniq | wc , I get 382 1221 16027


So we might be "winning" ๐Ÿ˜


Production deps:

$ clojure -Stree -A:dev:everything|sort|uniq|wc
    539    1675   29848
With test/dev deps as well:
$ clojure -Stree -A:dev:everything:test:runner:build:poly|sort|uniq|wc
WARNING: Use of :main-opts with -A is deprecated. Use -M instead.
    783    2477   44747

๐Ÿ˜ฒ 1

(but that's a 120K line code base)

๐Ÿ‘ 1

With Polylith, there's typically no "core" deps. Everything comes it with :dev for the "default" project. :everything is the core deps for our legacy code (that hasn't migrated to Polylith yet).


Even with the new extensions and tooling, portal remains 99.4% clojure. It's kinda nuts all the places clojure can reach!

๐Ÿ’ฏ 2
Ben Sless04:11:38

Question regarding implementation details, does portal keep references to all sent taps or does it eventually release them? Paranoid about eventual memory leaks


> NOTE: portal will keep objects from being garbage collected until they are cleared from the UI.


You are correct to be paranoid ๐Ÿ˜‚

Ben Sless04:11:23

Have you considered adding a default configurable upper limit?


It's partly why I have a hot key bound to clearing the Portal UI ๐Ÿ™‚

โ˜๏ธ 1
metal 1
Ben Sless04:11:37

There's probably some human upper limit which can be reasonably set


The problem is that reasonable is a relative value (wide vs deep references for example). My expectation is that most people are using portal during development where hanging onto values a little longer isn't an issue, especially because clearing values is pretty easy.


I guess my question would be, what are some issues you have experienced with portal?

Ben Sless04:11:24

True. It's just a consideration I have because I want to contribute to cider tap support for the inspector


My REPLs run for weeks and weeks and I don't clear Portal's UI very often TBH. I don't think it's something to really worry about. My default eval hot keys all tap> values into Portal and that's how I work day-in, day-out...


Interesting. Currently with portal, as soon as you add-tap the p/submit function, portal begins collecting values. Portal could easily drop values if no UI is currently connected :thinking_face:


A configurable upper limit could still be useful, perhaps turned off by default


I've seen a few people ask for an emacs integration -- does emacs have a built-in webview these days? I'm assuming not in the terminal version but maybe in some of the platform-integrated versions?


I think there are some native plugins but they aren't the default so not as easy of a target as the other portal extensions.