Hallo, ich bin Peter Russo. Ich werde mein Bestes tun, um den Gouverneur auszuwählen! !! Dieser Artikel ist der 21. Tagesartikel von Emacs Advent Calandar 2016. Übrigens konnte ich kürzlich Java in Emacs schreiben, und diesmal möchte ich darüber sprechen.
Bei der Java-Entwicklung werden häufig IDEs verwendet. Derzeit entweder Eclipse oder IntelliJ? Ist es so
Die IDE ist sicherlich nützlich, hat aber immer noch ein schweres Image. Wenn Sie Emacs als Basishaupt verwenden, können Sie das Bild, das schwer zu sein scheint, nicht zerstreuen Viele Menschen haben den starken Wunsch, Java auch mit Emacs zu entwickeln.
Wie kann man Java in Emacs schreiben?
Um nur einige zu nennen, würden Sie die folgenden Pakete verwenden:
Alle hatten es vor langer Zeit schwer, sie zu installieren, aber jetzt sind sie alle sehr einfach zu testen, damit sie über MELPA installiert werden können.
Jetzt möchte ich sehen, welche Art von Paket jedes Paket ist.
JDEE
Seit der Antike hat Emacs ein riesiges CEDET-basiertes Paket namens JDEE []. Es gibt ziemlich viele Funktionen. Da es bei MELPA registriert wurde, kann gesagt werden, dass die Einführung erheblich geringer ist als zuvor.
Ich habe das Repository kürzlich auf GitHub verschoben und versuche, die Entwicklung fortzusetzen, aber es gibt immer noch viele nicht unterstützte Teile der Java 5-Syntax und höher, z. B. Generika und Erweiterungen für Anweisungen. Da es auf CEDET basiert, wird es auch schwierig sein, es weiter zu warten. Die Build-Tools unterstützen ursprünglich nur Ant, und die Funktionen, die grundsätzlich unterstützt werden, sind ebenfalls alt. (Freiwillige haben möglicherweise verschiedene Funktionen hinzugefügt, aber nicht alle wurden in die Haupteinheit integriert.)
JDEE [] hat alte Funktionen, ist aber zahlreich, so dass es scheint, dass einige Benutzer JDEE [] immer noch individuell angepasst verwenden.
Malabar-mode
[Malabar-Modus] [] unterstützt Maven 3 und Java 6. Es gibt viel Unterstützung für Maven, und dies ist das Paket, das vor einem Jahrzehnt am besten funktioniert hat.
Dies war auch für eine Weile tot und der Betreuer wurde ersetzt, um die Entwicklung fortzusetzen. Infolgedessen wurde die 1.x-Serie bei MELPA registriert, und die Einführung der 1.x-Serie war sehr gering.
Die nächste Version, 2.0, befand sich ebenfalls in der Entwicklung, aber [Malabar-Modus] [] selbst basiert auf CEDET, und 2.0 erfordert die neueste Version von CEDET, sodass die Einführung ziemlich schwierig war. Aus diesem Grund funktioniert es oft nicht stabil und die Entwicklung ist jetzt fast gestoppt.
Viele der CEDET-Parser funktionieren in einigen Fällen nicht. Dies liegt an der Spezifikation, dass CEDET die Leerlaufzeit für die Analyse und das Caching verwendet. Daher wird der Abschluss möglicherweise nicht sofort nach dem Öffnen der Datei korrekt angezeigt, oder der Abschluss kann lange dauern. (Wenn kein Analyseergebnis vorliegt, beginnt die Analyse vor Ort, ist jedoch extrem langsam.)
Eclim
Es war ursprünglich eine Portierung von Emacs zum Schreiben von Java in Vim. Dies ist auch bei MELPA registriert, so dass die Einführung erheblich zurückgegangen ist.
Viele der Funktionen, die im Vergleich zu den ursprünglichen Eclim -Funktionen nicht implementiert wurden, wurden implementiert. Sie können Eclipse-ähnliche Funktionen wie Importoptimierung, Refactoring und Ausführen von Ant- und Maven-Aufgaben sowie deren Abschluss nahtlos verwenden. Da es die Funktionen von Eclipse verwendet, unterstützt es sowohl Java 8 als auch Generika. Da Eclim [] jedoch weiterhin die Funktionen von Eclipse selbst in Emacs verwendet, gibt es möglicherweise einige Teile, die Sie möglicherweise nicht verstehen, ohne vorher über Eclipse Bescheid zu wissen.
Abgesehen davon basiert die Java-Integration in Visual Studio Code auch auf Eclipse (JDT).
ENSIME (ENJIME)
Dies ist auch einer der aktuellen Favoriten. ENSIME [] hat ein starkes Image als Scala-Entwicklungsumgebung, ist jedoch bereits Java-fähig und kann von Emacs profitieren. Eine weitere Stärke ist, dass viele Build-Tools unterstützt werden. Die Ersteinrichtung dauert jedoch einige Zeit. Dies ist keine Geschichte, die Zeit und Mühe kostet. Dies bedeutet, dass Sie nach Ausführung des Befehls zu einem entfernten Geschäft gehen, in dem Sie gelegentlich zum Mittagessen gehen möchten.
Der Java-fähige Teil heißt ENJIME und arbeitet mit Java-Dateien, indem einfach der ensime-Modus aktiviert wird. Die Ergänzung funktioniert sogar mit Lambda usw., und die Operation ist leicht. Obwohl die Grundlagen mit ENSIME [] identisch sind, gibt es derzeit überhaupt keine Dokumentation. Wenn Sie also versuchen, sie nur mit Java zu verwenden, gibt es möglicherweise einige Teile, die Sie nicht verstehen.
Ich selbst bin übrigens vom ENSIME-Ausschuss zur Zusammenarbeit aufgefordert worden.
Wenn Sie sich entscheiden, haben Sie derzeit anscheinend zwei Möglichkeiten: Eclim [] oder ENSIME []. Eclim [] erfordert jedoch Eclipse und ist umständlich einzurichten. Es ähnelt im Wesentlichen dem Ausführen von Eclipse im Hintergrund. Warum also nicht einfach Eclipse verwenden? Ich fühle mich so.
Wenn es um ENJIME geht, sind die Anfangseinstellungen für jedes Build-Tool auch für ENJIME etwas problematisch. Ein weiterer negativer Eindruck ist, dass die Dokumentation zu mangelhaft ist und zu unklar ist, ob sie angepasst werden kann. Es kann ein Nachteil sein, dass die Einrichtung enorm viel Zeit in Anspruch nimmt.
Letztendlich haben Sie also keine andere Wahl, als sie zu entwickeln, es sei denn, Sie haben eine Umgebung, die zu Ihnen passt (Vertreter Russo). Ich habe diesen Bereich nicht von Grund auf neu entwickelt, daher ist es möglicherweise eine gute Idee, ihn auszuprobieren. Ich dachte, ich erhöhte mein Gewicht und begann mit der Entwicklung. Ich bin übrigens neu darin, ein anständiges Elisp zu schreiben.
Lassen Sie uns zunächst klären, was Sie (Vertreter Russo) wollen.
Wenn es so etwas wie das oben geschriebene gibt, scheint es praktisch zu sein. Also, welche Art von Design sollte gemacht werden, um es zu realisieren?
Die erste wichtige Entwurfsrichtlinie ist das Client-Server-Modell, das die Verarbeitung auf dem Client reduziert (diesmal Emacs). Diese Methode ist das Ergebnis des Lernens aus den Fehlern unserer Vorgänger, und auch ENJIME und andere sind solche Methoden. Elisp wird so weit wie möglich mit der Politik entwickelt, sich nur auf den Anzeigeteil zu spezialisieren und kein großes Elisp zu schreiben.
Die Gründe dafür, nicht so viel wie möglich zu schreiben, sind folgende.
Einige Verrückte versuchen es nur mit elisp umzusetzen, was ein Fehler ist. Wenn man nur elisp betrachtet, ist die Verarbeitungsgeschwindigkeit nicht so schlecht. Dies ist jedoch bei einer einfachen Verarbeitung der Fall. Wenn man sich die Sprachspezifikationen und Standardfunktionen von elisp ansieht, ist es schwer zu sagen, dass es reichhaltig ist, um die Verarbeitung zu beschreiben, die Sie realisieren möchten Sie müssen eine angemessene Menge an Code schreiben und so viel Code ausführen. Selbst wenn Sie das Paket als Bibliothek verwenden, wird die Codemenge reduziert, aber die Verarbeitung selbst wird nicht eliminiert. Bei einer moderaten Ausführungsgeschwindigkeit fühlen Sie sich immer noch langsam. Elisp kann auch nicht parallel verarbeitet werden. Jetzt, da Multi-Core zum Mainstream geworden ist, ist dies ein Schmerz. Daher schreibt elisp nicht viel Logik und implementiert die Hauptfunktion auf der Serverseite.
Natürlich hat dieses Verfahren auch seine Nachteile. Der Status des aktuell auf Emacs geschriebenen Puffers ist im Speicher von Emacs und vorhanden Der Punkt ist, dass es auf der Serverseite nicht sichtbar ist. Daher ist es nicht möglich, eine Syntaxanalyse in Echtzeit durchzuführen. Speichern Sie es einmal, spiegeln Sie es in einer Datei wider, analysieren Sie es vom Server und geben Sie das Ergebnis zurück. Sie müssen Schritte wie unternehmen. Es ist auch unklar, ob die gespeicherte Quelldatei eine syntaktisch korrekte Quelldatei ist. In einigen Fällen befindet sich die Quelldatei auf halbem Weg Es kann reflektiert werden. Ich denke, dieser Teil ist ein teilbarer Teil. Dieses Mal analysiert der Server beim Speichern der Datei die Quelldatei und verwaltet den Status der Quelldatei auf dem Server. Wenn die Quelldatei syntaktisch nicht korrekt ist, stoppen Sie die Analyse sofort und geben Sie das Analyseergebnis nicht wieder. Wenn Sie dagegen eine neue Variable hinzufügen, wird diese nur analysiert, wenn Sie sie speichern, und sie wird nicht ergänzt. Diese Methode ist für ENJIME usw. identisch. Es gibt jedoch einige schmerzhafte Teile. Es wird sehr schwierig zu schreiben sein, wenn Sie eine Methodenkette usw. ergänzen. Daher werden wir die Verarbeitung hinzufügen, um diese Probleme zu beheben.
Wenn Sie das Servermodell übernehmen, können Sie den Client frei wählen. Dies bedeutet, dass es mit weniger Aufwand auf Vim, Atom und VSCode portiert werden kann. ENSIME [], Eclim [] sind genau diese Methode, und es ist sehr einfach, verschiedene Editoren zu unterstützen.
In welcher Sprache sollte der Server entwickelt werden? Ich möchte darüber sprechen. Ursprünglich war eine der Motive für die Entwicklung dieses Themas die Veröffentlichung der Gradle Tooling API. Wie der Name schon sagt, können Sie Gradle direkt über die API bedienen. Die Ersteinrichtung von ENSIME [] usw. war ohne die Anwendung des Gradle-Plugins nicht möglich, aber solche Dinge sind nicht mehr erforderlich. Dann gibt es nur eine Antwort und die Entwicklungssprache wird Java sein.
Java 8 VS Clojure
Nun, es gibt viele Sprachen, die auf der JVM für die Entwicklung in Java ausgeführt werden, daher ist es möglicherweise in Ordnung, in ihnen zu schreiben. Ich begann in Clojure zu schreiben, um ein Gefühl für den Prototyp zu bekommen. Da die Startgeschwindigkeit jedoch zu langsam war, begann ich, den Code in Clojure immer dünner zu machen, und schließlich überschritt Java 90%, sodass ich alles in Java neu schrieb.
Die Startoption beginnt auch mit Schwerpunkt auf Startgeschwindigkeit und gelöschtem Speicher.
-XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -XX:+TieredCompilation -Xverify:none -Xms256m -Xmx2G
Für die Entwicklung in Java muss der Klassenpfad festgelegt werden. Viele Projekte verwenden ein vorhandenes Build-Tool. Es ist sehr nett, diese Einstellungen zu lesen und die Klassenpfadeinstellungen und Ausgabeziele nahtlos zu verknüpfen.
Gradle Tooling API
Derzeit werden Tools, die Gradle nicht unterstützen, nicht betrachtet. Gradle verfügt über eine API, mit der Sie eine externe Verbindung zum Gradle Daemon herstellen, Befehle senden und Aufgaben ausführen können. Dieses Mal stellen wir eine Verbindung zu Gradle auf der Serverseite her und integrieren Einstellungen wie Abhängigkeitsauflösung und Klassenpfad. Das Schöne an dieser API ist, dass wenn Sie einen Gradle Wrapper haben, dieser auch den Gradle selbst herunterlädt. Wenn Sie den im Projekt verwendeten Gradle-Versions-Wrapper in das Projekt übernehmen, wird der Hauptteil automatisch heruntergeladen und die Abhängigkeit wird aufgelöst. Usw. kann automatisch erfolgen.
Maven ist immer noch sehr beliebt. Maven kann den Maven auch selbst in den Server einbetten. Ich habe diese Methode tatsächlich ausprobiert, aber ich habe sie aufgegeben, weil einige Funktionen nicht gut injiziert wurden. (Das Innere ist DI, daher bin ich mir nicht sicher, welche Klasse in welchem Jar ist, und ich bin mir nicht sicher über das Initialisierungsverfahren.) In einigen Fällen funktioniert das Plug-In je nach Version von Maven möglicherweise nicht. Daher verwenden wir eine Methode, die intern eine Hybridmethode ausführt, indem sie das POM analysiert und den Befehl mvn ausführt und zusammenarbeitet.
Übrigens kooperieren wir tatsächlich mit dem Projekt und führen Ergänzungen usw. durch, aber wir müssen darüber nachdenken, wie wir die Informationen der Zielklasse erhalten können. Java hat eine Reflection API, ist das in Ordnung?
In Reflection ist von langsamem Feldzugriff und Methodenaufrufen die Rede, aber was ist mit der Aufzählung? Zum Beispiel möchte ich eine Liste von Klassen erstellen, um eine Liste der zu vervollständigenden Klassen anzuzeigen. Guava hat eine Klasse namens ClassPath, die auf Klassenpfadinformationen zugreift, aber das Aufrufen von getAllClasses ist damit lächerlich langsam. Dies ist ein Faktor, der das Laden des Klassenladers verlangsamt. Damit ist eine reibungslose Ergänzung schwierig. Außerdem wird der Klassenlader mit serverseitigen Klassen geladen. Infolgedessen können nicht verwandte Klassen, die nicht im Projekt enthalten sind, als Abschlusskandidaten angezeigt werden.
ASM Reflector
Ich habe meinen eigenen Reflektor hergestellt, um das obige Problem zu lösen. Da es nicht auf dem Klassenladeprogramm platziert ist, kann es als Kandidat für die Fertigstellung innerhalb des Projekts verwendet werden. Wir verfolgen auch den folgenden Ansatz, um das Geschwindigkeitsproblem zu lösen.
Aber wie viele ergänzende Kandidaten gibt es? Abhängig vom JDK gibt es allein im Java-Standard etwa 9000 Klassen. Wenn Sie die Projektabhängigkeit hinzufügen, werden etwa Zehntausende von Klassen indiziert. Um diese großen Zahlen schnell verarbeiten zu können, ist es notwendig, so viel wie möglich zu parallelisieren.
Meghanada
Die Implementierung des oben genannten ist jedoch Meghanada []. Viele sind auf in Java geschriebenen Servern implementiert, aber das Front-Elisp ist auch ziemlich groß. Dieses Client- und Servermodell wurde unter Bezugnahme auf den Ironiemodus erstellt. Gleichzeitig mit dem Öffnen mit [Meghanada-Modus] [] in Emacs wird der Server gestartet, verbunden und Befehle werden mit dem Server auf der Emacs-Seite ausgetauscht.
Die Fertigstellung wird als Backend für das Unternehmen implementiert. Außerdem wird das Prüfsystem für Kompilierungsfehler als Prüfer für Flycheck implementiert. Meghanada [] ist so konzipiert, dass der Emacs-Teil nicht so viel wie möglich selbst verarbeitet. Daher kann es auf die gleiche Weise wie andere Spracheinstellungen verwendet werden.
Abschlussauslöser basieren auf IntelliJ. Grundsätzlich, um Schlüsselwörter usw. aufzunehmen und mit der Fertigstellung zu beginnen Sie müssen keine Taste drücken, um den Vorgang abzuschließen.
Meghanada [] berücksichtigt auch die einfache Installation. Die Server-JAR-Datei wird in ein fettes JAR umgewandelt und in bintray hochgeladen. Wenn auf Elisp-Seite lokal kein Server-Jar vorhanden ist, wird es automatisch von bintray heruntergeladen. Alles was Sie tun müssen, ist Emacs neu zu starten und es klingt einsatzbereit. Sie müssen es nicht wie Ironie kompilieren.
In einigen Fällen kann es zu einer starken Verarbeitung kommen. In Erwartung dessen sind viele darauf ausgelegt, asynchron zu kommunizieren. Das Einfrieren im Editor ist ein schwerwiegendes Problem. Die Abschlussverarbeitung verwendet die Firma. Das Unternehmen verfügt über eine asynchrone API, mit der das Einfrieren verhindert wird.
Meghanada [] fügt zwei Verbindungen mit dem Server ein. Eine dient zum Senden und Empfangen von Befehlen und eine zum Streamen. Stream ist eine Funktion zum Empfangen von Ausgaben in Echtzeit. Dies wird insbesondere verwendet, um Konsolenprotokolle wie das Ausführen und Erstellen von JUnit zu überprüfen.
Um ehrlich zu sein, denke ich nicht, dass es ohne einen Stream möglich wäre, aber der von VSCode verwendete LSP hat keinen Stream.
Ich stellte kurz Meghanada [] vor. Ich habe dieses Jahr angefangen, dieses Projekt zu schreiben und wünschte, ich könnte es innerhalb des Jahres veröffentlichen. Ich habe es mehrmals umgeschrieben, bevor es veröffentlicht wurde, aber ich konnte die erste Ausgabe um den Oktober herum veröffentlichen.
Gegenwärtig wurde der Teil der Quellanalyse unabhängig implementiert, aber dieser Teil wird mit einer internen Compiler-API wie ENSIME [] neu geschrieben. Ich denke, dies wird es uns ermöglichen, Lambda und Methodenreferenzen vollständig zu unterstützen.
Recommended Posts