From 342d8831a3338fbcca779fd43328b57783fb3fb4 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Sat, 28 Jan 2023 13:50:24 +0100 Subject: [PATCH 01/21] version update --- CHANGELOG.md | 8 +++++++- build.gradle.kts | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5041b01..4ce47a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ -## 0.3.0 +## 0.4.0 + +### Added + +### Fixes + +## 0.3.0 - 230108 ### Added diff --git a/build.gradle.kts b/build.gradle.kts index b79703c..e30ec34 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "com.en_circle.slt" -version = "0.3.0" +version = "0.4.0" repositories { mavenCentral() From ee21d8aaea56ebb6e9856779e738db059fbbeb3b Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Mon, 30 Jan 2023 12:52:46 +0100 Subject: [PATCH 02/21] refactoring to actual library and files --- build.gradle.kts | 28 +++ .../com/en_circle/slt/plugin/SltLibrary.java | 43 ++++ .../slt/plugin/environment/LispInterpret.java | 15 ++ .../environment/SltSBCLEnvironment.java | 8 +- .../slt/templates/SltScriptTemplate.java | 16 -- src/main/lisp/load.lisp | 6 + src/main/lisp/slt/slt-sbcl.lisp | 4 + src/main/lisp/slt/slt.lisp | 90 +++++++ src/main/lisp/swank/swank-backend.lisp | 2 + src/main/lisp/swank/swank-sbcl.lisp | 15 ++ src/main/lisp/swank/swank.lisp | 108 +++++++++ .../resources/templates/en_US/initscript.cl | 4 + src/main/resources/templates/en_US/slt.cl | 222 ------------------ .../tests/indentation/IndentationTests.java | 14 +- 14 files changed, 325 insertions(+), 250 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/SltLibrary.java create mode 100644 src/main/java/com/en_circle/slt/plugin/environment/LispInterpret.java delete mode 100644 src/main/java/com/en_circle/slt/templates/SltScriptTemplate.java create mode 100644 src/main/lisp/load.lisp create mode 100644 src/main/lisp/slt/slt-sbcl.lisp create mode 100644 src/main/lisp/slt/slt.lisp create mode 100644 src/main/lisp/swank/swank-backend.lisp create mode 100644 src/main/lisp/swank/swank-sbcl.lisp create mode 100644 src/main/lisp/swank/swank.lisp delete mode 100644 src/main/resources/templates/en_US/slt.cl diff --git a/build.gradle.kts b/build.gradle.kts index e30ec34..4d0b3e6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,6 +14,7 @@ dependencies { implementation("org.awaitility:awaitility:4.2.0") implementation("org.watertemplate:watertemplate-engine:1.2.2") implementation("com.google.guava:guava:31.1-jre") + implementation("org.rauschig:jarchivelib:1.2.0") testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1") @@ -42,7 +43,33 @@ intellij { /* Plugin Dependencies */)) } + tasks { + val sltZip = task("sltZip", Zip::class) { + from("src/main/lisp") + archiveFileName.set("slt.zip") + destinationDirectory.set(File("build/resources/main")) + include("**/*.*") + + doFirst { + println("Zipping SLT to " + destinationDirectory.get()) + } + eachFile{ + println("Zipping $this") + } + doLast { + println("Done Zipping SLT") + } + + outputs.upToDateWhen { + false + } + } + sltZip.mustRunAfter(processResources) + jar { + dependsOn(sltZip) + } + // Set the JVM compatibility versions withType { sourceCompatibility = "17" @@ -68,3 +95,4 @@ tasks { token.set(System.getenv("PUBLISH_TOKEN")) } } + diff --git a/src/main/java/com/en_circle/slt/plugin/SltLibrary.java b/src/main/java/com/en_circle/slt/plugin/SltLibrary.java new file mode 100644 index 0000000..b0f6725 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/SltLibrary.java @@ -0,0 +1,43 @@ +package com.en_circle.slt.plugin; + +import com.en_circle.slt.tools.PluginPath; +import org.apache.commons.io.FileUtils; +import org.rauschig.jarchivelib.ArchiveFormat; +import org.rauschig.jarchivelib.Archiver; +import org.rauschig.jarchivelib.ArchiverFactory; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +public class SltLibrary { + + private static boolean loaded = false; + + public static synchronized File getLibraryInitFile() throws IOException { + File pluginPath = PluginPath.getPluginFolder(); + File sltPath = new File(pluginPath, "slt"); + if (!sltPath.exists()) { + sltPath.mkdirs(); + loaded = false; + } else if (!loaded) { + FileUtils.deleteDirectory(sltPath); + sltPath.mkdirs(); + } + + if (!loaded) { + extractAndCopy(sltPath); + } + + return new File(sltPath, "load.lisp"); + } + + private static void extractAndCopy(File sltPath) throws IOException { + InputStream is = SltLibrary.class.getResourceAsStream("/slt.zip"); + assert is != null; + + Archiver archiver = ArchiverFactory.createArchiver(ArchiveFormat.ZIP); + archiver.extract(is, sltPath); + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/environment/LispInterpret.java b/src/main/java/com/en_circle/slt/plugin/environment/LispInterpret.java new file mode 100644 index 0000000..73d63dc --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/environment/LispInterpret.java @@ -0,0 +1,15 @@ +package com.en_circle.slt.plugin.environment; + +public enum LispInterpret { + + SBCL(":sbcl") + + ; + + public final String symbolName; + + LispInterpret(String symbolName) { + this.symbolName = symbolName; + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java b/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java index cd9dddc..3b1c8f5 100644 --- a/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java @@ -1,8 +1,8 @@ package com.en_circle.slt.plugin.environment; +import com.en_circle.slt.plugin.SltLibrary; import com.en_circle.slt.plugin.environment.SltProcessStreamGobbler.ProcessInitializationWaiter; import com.en_circle.slt.plugin.environment.SltProcessStreamGobbler.WaitForOccurrence; -import com.en_circle.slt.templates.SltScriptTemplate; import com.en_circle.slt.tools.PluginPath; import com.intellij.openapi.util.io.FileUtil; import org.apache.commons.io.FileUtils; @@ -43,10 +43,7 @@ protected Object prepareProcessEnvironment(SltLispEnvironmentProcessConfiguratio File tempDir = FileUtil.createTempDirectory(PluginPath.getPluginFolder(), "SLTinit", ""); - e.sltCore = new File(tempDir, "slt.cl"); - e.sltCore.deleteOnExit(); - String sltScriptTemplate = new SltScriptTemplate().render(); - FileUtils.write(e.sltCore, sltScriptTemplate, StandardCharsets.UTF_8); + e.sltCore = SltLibrary.getLibraryInitFile(); e.serverStartSetup = new File(tempDir, "startServer.cl"); e.serverStartSetup.deleteOnExit(); @@ -156,6 +153,7 @@ public SBCLInitScriptTemplate(SltSBCLEnvironmentConfiguration configuration, Str add("port", "" + port); add("cwd", cwd); add("sbclcorefile", sltCoreScript); + add("interpret", LispInterpret.SBCL.symbolName); } @Override diff --git a/src/main/java/com/en_circle/slt/templates/SltScriptTemplate.java b/src/main/java/com/en_circle/slt/templates/SltScriptTemplate.java deleted file mode 100644 index e972ea3..0000000 --- a/src/main/java/com/en_circle/slt/templates/SltScriptTemplate.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.en_circle.slt.templates; - -import org.watertemplate.Template; - -public class SltScriptTemplate extends Template { - - public SltScriptTemplate() { - - } - - @Override - protected String getFilePath() { - return "slt.cl"; - } - -} diff --git a/src/main/lisp/load.lisp b/src/main/lisp/load.lisp new file mode 100644 index 0000000..74c7fc0 --- /dev/null +++ b/src/main/lisp/load.lisp @@ -0,0 +1,6 @@ +(format T "SLT Interpret ~S~%" +slt-interpret+) + +(load (merge-pathnames "swank/swank.lisp" *load-truename*)) +(load (merge-pathnames "slt/slt.lisp" *load-truename*)) + +(in-package :cl-user) \ No newline at end of file diff --git a/src/main/lisp/slt/slt-sbcl.lisp b/src/main/lisp/slt/slt-sbcl.lisp new file mode 100644 index 0000000..58d2443 --- /dev/null +++ b/src/main/lisp/slt/slt-sbcl.lisp @@ -0,0 +1,4 @@ +(in-package :slt-core) + +(defun specialp (test-sym) + (eq (sb-cltl2:variable-information test-sym) :special)) \ No newline at end of file diff --git a/src/main/lisp/slt/slt.lisp b/src/main/lisp/slt/slt.lisp new file mode 100644 index 0000000..4fcd590 --- /dev/null +++ b/src/main/lisp/slt/slt.lisp @@ -0,0 +1,90 @@ +(defpackage :slt-core + (:use :cl :swank) + (:export analyze-symbol analyze-symbols read-fix-packages list-package-names + initialize-or-get-debug-context debug-context debug-frame-variable register-variable + )) + +(when (eq +slt-interpret+ :sbcl) + (load (merge-pathnames "slt-sbcl.lisp" *load-truename*))) + +(in-package :slt-core) + +(defun analyze-symbol (test-sym) + (cons test-sym + (let ((*standard-output* (make-string-output-stream)) + (swank::*source-snippet-size* 0)) + (cond + ((not test-sym) (list NIL NIL NIL)) + ((and (fboundp test-sym) + (typep (symbol-function test-sym) 'generic-function)) + (progn + (describe test-sym) + (list :method (get-output-stream-string *standard-output*) + (swank:find-source-location (symbol-function test-sym))))) + ((special-operator-p test-sym) (list :special-form NIL NIL)) + ((macro-function test-sym) (progn + (describe test-sym) + (list + :macro + (get-output-stream-string *standard-output*) + (swank:find-source-location (symbol-function test-sym))))) + ((fboundp test-sym) (progn + (describe test-sym) + (list + :function + (get-output-stream-string *standard-output*) + (swank:find-source-location (symbol-function test-sym))))) + ((specialp test-sym) (progn + (describe test-sym) + (list :special (get-output-stream-string *standard-output*) NIL))) + ((keywordp test-sym) (progn + (describe test-sym) + (list :keyword (get-output-stream-string *standard-output*) NIL))) + ((constantp test-sym) (progn + (describe test-sym) + (list :constant (get-output-stream-string *standard-output*) NIL))) + ((find-class test-sym NIL) (progn + (describe test-sym) + (list :class (get-output-stream-string *standard-output*) + (swank:find-source-location (find-class test-sym))))) + (T (list NIL NIL NIL)))))) + +(defun analyze-symbols (symbols) + (map 'list #'analyze-symbol symbols)) + +(defun reader-recover (c) + (declare (ignorable c)) + (let ((restart (find-restart 'eclector.reader:recover))) + (when restart + (invoke-restart restart)))) + +(defun reader-recover (c) + (declare (ignorable c)) + (let ((restart (find-restart 'eclector.reader:recover))) + (when restart + (invoke-restart restart)))) + +(defun reader-user-anyway (c) + (declare (ignorable c)) + (let ((restart (find-restart 'eclector.reader::use-anyway))) + (when restart + (invoke-restart restart)))) + +(defun read-fix-packages (str) + (handler-bind + ((ECLECTOR.READER:SYMBOL-NAME-MUST-NOT-END-WITH-PACKAGE-MARKER + #'reader-recover) + (ECLECTOR.READER:SYMBOL-IS-NOT-EXTERNAL + #'reader-user-anyway) + (ECLECTOR.READER:SYMBOL-DOES-NOT-EXIST + #'reader-recover) + (ECLECTOR.READER:PACKAGE-DOES-NOT-EXIST + #'reader-recover) + (error (lambda (c) + (format *error-output* "general error: ~S ~%" c)))) + (eclector.reader:read-from-string str))) + +(defun list-package-names () + (let ((packages (list-all-packages))) + (loop for package in packages collect + (package-name package)))) \ No newline at end of file diff --git a/src/main/lisp/swank/swank-backend.lisp b/src/main/lisp/swank/swank-backend.lisp new file mode 100644 index 0000000..4ee393a --- /dev/null +++ b/src/main/lisp/swank/swank-backend.lisp @@ -0,0 +1,2 @@ +(in-package swank/backend) + diff --git a/src/main/lisp/swank/swank-sbcl.lisp b/src/main/lisp/swank/swank-sbcl.lisp new file mode 100644 index 0000000..b13025c --- /dev/null +++ b/src/main/lisp/swank/swank-sbcl.lisp @@ -0,0 +1,15 @@ +(in-package sb-debug) + +(export 'frame-code-location) +(export 'frame-call) +(export 'ensure-printable-object) +(export 'code-location-source-form) + +(in-package :swank) + +(defun print-frame-call-place (frame) + (multiple-value-bind (name args info) + (SB-DEBUG:frame-call frame) + (declare (ignore args info)) + (let ((name (SB-DEBUG:ensure-printable-object name))) + name))) diff --git a/src/main/lisp/swank/swank.lisp b/src/main/lisp/swank/swank.lisp new file mode 100644 index 0000000..4c9f54e --- /dev/null +++ b/src/main/lisp/swank/swank.lisp @@ -0,0 +1,108 @@ +(load (merge-pathnames "swank-backend.lisp" *load-truename*)) +(when (eq +slt-interpret+ :sbcl) + (load (merge-pathnames "swank-sbcl.lisp" *load-truename*))) + +(in-package :swank) + +(export 'find-source-location) + +(defslimefun slt-eval (string) + (let ((*echo-area-prefix* "")) + (with-buffer-syntax () + (with-retry-restart (:msg "Retry SLIME interactive evaluation request.") + (let ((values (multiple-value-list (eval (from-string string))))) + (finish-output) + (format-values-for-echo-area values)))))) + +(defslimefun invoke-nth-restart-slt (sldb-level n args rest) + (when (= sldb-level *sldb-level*) + (let ((restart (nth-restart n)) + (parsed-args (from-string args)) + (parsed-rest (from-string rest))) + (when restart + (if (or parsed-args parsed-rest) + (apply #'invoke-restart (concatenate 'list (list restart) parsed-args parsed-rest)) + (invoke-restart restart)))))) + +(defun format-restarts-for-emacs () + "Return a list of restarts for *swank-debugger-condition* in a +format suitable for Emacs." + (let ((*print-right-margin* most-positive-fixnum)) + (loop for restart in *sldb-restarts* collect + (list (format nil "~:[~;*~]~a" + (eq restart *sldb-quit-restart*) + (restart-name restart)) + (with-output-to-string (stream) + (without-printing-errors (:object restart + :stream stream + :msg "<>") + (princ restart stream))) + (swank-backend:arglist (slot-value restart 'function)))))) + +(defslimefun backtrace (start end) + (loop for frame in (compute-backtrace start end) + for i from start collect + (list i (frame-to-string frame) + (format NIL "~S" (print-frame-call-place frame)) + (frame-source-location i) + (let ((pkg (frame-package i))) + (cond + (pkg (package-name pkg)) + (T NIL)))))) + +(defslimefun compile-string-region-slt (string buffer offset filename package) + (with-buffer-syntax () + (collect-notes + (lambda () + (let ((*compile-print* t) (*compile-verbose* nil) (*package* (find-package package))) + (swank-compile-string string + :buffer buffer + :position offset + :filename filename)))))) + +(defun get-all-symbols-with-prefix (prefix) + (let ((all (get-all-symbols))) + (loop for data-pair in all + when (prefix-match-p prefix (first data-pair)) + collect data-pair))) + +(defun get-all-symbols () + (let ((data '())) + (do-symbols (s) + (push (list (unparse-symbol s) s (symbol-package s)) data)) + (remove-duplicates data :key (lambda (e) (second e))))) + +(defun find-reference-class-filter (symbol package) + (find-class symbol NIL)) + +(defun get-reference-prefix (prefix type) + (let ((apply-func (cond + ((eq type :class) #'find-reference-class-filter) + (T (lambda (symbol package) T))))) + (let ((filtered-symbols (get-all-symbols-with-prefix prefix)) + (*source-snippet-size* 0)) + (loop for data-pair in filtered-symbols + when (funcall apply-func (second data-pair) (third data-pair)) + collect + (let* ((symbol (second data-pair)) + (str (first data-pair)) + (package (third data-pair)) + (strpackage (format NIL "~S" package))) + (cond + ((not symbol) (list str strpackage NIL NIL)) + ((macro-function symbol) (list str strpackage :macro (find-source-location (symbol-function symbol)))) + ((and (fboundp symbol) + (typep (symbol-function symbol) 'generic-function)) + (list str strpackage :method (find-source-location (symbol-function symbol)))) + ((fboundp symbol) (list str strpackage :function (find-source-location (symbol-function symbol)))) + ((find-class symbol NIL) (list str strpackage :class (find-source-location (find-class symbol)))) + (T (list str strpackage NIL NIL)))))))) + +(defslimefun find-reference-prefix (prefix type) + (let ((references (get-reference-prefix prefix type))) + (when references + (sort references #'string< :key (lambda (x) (first x)))))) + +(export 'slt-eval) +(export 'compile-string-region-slt) +(export 'find-reference-prefix) \ No newline at end of file diff --git a/src/main/resources/templates/en_US/initscript.cl b/src/main/resources/templates/en_US/initscript.cl index 2489a39..b99edc0 100644 --- a/src/main/resources/templates/en_US/initscript.cl +++ b/src/main/resources/templates/en_US/initscript.cl @@ -1,3 +1,7 @@ +(in-package :cl) +(defconstant +slt-interpret+ ~interpret~ + "Defines current slt interpret. For SBCL the value is :sbcl") + (load "~qlpath~") (ql:quickload :swank) (ql:quickload :eclector) diff --git a/src/main/resources/templates/en_US/slt.cl b/src/main/resources/templates/en_US/slt.cl deleted file mode 100644 index 1dfd843..0000000 --- a/src/main/resources/templates/en_US/slt.cl +++ /dev/null @@ -1,222 +0,0 @@ -; TODO: swank:defslimefunction - -(defpackage :slt-core - (:use :cl :swank) - (:export analyze-symbol analyze-symbols read-fix-packages list-package-names - initialize-or-get-debug-context debug-context debug-frame-variable register-variable - )) - -; swank/slime overrides - -(in-package sb-debug) - -(export 'frame-code-location) -(export 'frame-call) -(export 'ensure-printable-object) -(export 'code-location-source-form) - -(in-package swank/backend) - -(in-package :swank) - -(export 'find-source-location) - -(defslimefun slt-eval (string) - (let ((*echo-area-prefix* "")) - (with-buffer-syntax () - (with-retry-restart (:msg "Retry SLIME interactive evaluation request.") - (let ((values (multiple-value-list (eval (from-string string))))) - (finish-output) - (format-values-for-echo-area values)))))) - -(defslimefun invoke-nth-restart-slt (sldb-level n args rest) - (when (= sldb-level *sldb-level*) - (let ((restart (nth-restart n)) - (parsed-args (from-string args)) - (parsed-rest (from-string rest))) - (when restart - (if (or parsed-args parsed-rest) - (apply #'invoke-restart (concatenate 'list (list restart) parsed-args parsed-rest)) - (invoke-restart restart)))))) - -(defun format-restarts-for-emacs () - "Return a list of restarts for *swank-debugger-condition* in a -format suitable for Emacs." - (let ((*print-right-margin* most-positive-fixnum)) - (loop for restart in *sldb-restarts* collect - (list (format nil "~:[~;*~]~a" - (eq restart *sldb-quit-restart*) - (restart-name restart)) - (with-output-to-string (stream) - (without-printing-errors (:object restart - :stream stream - :msg "<>") - (princ restart stream))) - (swank-backend:arglist (slot-value restart 'function)))))) - -(defun print-frame-call-place (frame) - (multiple-value-bind (name args info) - (SB-DEBUG:frame-call frame) - (declare (ignore args info)) - (let ((name (SB-DEBUG:ensure-printable-object name))) - name))) - -(defslimefun backtrace (start end) - (loop for frame in (compute-backtrace start end) - for i from start collect - (list i (frame-to-string frame) - (format NIL "~S" (print-frame-call-place frame)) - (frame-source-location i) - (let ((pkg (frame-package i))) - (cond - (pkg (package-name pkg)) - (T NIL)))))) - -(defslimefun compile-string-region-slt (string buffer offset filename package) - (with-buffer-syntax () - (collect-notes - (lambda () - (let ((*compile-print* t) (*compile-verbose* nil) (*package* (find-package package))) - (swank-compile-string string - :buffer buffer - :position offset - :filename filename)))))) - -(in-package swank) - -(defun get-all-symbols-with-prefix (prefix) - (let ((all (get-all-symbols))) - (loop for data-pair in all - when (prefix-match-p prefix (first data-pair)) - collect data-pair))) - -(defun get-all-symbols () - (let ((data '())) - (do-symbols (s) - (push (list (unparse-symbol s) s (symbol-package s)) data)) - (remove-duplicates data :key (lambda (e) (second e))))) - -(defun find-reference-class-filter (symbol package) - (find-class symbol NIL)) - -(defun get-reference-prefix (prefix type) - (let ((apply-func (cond - ((eq type :class) #'find-reference-class-filter) - (T (lambda (symbol package) T))))) - (let ((filtered-symbols (get-all-symbols-with-prefix prefix)) - (*source-snippet-size* 0)) - (loop for data-pair in filtered-symbols - when (funcall apply-func (second data-pair) (third data-pair)) - collect - (let* ((symbol (second data-pair)) - (str (first data-pair)) - (package (third data-pair)) - (strpackage (format NIL "~S" package))) - (cond - ((not symbol) (list str strpackage NIL NIL)) - ((macro-function symbol) (list str strpackage :macro (swank:find-source-location (symbol-function symbol)))) - ((and (fboundp symbol) - (typep (symbol-function symbol) 'generic-function)) - (list str strpackage :method (swank:find-source-location (symbol-function symbol)))) - ((fboundp symbol) (list str strpackage :function (swank:find-source-location (symbol-function symbol)))) - ((find-class symbol NIL) (list str strpackage :class (swank:find-source-location (find-class symbol)))) - (T (list str strpackage NIL NIL)))))))) - -(defslimefun find-reference-prefix (prefix type) - (let ((references (get-reference-prefix prefix type))) - (when references - (sort references #'string< :key (lambda (x) (first x)))))) - -(export 'slt-eval) -(export 'compile-string-region-slt) - -(in-package swank/sbcl) - -(in-package swank/source-file-cache) - -(in-package :slt-core) - -(defun specialp (test-sym) - (eq (sb-cltl2:variable-information test-sym) :special)) - -(defun analyze-symbol (test-sym) - (cons test-sym - (let ((*standard-output* (make-string-output-stream)) - (*source-snippet-size* 0)) - (cond - ((not test-sym) (list NIL NIL NIL)) - ((and (fboundp test-sym) - (typep (symbol-function test-sym) 'generic-function)) - (progn - (describe test-sym) - (list :method (get-output-stream-string *standard-output*) - (swank:find-source-location (symbol-function test-sym))))) - ((special-operator-p test-sym) (list :special-form NIL NIL)) - ((macro-function test-sym) (progn - (describe test-sym) - (list - :macro - (get-output-stream-string *standard-output*) - (swank:find-source-location (symbol-function test-sym))))) - ((fboundp test-sym) (progn - (describe test-sym) - (list - :function - (get-output-stream-string *standard-output*) - (swank:find-source-location (symbol-function test-sym))))) - ((specialp test-sym) (progn - (describe test-sym) - (list :special (get-output-stream-string *standard-output*) NIL))) - ((keywordp test-sym) (progn - (describe test-sym) - (list :keyword (get-output-stream-string *standard-output*) NIL))) - ((constantp test-sym) (progn - (describe test-sym) - (list :constant (get-output-stream-string *standard-output*) NIL))) - ((find-class test-sym NIL) (progn - (describe test-sym) - (list :class (get-output-stream-string *standard-output*) - (swank:find-source-location (find-class test-sym))))) - (T (list NIL NIL NIL)))))) - -(defun analyze-symbols (symbols) - (map 'list #'analyze-symbol symbols)) - -(defun reader-recover (c) - (declare (ignorable c)) - (let ((restart (find-restart 'eclector.reader:recover))) - (when restart - (invoke-restart restart)))) - -(defun reader-recover (c) - (declare (ignorable c)) - (let ((restart (find-restart 'eclector.reader:recover))) - (when restart - (invoke-restart restart)))) - -(defun reader-user-anyway (c) - (declare (ignorable c)) - (let ((restart (find-restart 'eclector.reader::use-anyway))) - (when restart - (invoke-restart restart)))) - -(defun read-fix-packages (str) - (handler-bind - ((ECLECTOR.READER:SYMBOL-NAME-MUST-NOT-END-WITH-PACKAGE-MARKER - #'reader-recover) - (ECLECTOR.READER:SYMBOL-IS-NOT-EXTERNAL - #'reader-user-anyway) - (ECLECTOR.READER:SYMBOL-DOES-NOT-EXIST - #'reader-recover) - (ECLECTOR.READER:PACKAGE-DOES-NOT-EXIST - #'reader-recover) - (error (lambda (c) - (format *error-output* "general error: ~S ~%" c)))) - (eclector.reader:read-from-string str))) - -(defun list-package-names () - (let ((packages (list-all-packages))) - (loop for package in packages collect - (package-name package)))) - -(in-package :cl-user) \ No newline at end of file diff --git a/src/test/java/com/en_circle/slt/tests/indentation/IndentationTests.java b/src/test/java/com/en_circle/slt/tests/indentation/IndentationTests.java index fd6e5b7..ee11ea6 100644 --- a/src/test/java/com/en_circle/slt/tests/indentation/IndentationTests.java +++ b/src/test/java/com/en_circle/slt/tests/indentation/IndentationTests.java @@ -35,9 +35,9 @@ public void testFormsBlock() throws Exception { public void testFormsCase() throws Exception { assertEquals(4, container.testIndentCL("(case XXX)")); assertEquals(2, container.testIndentCL("(case blah XXX)")); - assertEquals(3, container.testIndentCL("(case blah (XXX))")); - assertEquals(3, container.testIndentCL("(case blah (wot) (XXX))")); - assertEquals(3, container.testIndentCL("(case blah (foo XXX))")); + assertEquals(12, container.testIndentCL("(case blah (XXX))")); + assertEquals(18, container.testIndentCL("(case blah (wot) (XXX))")); + assertEquals(12, container.testIndentCL("(case blah (foo XXX))")); assertEquals(3, container.testIndentCL(""" (case blah @@ -67,11 +67,11 @@ public void testFormsCatch() throws Exception { @Test public void testFormsCond() throws Exception { assertEquals(2, container.testIndentCL("(cond XXX)")); - assertEquals(4, container.testIndentCL("(cond (XXX))")); - assertEquals(4, container.testIndentCL("(cond (foo XXX))")); + assertEquals(8, container.testIndentCL("(cond (XXX))")); + assertEquals(10, container.testIndentCL("(cond (foo XXX))")); assertEquals(7+4, container.testIndentCL("(cond ((= 1 XXX)))")); - assertEquals(4, container.testIndentCL("(cond (foo bar) (XXX))")); - assertEquals(4, container.testIndentCL("(cond (foo bar) (baz XXX))")); + assertEquals(18, container.testIndentCL("(cond (foo bar) (XXX))")); + assertEquals(20, container.testIndentCL("(cond (foo bar) (baz XXX))")); } @Test From 98724a00c412feb2bfd9b2a7699c022003645df9 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Mon, 30 Jan 2023 12:52:46 +0100 Subject: [PATCH 03/21] refactoring to actual library and files --- build.gradle.kts | 28 +++ .../com/en_circle/slt/plugin/SltLibrary.java | 43 ++++ .../slt/plugin/environment/LispInterpret.java | 15 ++ .../environment/SltSBCLEnvironment.java | 8 +- .../slt/templates/SltScriptTemplate.java | 16 -- src/main/lisp/load.lisp | 6 + src/main/lisp/slt/slt-sbcl.lisp | 4 + src/main/lisp/slt/slt.lisp | 90 +++++++ src/main/lisp/swank/swank-backend.lisp | 2 + src/main/lisp/swank/swank-sbcl.lisp | 15 ++ src/main/lisp/swank/swank.lisp | 108 +++++++++ .../resources/templates/en_US/initscript.cl | 4 + src/main/resources/templates/en_US/slt.cl | 222 ------------------ .../tests/indentation/IndentationTests.java | 14 +- 14 files changed, 325 insertions(+), 250 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/SltLibrary.java create mode 100644 src/main/java/com/en_circle/slt/plugin/environment/LispInterpret.java delete mode 100644 src/main/java/com/en_circle/slt/templates/SltScriptTemplate.java create mode 100644 src/main/lisp/load.lisp create mode 100644 src/main/lisp/slt/slt-sbcl.lisp create mode 100644 src/main/lisp/slt/slt.lisp create mode 100644 src/main/lisp/swank/swank-backend.lisp create mode 100644 src/main/lisp/swank/swank-sbcl.lisp create mode 100644 src/main/lisp/swank/swank.lisp delete mode 100644 src/main/resources/templates/en_US/slt.cl diff --git a/build.gradle.kts b/build.gradle.kts index b79703c..5813ec5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,6 +14,7 @@ dependencies { implementation("org.awaitility:awaitility:4.2.0") implementation("org.watertemplate:watertemplate-engine:1.2.2") implementation("com.google.guava:guava:31.1-jre") + implementation("org.rauschig:jarchivelib:1.2.0") testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1") @@ -42,7 +43,33 @@ intellij { /* Plugin Dependencies */)) } + tasks { + val sltZip = task("sltZip", Zip::class) { + from("src/main/lisp") + archiveFileName.set("slt.zip") + destinationDirectory.set(File("build/resources/main")) + include("**/*.*") + + doFirst { + println("Zipping SLT to " + destinationDirectory.get()) + } + eachFile{ + println("Zipping $this") + } + doLast { + println("Done Zipping SLT") + } + + outputs.upToDateWhen { + false + } + } + sltZip.mustRunAfter(processResources) + jar { + dependsOn(sltZip) + } + // Set the JVM compatibility versions withType { sourceCompatibility = "17" @@ -68,3 +95,4 @@ tasks { token.set(System.getenv("PUBLISH_TOKEN")) } } + diff --git a/src/main/java/com/en_circle/slt/plugin/SltLibrary.java b/src/main/java/com/en_circle/slt/plugin/SltLibrary.java new file mode 100644 index 0000000..b0f6725 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/SltLibrary.java @@ -0,0 +1,43 @@ +package com.en_circle.slt.plugin; + +import com.en_circle.slt.tools.PluginPath; +import org.apache.commons.io.FileUtils; +import org.rauschig.jarchivelib.ArchiveFormat; +import org.rauschig.jarchivelib.Archiver; +import org.rauschig.jarchivelib.ArchiverFactory; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +public class SltLibrary { + + private static boolean loaded = false; + + public static synchronized File getLibraryInitFile() throws IOException { + File pluginPath = PluginPath.getPluginFolder(); + File sltPath = new File(pluginPath, "slt"); + if (!sltPath.exists()) { + sltPath.mkdirs(); + loaded = false; + } else if (!loaded) { + FileUtils.deleteDirectory(sltPath); + sltPath.mkdirs(); + } + + if (!loaded) { + extractAndCopy(sltPath); + } + + return new File(sltPath, "load.lisp"); + } + + private static void extractAndCopy(File sltPath) throws IOException { + InputStream is = SltLibrary.class.getResourceAsStream("/slt.zip"); + assert is != null; + + Archiver archiver = ArchiverFactory.createArchiver(ArchiveFormat.ZIP); + archiver.extract(is, sltPath); + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/environment/LispInterpret.java b/src/main/java/com/en_circle/slt/plugin/environment/LispInterpret.java new file mode 100644 index 0000000..73d63dc --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/environment/LispInterpret.java @@ -0,0 +1,15 @@ +package com.en_circle.slt.plugin.environment; + +public enum LispInterpret { + + SBCL(":sbcl") + + ; + + public final String symbolName; + + LispInterpret(String symbolName) { + this.symbolName = symbolName; + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java b/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java index cd9dddc..3b1c8f5 100644 --- a/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java @@ -1,8 +1,8 @@ package com.en_circle.slt.plugin.environment; +import com.en_circle.slt.plugin.SltLibrary; import com.en_circle.slt.plugin.environment.SltProcessStreamGobbler.ProcessInitializationWaiter; import com.en_circle.slt.plugin.environment.SltProcessStreamGobbler.WaitForOccurrence; -import com.en_circle.slt.templates.SltScriptTemplate; import com.en_circle.slt.tools.PluginPath; import com.intellij.openapi.util.io.FileUtil; import org.apache.commons.io.FileUtils; @@ -43,10 +43,7 @@ protected Object prepareProcessEnvironment(SltLispEnvironmentProcessConfiguratio File tempDir = FileUtil.createTempDirectory(PluginPath.getPluginFolder(), "SLTinit", ""); - e.sltCore = new File(tempDir, "slt.cl"); - e.sltCore.deleteOnExit(); - String sltScriptTemplate = new SltScriptTemplate().render(); - FileUtils.write(e.sltCore, sltScriptTemplate, StandardCharsets.UTF_8); + e.sltCore = SltLibrary.getLibraryInitFile(); e.serverStartSetup = new File(tempDir, "startServer.cl"); e.serverStartSetup.deleteOnExit(); @@ -156,6 +153,7 @@ public SBCLInitScriptTemplate(SltSBCLEnvironmentConfiguration configuration, Str add("port", "" + port); add("cwd", cwd); add("sbclcorefile", sltCoreScript); + add("interpret", LispInterpret.SBCL.symbolName); } @Override diff --git a/src/main/java/com/en_circle/slt/templates/SltScriptTemplate.java b/src/main/java/com/en_circle/slt/templates/SltScriptTemplate.java deleted file mode 100644 index e972ea3..0000000 --- a/src/main/java/com/en_circle/slt/templates/SltScriptTemplate.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.en_circle.slt.templates; - -import org.watertemplate.Template; - -public class SltScriptTemplate extends Template { - - public SltScriptTemplate() { - - } - - @Override - protected String getFilePath() { - return "slt.cl"; - } - -} diff --git a/src/main/lisp/load.lisp b/src/main/lisp/load.lisp new file mode 100644 index 0000000..74c7fc0 --- /dev/null +++ b/src/main/lisp/load.lisp @@ -0,0 +1,6 @@ +(format T "SLT Interpret ~S~%" +slt-interpret+) + +(load (merge-pathnames "swank/swank.lisp" *load-truename*)) +(load (merge-pathnames "slt/slt.lisp" *load-truename*)) + +(in-package :cl-user) \ No newline at end of file diff --git a/src/main/lisp/slt/slt-sbcl.lisp b/src/main/lisp/slt/slt-sbcl.lisp new file mode 100644 index 0000000..58d2443 --- /dev/null +++ b/src/main/lisp/slt/slt-sbcl.lisp @@ -0,0 +1,4 @@ +(in-package :slt-core) + +(defun specialp (test-sym) + (eq (sb-cltl2:variable-information test-sym) :special)) \ No newline at end of file diff --git a/src/main/lisp/slt/slt.lisp b/src/main/lisp/slt/slt.lisp new file mode 100644 index 0000000..4fcd590 --- /dev/null +++ b/src/main/lisp/slt/slt.lisp @@ -0,0 +1,90 @@ +(defpackage :slt-core + (:use :cl :swank) + (:export analyze-symbol analyze-symbols read-fix-packages list-package-names + initialize-or-get-debug-context debug-context debug-frame-variable register-variable + )) + +(when (eq +slt-interpret+ :sbcl) + (load (merge-pathnames "slt-sbcl.lisp" *load-truename*))) + +(in-package :slt-core) + +(defun analyze-symbol (test-sym) + (cons test-sym + (let ((*standard-output* (make-string-output-stream)) + (swank::*source-snippet-size* 0)) + (cond + ((not test-sym) (list NIL NIL NIL)) + ((and (fboundp test-sym) + (typep (symbol-function test-sym) 'generic-function)) + (progn + (describe test-sym) + (list :method (get-output-stream-string *standard-output*) + (swank:find-source-location (symbol-function test-sym))))) + ((special-operator-p test-sym) (list :special-form NIL NIL)) + ((macro-function test-sym) (progn + (describe test-sym) + (list + :macro + (get-output-stream-string *standard-output*) + (swank:find-source-location (symbol-function test-sym))))) + ((fboundp test-sym) (progn + (describe test-sym) + (list + :function + (get-output-stream-string *standard-output*) + (swank:find-source-location (symbol-function test-sym))))) + ((specialp test-sym) (progn + (describe test-sym) + (list :special (get-output-stream-string *standard-output*) NIL))) + ((keywordp test-sym) (progn + (describe test-sym) + (list :keyword (get-output-stream-string *standard-output*) NIL))) + ((constantp test-sym) (progn + (describe test-sym) + (list :constant (get-output-stream-string *standard-output*) NIL))) + ((find-class test-sym NIL) (progn + (describe test-sym) + (list :class (get-output-stream-string *standard-output*) + (swank:find-source-location (find-class test-sym))))) + (T (list NIL NIL NIL)))))) + +(defun analyze-symbols (symbols) + (map 'list #'analyze-symbol symbols)) + +(defun reader-recover (c) + (declare (ignorable c)) + (let ((restart (find-restart 'eclector.reader:recover))) + (when restart + (invoke-restart restart)))) + +(defun reader-recover (c) + (declare (ignorable c)) + (let ((restart (find-restart 'eclector.reader:recover))) + (when restart + (invoke-restart restart)))) + +(defun reader-user-anyway (c) + (declare (ignorable c)) + (let ((restart (find-restart 'eclector.reader::use-anyway))) + (when restart + (invoke-restart restart)))) + +(defun read-fix-packages (str) + (handler-bind + ((ECLECTOR.READER:SYMBOL-NAME-MUST-NOT-END-WITH-PACKAGE-MARKER + #'reader-recover) + (ECLECTOR.READER:SYMBOL-IS-NOT-EXTERNAL + #'reader-user-anyway) + (ECLECTOR.READER:SYMBOL-DOES-NOT-EXIST + #'reader-recover) + (ECLECTOR.READER:PACKAGE-DOES-NOT-EXIST + #'reader-recover) + (error (lambda (c) + (format *error-output* "general error: ~S ~%" c)))) + (eclector.reader:read-from-string str))) + +(defun list-package-names () + (let ((packages (list-all-packages))) + (loop for package in packages collect + (package-name package)))) \ No newline at end of file diff --git a/src/main/lisp/swank/swank-backend.lisp b/src/main/lisp/swank/swank-backend.lisp new file mode 100644 index 0000000..4ee393a --- /dev/null +++ b/src/main/lisp/swank/swank-backend.lisp @@ -0,0 +1,2 @@ +(in-package swank/backend) + diff --git a/src/main/lisp/swank/swank-sbcl.lisp b/src/main/lisp/swank/swank-sbcl.lisp new file mode 100644 index 0000000..b13025c --- /dev/null +++ b/src/main/lisp/swank/swank-sbcl.lisp @@ -0,0 +1,15 @@ +(in-package sb-debug) + +(export 'frame-code-location) +(export 'frame-call) +(export 'ensure-printable-object) +(export 'code-location-source-form) + +(in-package :swank) + +(defun print-frame-call-place (frame) + (multiple-value-bind (name args info) + (SB-DEBUG:frame-call frame) + (declare (ignore args info)) + (let ((name (SB-DEBUG:ensure-printable-object name))) + name))) diff --git a/src/main/lisp/swank/swank.lisp b/src/main/lisp/swank/swank.lisp new file mode 100644 index 0000000..4c9f54e --- /dev/null +++ b/src/main/lisp/swank/swank.lisp @@ -0,0 +1,108 @@ +(load (merge-pathnames "swank-backend.lisp" *load-truename*)) +(when (eq +slt-interpret+ :sbcl) + (load (merge-pathnames "swank-sbcl.lisp" *load-truename*))) + +(in-package :swank) + +(export 'find-source-location) + +(defslimefun slt-eval (string) + (let ((*echo-area-prefix* "")) + (with-buffer-syntax () + (with-retry-restart (:msg "Retry SLIME interactive evaluation request.") + (let ((values (multiple-value-list (eval (from-string string))))) + (finish-output) + (format-values-for-echo-area values)))))) + +(defslimefun invoke-nth-restart-slt (sldb-level n args rest) + (when (= sldb-level *sldb-level*) + (let ((restart (nth-restart n)) + (parsed-args (from-string args)) + (parsed-rest (from-string rest))) + (when restart + (if (or parsed-args parsed-rest) + (apply #'invoke-restart (concatenate 'list (list restart) parsed-args parsed-rest)) + (invoke-restart restart)))))) + +(defun format-restarts-for-emacs () + "Return a list of restarts for *swank-debugger-condition* in a +format suitable for Emacs." + (let ((*print-right-margin* most-positive-fixnum)) + (loop for restart in *sldb-restarts* collect + (list (format nil "~:[~;*~]~a" + (eq restart *sldb-quit-restart*) + (restart-name restart)) + (with-output-to-string (stream) + (without-printing-errors (:object restart + :stream stream + :msg "<>") + (princ restart stream))) + (swank-backend:arglist (slot-value restart 'function)))))) + +(defslimefun backtrace (start end) + (loop for frame in (compute-backtrace start end) + for i from start collect + (list i (frame-to-string frame) + (format NIL "~S" (print-frame-call-place frame)) + (frame-source-location i) + (let ((pkg (frame-package i))) + (cond + (pkg (package-name pkg)) + (T NIL)))))) + +(defslimefun compile-string-region-slt (string buffer offset filename package) + (with-buffer-syntax () + (collect-notes + (lambda () + (let ((*compile-print* t) (*compile-verbose* nil) (*package* (find-package package))) + (swank-compile-string string + :buffer buffer + :position offset + :filename filename)))))) + +(defun get-all-symbols-with-prefix (prefix) + (let ((all (get-all-symbols))) + (loop for data-pair in all + when (prefix-match-p prefix (first data-pair)) + collect data-pair))) + +(defun get-all-symbols () + (let ((data '())) + (do-symbols (s) + (push (list (unparse-symbol s) s (symbol-package s)) data)) + (remove-duplicates data :key (lambda (e) (second e))))) + +(defun find-reference-class-filter (symbol package) + (find-class symbol NIL)) + +(defun get-reference-prefix (prefix type) + (let ((apply-func (cond + ((eq type :class) #'find-reference-class-filter) + (T (lambda (symbol package) T))))) + (let ((filtered-symbols (get-all-symbols-with-prefix prefix)) + (*source-snippet-size* 0)) + (loop for data-pair in filtered-symbols + when (funcall apply-func (second data-pair) (third data-pair)) + collect + (let* ((symbol (second data-pair)) + (str (first data-pair)) + (package (third data-pair)) + (strpackage (format NIL "~S" package))) + (cond + ((not symbol) (list str strpackage NIL NIL)) + ((macro-function symbol) (list str strpackage :macro (find-source-location (symbol-function symbol)))) + ((and (fboundp symbol) + (typep (symbol-function symbol) 'generic-function)) + (list str strpackage :method (find-source-location (symbol-function symbol)))) + ((fboundp symbol) (list str strpackage :function (find-source-location (symbol-function symbol)))) + ((find-class symbol NIL) (list str strpackage :class (find-source-location (find-class symbol)))) + (T (list str strpackage NIL NIL)))))))) + +(defslimefun find-reference-prefix (prefix type) + (let ((references (get-reference-prefix prefix type))) + (when references + (sort references #'string< :key (lambda (x) (first x)))))) + +(export 'slt-eval) +(export 'compile-string-region-slt) +(export 'find-reference-prefix) \ No newline at end of file diff --git a/src/main/resources/templates/en_US/initscript.cl b/src/main/resources/templates/en_US/initscript.cl index 2489a39..b99edc0 100644 --- a/src/main/resources/templates/en_US/initscript.cl +++ b/src/main/resources/templates/en_US/initscript.cl @@ -1,3 +1,7 @@ +(in-package :cl) +(defconstant +slt-interpret+ ~interpret~ + "Defines current slt interpret. For SBCL the value is :sbcl") + (load "~qlpath~") (ql:quickload :swank) (ql:quickload :eclector) diff --git a/src/main/resources/templates/en_US/slt.cl b/src/main/resources/templates/en_US/slt.cl deleted file mode 100644 index 1dfd843..0000000 --- a/src/main/resources/templates/en_US/slt.cl +++ /dev/null @@ -1,222 +0,0 @@ -; TODO: swank:defslimefunction - -(defpackage :slt-core - (:use :cl :swank) - (:export analyze-symbol analyze-symbols read-fix-packages list-package-names - initialize-or-get-debug-context debug-context debug-frame-variable register-variable - )) - -; swank/slime overrides - -(in-package sb-debug) - -(export 'frame-code-location) -(export 'frame-call) -(export 'ensure-printable-object) -(export 'code-location-source-form) - -(in-package swank/backend) - -(in-package :swank) - -(export 'find-source-location) - -(defslimefun slt-eval (string) - (let ((*echo-area-prefix* "")) - (with-buffer-syntax () - (with-retry-restart (:msg "Retry SLIME interactive evaluation request.") - (let ((values (multiple-value-list (eval (from-string string))))) - (finish-output) - (format-values-for-echo-area values)))))) - -(defslimefun invoke-nth-restart-slt (sldb-level n args rest) - (when (= sldb-level *sldb-level*) - (let ((restart (nth-restart n)) - (parsed-args (from-string args)) - (parsed-rest (from-string rest))) - (when restart - (if (or parsed-args parsed-rest) - (apply #'invoke-restart (concatenate 'list (list restart) parsed-args parsed-rest)) - (invoke-restart restart)))))) - -(defun format-restarts-for-emacs () - "Return a list of restarts for *swank-debugger-condition* in a -format suitable for Emacs." - (let ((*print-right-margin* most-positive-fixnum)) - (loop for restart in *sldb-restarts* collect - (list (format nil "~:[~;*~]~a" - (eq restart *sldb-quit-restart*) - (restart-name restart)) - (with-output-to-string (stream) - (without-printing-errors (:object restart - :stream stream - :msg "<>") - (princ restart stream))) - (swank-backend:arglist (slot-value restart 'function)))))) - -(defun print-frame-call-place (frame) - (multiple-value-bind (name args info) - (SB-DEBUG:frame-call frame) - (declare (ignore args info)) - (let ((name (SB-DEBUG:ensure-printable-object name))) - name))) - -(defslimefun backtrace (start end) - (loop for frame in (compute-backtrace start end) - for i from start collect - (list i (frame-to-string frame) - (format NIL "~S" (print-frame-call-place frame)) - (frame-source-location i) - (let ((pkg (frame-package i))) - (cond - (pkg (package-name pkg)) - (T NIL)))))) - -(defslimefun compile-string-region-slt (string buffer offset filename package) - (with-buffer-syntax () - (collect-notes - (lambda () - (let ((*compile-print* t) (*compile-verbose* nil) (*package* (find-package package))) - (swank-compile-string string - :buffer buffer - :position offset - :filename filename)))))) - -(in-package swank) - -(defun get-all-symbols-with-prefix (prefix) - (let ((all (get-all-symbols))) - (loop for data-pair in all - when (prefix-match-p prefix (first data-pair)) - collect data-pair))) - -(defun get-all-symbols () - (let ((data '())) - (do-symbols (s) - (push (list (unparse-symbol s) s (symbol-package s)) data)) - (remove-duplicates data :key (lambda (e) (second e))))) - -(defun find-reference-class-filter (symbol package) - (find-class symbol NIL)) - -(defun get-reference-prefix (prefix type) - (let ((apply-func (cond - ((eq type :class) #'find-reference-class-filter) - (T (lambda (symbol package) T))))) - (let ((filtered-symbols (get-all-symbols-with-prefix prefix)) - (*source-snippet-size* 0)) - (loop for data-pair in filtered-symbols - when (funcall apply-func (second data-pair) (third data-pair)) - collect - (let* ((symbol (second data-pair)) - (str (first data-pair)) - (package (third data-pair)) - (strpackage (format NIL "~S" package))) - (cond - ((not symbol) (list str strpackage NIL NIL)) - ((macro-function symbol) (list str strpackage :macro (swank:find-source-location (symbol-function symbol)))) - ((and (fboundp symbol) - (typep (symbol-function symbol) 'generic-function)) - (list str strpackage :method (swank:find-source-location (symbol-function symbol)))) - ((fboundp symbol) (list str strpackage :function (swank:find-source-location (symbol-function symbol)))) - ((find-class symbol NIL) (list str strpackage :class (swank:find-source-location (find-class symbol)))) - (T (list str strpackage NIL NIL)))))))) - -(defslimefun find-reference-prefix (prefix type) - (let ((references (get-reference-prefix prefix type))) - (when references - (sort references #'string< :key (lambda (x) (first x)))))) - -(export 'slt-eval) -(export 'compile-string-region-slt) - -(in-package swank/sbcl) - -(in-package swank/source-file-cache) - -(in-package :slt-core) - -(defun specialp (test-sym) - (eq (sb-cltl2:variable-information test-sym) :special)) - -(defun analyze-symbol (test-sym) - (cons test-sym - (let ((*standard-output* (make-string-output-stream)) - (*source-snippet-size* 0)) - (cond - ((not test-sym) (list NIL NIL NIL)) - ((and (fboundp test-sym) - (typep (symbol-function test-sym) 'generic-function)) - (progn - (describe test-sym) - (list :method (get-output-stream-string *standard-output*) - (swank:find-source-location (symbol-function test-sym))))) - ((special-operator-p test-sym) (list :special-form NIL NIL)) - ((macro-function test-sym) (progn - (describe test-sym) - (list - :macro - (get-output-stream-string *standard-output*) - (swank:find-source-location (symbol-function test-sym))))) - ((fboundp test-sym) (progn - (describe test-sym) - (list - :function - (get-output-stream-string *standard-output*) - (swank:find-source-location (symbol-function test-sym))))) - ((specialp test-sym) (progn - (describe test-sym) - (list :special (get-output-stream-string *standard-output*) NIL))) - ((keywordp test-sym) (progn - (describe test-sym) - (list :keyword (get-output-stream-string *standard-output*) NIL))) - ((constantp test-sym) (progn - (describe test-sym) - (list :constant (get-output-stream-string *standard-output*) NIL))) - ((find-class test-sym NIL) (progn - (describe test-sym) - (list :class (get-output-stream-string *standard-output*) - (swank:find-source-location (find-class test-sym))))) - (T (list NIL NIL NIL)))))) - -(defun analyze-symbols (symbols) - (map 'list #'analyze-symbol symbols)) - -(defun reader-recover (c) - (declare (ignorable c)) - (let ((restart (find-restart 'eclector.reader:recover))) - (when restart - (invoke-restart restart)))) - -(defun reader-recover (c) - (declare (ignorable c)) - (let ((restart (find-restart 'eclector.reader:recover))) - (when restart - (invoke-restart restart)))) - -(defun reader-user-anyway (c) - (declare (ignorable c)) - (let ((restart (find-restart 'eclector.reader::use-anyway))) - (when restart - (invoke-restart restart)))) - -(defun read-fix-packages (str) - (handler-bind - ((ECLECTOR.READER:SYMBOL-NAME-MUST-NOT-END-WITH-PACKAGE-MARKER - #'reader-recover) - (ECLECTOR.READER:SYMBOL-IS-NOT-EXTERNAL - #'reader-user-anyway) - (ECLECTOR.READER:SYMBOL-DOES-NOT-EXIST - #'reader-recover) - (ECLECTOR.READER:PACKAGE-DOES-NOT-EXIST - #'reader-recover) - (error (lambda (c) - (format *error-output* "general error: ~S ~%" c)))) - (eclector.reader:read-from-string str))) - -(defun list-package-names () - (let ((packages (list-all-packages))) - (loop for package in packages collect - (package-name package)))) - -(in-package :cl-user) \ No newline at end of file diff --git a/src/test/java/com/en_circle/slt/tests/indentation/IndentationTests.java b/src/test/java/com/en_circle/slt/tests/indentation/IndentationTests.java index fd6e5b7..ee11ea6 100644 --- a/src/test/java/com/en_circle/slt/tests/indentation/IndentationTests.java +++ b/src/test/java/com/en_circle/slt/tests/indentation/IndentationTests.java @@ -35,9 +35,9 @@ public void testFormsBlock() throws Exception { public void testFormsCase() throws Exception { assertEquals(4, container.testIndentCL("(case XXX)")); assertEquals(2, container.testIndentCL("(case blah XXX)")); - assertEquals(3, container.testIndentCL("(case blah (XXX))")); - assertEquals(3, container.testIndentCL("(case blah (wot) (XXX))")); - assertEquals(3, container.testIndentCL("(case blah (foo XXX))")); + assertEquals(12, container.testIndentCL("(case blah (XXX))")); + assertEquals(18, container.testIndentCL("(case blah (wot) (XXX))")); + assertEquals(12, container.testIndentCL("(case blah (foo XXX))")); assertEquals(3, container.testIndentCL(""" (case blah @@ -67,11 +67,11 @@ public void testFormsCatch() throws Exception { @Test public void testFormsCond() throws Exception { assertEquals(2, container.testIndentCL("(cond XXX)")); - assertEquals(4, container.testIndentCL("(cond (XXX))")); - assertEquals(4, container.testIndentCL("(cond (foo XXX))")); + assertEquals(8, container.testIndentCL("(cond (XXX))")); + assertEquals(10, container.testIndentCL("(cond (foo XXX))")); assertEquals(7+4, container.testIndentCL("(cond ((= 1 XXX)))")); - assertEquals(4, container.testIndentCL("(cond (foo bar) (XXX))")); - assertEquals(4, container.testIndentCL("(cond (foo bar) (baz XXX))")); + assertEquals(18, container.testIndentCL("(cond (foo bar) (XXX))")); + assertEquals(20, container.testIndentCL("(cond (foo bar) (baz XXX))")); } @Test From 621aefacf0299abe0d554d8165a7ae189dd85312 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Tue, 31 Jan 2023 08:18:15 +0100 Subject: [PATCH 04/21] version --- CHANGELOG.md | 10 ++++++++++ README.md | 1 + 2 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ee427e..21ec43b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 0.3.1 + +### Changes + +- SLT library is now formatted into multiple chunks + +### Fixes + +- Fixed tests + ## 0.3.0 230108 ### Added diff --git a/README.md b/README.md index 59c2ec2..f3e6758 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ [![0.1.0](https://badgen.net/github/milestones/enerccio/SLT/1)](https://github.com/enerccio/SLT/milestone/1) [![0.2.0](https://badgen.net/github/milestones/enerccio/SLT/2)](https://github.com/enerccio/SLT/milestone/2) [![0.3.0](https://badgen.net/github/milestones/enerccio/SLT/4)](https://github.com/enerccio/SLT/milestone/4) +[![0.3.0](https://badgen.net/github/milestones/enerccio/SLT/5)](https://github.com/enerccio/SLT/milestone/5) ![GitHub all releases](https://img.shields.io/github/downloads/Enerccio/SLT/total) ![GitHub last commit](https://img.shields.io/github/last-commit/Enerccio/SLT) ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/Enerccio/SLT) From bfd3c5cae43b3e74e8ee367d92177942df13cb66 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Tue, 31 Jan 2023 09:35:25 +0100 Subject: [PATCH 05/21] environment preparations --- CHANGELOG.md | 7 ++ build.gradle.kts | 4 +- .../slt/plugin/environment/Environment.java | 72 +++++++++++++++++++ .../slt/plugin/references/SltReference.java | 5 ++ .../com/en_circle/slt/plugin/sdk/LispSdk.java | 21 ++++++ .../lisp/LispEnvironmentServiceImpl.java | 14 ++-- ....java => SdkConfigurationSBCLProcess.java} | 29 +++----- .../slt/plugin/ui/sdk/SdkConfigurer.java | 56 +++++++++++---- .../slt/plugin/ui/sdk/SdkDialogProvider.java | 22 ++++++ .../tools/platform/DownloadLispAction.java | 13 ++++ .../tools/platform/DownloadSBCLAction.java | 3 +- .../tools/platform/DownloadSBCLMsiAction.java | 2 +- src/main/lisp/load.lisp | 9 +++ src/main/lisp/swank/swank.lisp | 17 ++--- .../resources/messages/SltBundle.properties | 26 +++---- 15 files changed, 233 insertions(+), 67 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/environment/Environment.java rename src/main/java/com/en_circle/slt/plugin/ui/sdk/{SdkConfiguration.java => SdkConfigurationSBCLProcess.java} (94%) create mode 100644 src/main/java/com/en_circle/slt/plugin/ui/sdk/SdkDialogProvider.java create mode 100644 src/main/java/com/en_circle/slt/tools/platform/DownloadLispAction.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ce47a4..a227a8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,15 @@ ### Added +### Changes + +- SLT library is now formatted into multiple chunks + ### Fixes +- Fixed tests + + ## 0.3.0 - 230108 ### Added diff --git a/build.gradle.kts b/build.gradle.kts index 4d0b3e6..89cb1c6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,8 +16,8 @@ dependencies { implementation("com.google.guava:guava:31.1-jre") implementation("org.rauschig:jarchivelib:1.2.0") - testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2") } sourceSets { diff --git a/src/main/java/com/en_circle/slt/plugin/environment/Environment.java b/src/main/java/com/en_circle/slt/plugin/environment/Environment.java new file mode 100644 index 0000000..dfc5545 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/environment/Environment.java @@ -0,0 +1,72 @@ +package com.en_circle.slt.plugin.environment; + +import com.en_circle.slt.plugin.SltBundle; +import com.en_circle.slt.plugin.environment.SltLispEnvironmentConfiguration.Builder; +import com.en_circle.slt.plugin.sdk.LispSdk; +import com.en_circle.slt.plugin.ui.sdk.SdkConfigurationSBCLProcess; +import com.en_circle.slt.plugin.ui.sdk.SdkDialogProvider; +import com.en_circle.slt.tools.ProjectUtils; +import com.en_circle.slt.tools.platform.DownloadLispAction; +import com.en_circle.slt.tools.platform.DownloadSBCLAction; + +import java.util.function.Supplier; + +public enum Environment { + + SBCL_PROCESS(new EnvironmentDefinition() { + @Override + public String getName() { + return SltBundle.message("slt.environment.sbcl"); + } + + @Override + public Class getDownloadActionDef() { + return DownloadSBCLAction.class; + } + + @Override + public Supplier getEnvironmentCreator() { + return SltSBCLEnvironment::new; + } + + @SuppressWarnings("unchecked") + @Override + public , R extends SltLispEnvironmentConfiguration> + SltLispEnvironmentConfiguration.Builder buildConfiguration(LispSdk sdk) { + return (Builder) new SltSBCLEnvironmentConfiguration.Builder() + .setExecutable(sdk.sbclExecutable) + .setCore(sdk.sbclCorePath) + .setQuicklispStartScriptPath(sdk.quickLispPath) + .setProjectDirectory(ProjectUtils.getCurrentProject().getBasePath()); + } + + @Override + public SdkDialogProvider getDialogProvider() { + return SdkConfigurationSBCLProcess::new; + } + }) + + ; + + private final EnvironmentDefinition definition; + + Environment(EnvironmentDefinition definition) { + this.definition = definition; + } + + public EnvironmentDefinition getDefinition() { + return definition; + } + + public static abstract class EnvironmentDefinition { + + public abstract String getName(); + public abstract Class getDownloadActionDef(); + public abstract Supplier getEnvironmentCreator(); + public abstract , R extends SltLispEnvironmentConfiguration> + SltLispEnvironmentConfiguration.Builder buildConfiguration(LispSdk sdk); + public abstract SdkDialogProvider getDialogProvider(); + + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/references/SltReference.java b/src/main/java/com/en_circle/slt/plugin/references/SltReference.java index 86c120d..5235ee6 100644 --- a/src/main/java/com/en_circle/slt/plugin/references/SltReference.java +++ b/src/main/java/com/en_circle/slt/plugin/references/SltReference.java @@ -94,6 +94,11 @@ private ResolveResult[] getReferenceClosesSymbolOrFail(PsiElement referenceEleme } } } + + if (referenceElement instanceof LispSymbol) { + // default just move to this even if it is a different symbol + return new ResolveResult[] { new PsiElementResolveResult(referenceElement) }; + } return new ResolveResult[0]; } diff --git a/src/main/java/com/en_circle/slt/plugin/sdk/LispSdk.java b/src/main/java/com/en_circle/slt/plugin/sdk/LispSdk.java index afd629c..2ecb57f 100644 --- a/src/main/java/com/en_circle/slt/plugin/sdk/LispSdk.java +++ b/src/main/java/com/en_circle/slt/plugin/sdk/LispSdk.java @@ -1,5 +1,6 @@ package com.en_circle.slt.plugin.sdk; +import com.en_circle.slt.plugin.environment.Environment; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.util.xmlb.XmlSerializerUtil; import org.jetbrains.annotations.NotNull; @@ -10,18 +11,38 @@ public class LispSdk implements PersistentStateComponent { public String uuid; public String userName; + // use getter! + public Environment environment; + + // SBCL Process used public String sbclExecutable; public String sbclCorePath; public String quickLispPath; + public Environment getEnvironment() { + if (environment == null) { + // backwards compat + environment = Environment.SBCL_PROCESS; + } + return environment; + } + @Override public @Nullable LispSdk getState() { + if (environment == null) { + // backwards compat + environment = Environment.SBCL_PROCESS; + } return this; } @Override public void loadState(@NotNull LispSdk state) { XmlSerializerUtil.copyBean(state, this); + if (environment == null) { + // backwards compat + environment = Environment.SBCL_PROCESS; + } } } diff --git a/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java b/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java index 1d7653f..6860c74 100644 --- a/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java +++ b/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java @@ -2,8 +2,10 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.SymbolState; -import com.en_circle.slt.plugin.environment.*; +import com.en_circle.slt.plugin.environment.SltLispEnvironment; import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; +import com.en_circle.slt.plugin.environment.SltLispEnvironmentConfiguration; +import com.en_circle.slt.plugin.environment.SltProcessException; import com.en_circle.slt.plugin.lisp.lisp.LispContainer; import com.en_circle.slt.plugin.lisp.lisp.LispElement; import com.en_circle.slt.plugin.lisp.psi.LispList; @@ -78,12 +80,10 @@ public boolean configured() { return false; } - environmentProvider = SltSBCLEnvironment::new; - configurationBuilder = new SltSBCLEnvironmentConfiguration.Builder() - .setExecutable(sdk.sbclExecutable) - .setCore(sdk.sbclCorePath) - .setQuicklispStartScriptPath(sdk.quickLispPath) - .setProjectDirectory(ProjectUtils.getCurrentProject().getBasePath()); + environmentProvider = sdk.getEnvironment().getDefinition().getEnvironmentCreator(); + configurationBuilder = sdk.getEnvironment().getDefinition().buildConfiguration(sdk); + + // TODO: add UI resolve actions here return true; } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/sdk/SdkConfiguration.java b/src/main/java/com/en_circle/slt/plugin/ui/sdk/SdkConfigurationSBCLProcess.java similarity index 94% rename from src/main/java/com/en_circle/slt/plugin/ui/sdk/SdkConfiguration.java rename to src/main/java/com/en_circle/slt/plugin/ui/sdk/SdkConfigurationSBCLProcess.java index ed00977..8e09ef1 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/sdk/SdkConfiguration.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/sdk/SdkConfigurationSBCLProcess.java @@ -2,6 +2,7 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.sdk.LispSdk; +import com.en_circle.slt.plugin.ui.sdk.SdkDialogProvider.OnSave; import com.en_circle.slt.tools.SBCLUtils; import com.intellij.openapi.Disposable; import com.intellij.openapi.fileChooser.FileChooserDescriptor; @@ -23,14 +24,13 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.border.Border; import javax.swing.event.CaretListener; import java.awt.*; import java.awt.event.ActionEvent; import java.io.File; import java.util.Objects; -public class SdkConfiguration extends DialogWrapper { +public class SdkConfigurationSBCLProcess extends DialogWrapper { private final Disposable parentDisposable; private final LispSdk instance; @@ -41,9 +41,8 @@ public class SdkConfiguration extends DialogWrapper { private FileTextField sbclExecutable; private FileTextField sbclCore; private FileTextField quicklispPath; - private Border baseBorder; - protected SdkConfiguration(@NotNull Component parent, LispSdk instance, String title, OnSave onSave) { + public SdkConfigurationSBCLProcess(@NotNull Component parent, LispSdk instance, String title, OnSave onSave) { super(parent, true); this.parentDisposable = Objects.requireNonNull(DialogWrapper.findInstanceFromFocus()).getDisposable(); @@ -91,20 +90,16 @@ protected SdkConfiguration(@NotNull Component parent, LispSdk instance, String t quicklispPathPicker.addBrowseFolderListener( SltBundle.message("slt.ui.settings.sdk.editor.quicklisp.select"), "", null, descriptor); - JPanel panel = new FormBuilder() + return new FormBuilder() .addLabeledComponent(SltBundle.message("slt.ui.settings.sdk.editor.name"), name, 1, false) - .addLabeledComponent(SltBundle.message("slt.ui.settings.sdk.editor.executable"), + .addLabeledComponent(SltBundle.message("slt.ui.settings.sdk.editor.sbcl.process.executable"), sbclExecutablePicker, 1, false) - .addLabeledComponent(SltBundle.message("slt.ui.settings.sdk.editor.core"), + .addLabeledComponent(SltBundle.message("slt.ui.settings.sdk.editor.sbcl.process.core"), sbclCorePicker, 1, false) .addLabeledComponent(SltBundle.message("slt.ui.settings.sdk.editor.quicklisp"), quicklispPathPicker, 1, false) .addComponentFillVertically(new JPanel(), 0) .getPanel(); - - baseBorder = name.getBorder(); - - return panel; } private CaretListener createChangeListener() { @@ -159,7 +154,7 @@ private void verifySdk() { if (verified) verified = checkAndLoadSbclCore(executable, core, quicklisp); if (!verified) { - Messages.showErrorDialog(SltBundle.message("slt.ui.settings.sdk.editor.verifying.error"), + Messages.showErrorDialog(SltBundle.message("slt.ui.settings.sdk.editor.sbcl.process.verifying.error"), SltBundle.message("slt.ui.settings.sdk.editor.verifying.error.title")); } @@ -204,7 +199,7 @@ private void save() { public class VerifyAction extends AbstractAction { public VerifyAction() { - super(SltBundle.message("slt.ui.settings.sdk.editor.verify")); + super(SltBundle.message("slt.ui.settings.sdk.editor.sbcl.process.verify")); } @Override @@ -223,7 +218,7 @@ public SaveAction() { public void actionPerformed(ActionEvent e) { if (!isVerified) { Messages.showInfoMessage(SltBundle.message("slt.ui.settings.sdk.editor.notverified.title"), - SltBundle.message("slt.ui.settings.sdk.editor.notverified.message")); + SltBundle.message("slt.ui.settings.sdk.editor.sbcl.process.notverified.message")); return; } @@ -231,10 +226,4 @@ public void actionPerformed(ActionEvent e) { } } - public interface OnSave { - - void saveAction(LispSdk sdk); - - } - } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/sdk/SdkConfigurer.java b/src/main/java/com/en_circle/slt/plugin/ui/sdk/SdkConfigurer.java index 87dbd22..b5fd712 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/sdk/SdkConfigurer.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/sdk/SdkConfigurer.java @@ -1,9 +1,10 @@ package com.en_circle.slt.plugin.ui.sdk; import com.en_circle.slt.plugin.SltBundle; +import com.en_circle.slt.plugin.environment.Environment; import com.en_circle.slt.plugin.sdk.LispSdk; import com.en_circle.slt.plugin.sdk.SdkList; -import com.en_circle.slt.tools.platform.DownloadSBCLAction; +import com.en_circle.slt.tools.platform.PlatformAction; import com.en_circle.slt.tools.platform.PlatformActionsContainer; import com.intellij.icons.AllIcons.Actions; import com.intellij.icons.AllIcons.General; @@ -11,6 +12,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.NlsContexts.ConfigurableName; import com.intellij.ui.components.JBScrollPane; @@ -99,11 +101,16 @@ private void addSdk() { LispSdk newSdk = new LispSdk(); newSdk.uuid = UUID.randomUUID().toString(); - SdkConfiguration configuration = new SdkConfiguration(root, newSdk, SltBundle.message("slt.ui.settings.sdk.editor.title.new"), + + // TODO: Environment selector + Environment environment = Environment.SBCL_PROCESS; + DialogWrapper configuration = environment.getDefinition().getDialogProvider().createSdkConfiguration( + root, newSdk, SltBundle.message("slt.ui.settings.sdk.editor.title.new"), sdk -> { - definedSdks.add(sdk); - SdkListModel model = new SdkListModel(definedSdks); - table.setModel(model); + sdk.environment = environment; + definedSdks.add(sdk); + SdkListModel model = new SdkListModel(definedSdks); + table.setModel(model); }); configuration.show(); } @@ -113,13 +120,17 @@ private void editSdk() { LispSdk copy = new LispSdk(); copy.loadState(sdk); - SdkConfiguration configuration = new SdkConfiguration(root, copy, SltBundle.message("slt.ui.settings.sdk.editor.title.edit"), + // TODO: Environment selector + Environment environment = Environment.SBCL_PROCESS; + DialogWrapper configuration = environment.getDefinition().getDialogProvider().createSdkConfiguration( + root, copy, SltBundle.message("slt.ui.settings.sdk.editor.title.edit"), sdkModified -> { - int ix = definedSdks.indexOf(sdk); - definedSdks.remove(ix); - definedSdks.add(ix, sdkModified); - SdkListModel model = new SdkListModel(definedSdks); - table.setModel(model); + sdkModified.environment = environment; + int ix = definedSdks.indexOf(sdk); + definedSdks.remove(ix); + definedSdks.add(ix, sdkModified); + SdkListModel model = new SdkListModel(definedSdks); + table.setModel(model); }); configuration.show(); } @@ -134,10 +145,14 @@ private void removeSdk() { @SuppressWarnings("IncorrectParentDisposable") private void downloadSdk() { - Objects.requireNonNull(PlatformActionsContainer.getAction(DownloadSBCLAction.class)) + // TODO: Use Environment + Environment environment = Environment.SBCL_PROCESS; + + Objects.requireNonNull(PlatformActionsContainer.getAction(environment.getDefinition().getDownloadActionDef())) .downloadSdk(ApplicationManager.getApplication(), root, sdk -> { if (sdk != null) { + sdk.environment = environment; definedSdks.add(sdk); SdkListModel model = new SdkListModel(definedSdks); table.setModel(model); @@ -202,7 +217,18 @@ public void actionPerformed(@NotNull AnActionEvent e) { @Override public void update(@NotNull AnActionEvent e) { - e.getPresentation().setEnabled(PlatformActionsContainer.hasAction(DownloadSBCLAction.class)); + boolean enable = false; + for (Environment environment : Environment.values()) { + Class actionDef = environment.getDefinition().getDownloadActionDef(); + if (actionDef != null) { + if (PlatformActionsContainer.hasAction(actionDef)) { + enable = true; + break; + } + } + } + + e.getPresentation().setEnabled(enable); } @Override @@ -257,7 +283,7 @@ public int getColumnCount() { public Object getValueAt(int rowIndex, int columnIndex) { return switch (columnIndex) { case 0 -> items.get(rowIndex).userName; - case 1 -> items.get(rowIndex).sbclExecutable; + case 1 -> items.get(rowIndex).getEnvironment().getDefinition().getName(); case 2 -> items.get(rowIndex).quickLispPath; default -> null; }; @@ -267,7 +293,7 @@ public Object getValueAt(int rowIndex, int columnIndex) { public String getColumnName(int column) { return switch (column) { case 0 -> SltBundle.message("slt.ui.settings.sdk.table.column.name"); - case 1 -> SltBundle.message("slt.ui.settings.sdk.table.column.executable"); + case 1 -> SltBundle.message("slt.ui.settings.sdk.table.column.type"); case 2 -> SltBundle.message("slt.ui.settings.sdk.table.column.quicklisp"); default -> null; }; diff --git a/src/main/java/com/en_circle/slt/plugin/ui/sdk/SdkDialogProvider.java b/src/main/java/com/en_circle/slt/plugin/ui/sdk/SdkDialogProvider.java new file mode 100644 index 0000000..4eae85b --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/ui/sdk/SdkDialogProvider.java @@ -0,0 +1,22 @@ +package com.en_circle.slt.plugin.ui.sdk; + +import com.en_circle.slt.plugin.sdk.LispSdk; +import com.intellij.openapi.ui.DialogWrapper; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; + +public interface SdkDialogProvider { + + DialogWrapper createSdkConfiguration(@NotNull Component parent, + LispSdk instance, + String title, + OnSave onSave); + + interface OnSave { + + void saveAction(LispSdk sdk); + + } + +} diff --git a/src/main/java/com/en_circle/slt/tools/platform/DownloadLispAction.java b/src/main/java/com/en_circle/slt/tools/platform/DownloadLispAction.java new file mode 100644 index 0000000..c8028b0 --- /dev/null +++ b/src/main/java/com/en_circle/slt/tools/platform/DownloadLispAction.java @@ -0,0 +1,13 @@ +package com.en_circle.slt.tools.platform; + +import com.en_circle.slt.plugin.sdk.LispSdk; +import com.intellij.openapi.Disposable; + +import javax.swing.*; +import java.util.function.Consumer; + +public interface DownloadLispAction extends UIAction { + + void downloadSdk(Disposable disposable, JComponent rootPane, Consumer acceptor); + +} diff --git a/src/main/java/com/en_circle/slt/tools/platform/DownloadSBCLAction.java b/src/main/java/com/en_circle/slt/tools/platform/DownloadSBCLAction.java index bd9468b..33b3513 100644 --- a/src/main/java/com/en_circle/slt/tools/platform/DownloadSBCLAction.java +++ b/src/main/java/com/en_circle/slt/tools/platform/DownloadSBCLAction.java @@ -8,13 +8,14 @@ import javax.swing.*; import java.util.function.Consumer; -public interface DownloadSBCLAction extends UIAction { +public interface DownloadSBCLAction extends DownloadLispAction { Logger log = LoggerFactory.getLogger(DownloadSBCLAction.class); LispSdk getConfiguredSdk(); void setDisposable(Disposable disposable); void setRootPane(JComponent rootPane); + @Override default void downloadSdk(Disposable disposable, JComponent rootPane, Consumer acceptor) { setDisposable(disposable); setRootPane(rootPane); diff --git a/src/main/java/com/en_circle/slt/tools/platform/DownloadSBCLMsiAction.java b/src/main/java/com/en_circle/slt/tools/platform/DownloadSBCLMsiAction.java index 189cc44..0d956d4 100644 --- a/src/main/java/com/en_circle/slt/tools/platform/DownloadSBCLMsiAction.java +++ b/src/main/java/com/en_circle/slt/tools/platform/DownloadSBCLMsiAction.java @@ -63,7 +63,7 @@ public void run(Runnable callback) { private SBCLInstallation downloadSbcl(String uuidInstall) { ProgressWindow verifyWindow = new ProgressWindow(true, false, null, rootPane, SltBundle.message("slt.ui.settings.sdk.download.cancel")); - verifyWindow.setTitle(SltBundle.message("slt.ui.settings.sdk.download.downloading")); + verifyWindow.setTitle(SltBundle.message("slt.ui.settings.sdk.download.sbcl.downloading")); Disposer.register(parentDisposable, verifyWindow); ProgressResult result = new ProgressRunner<>(pi -> downloadSbcl(uuidInstall, pi)) diff --git a/src/main/lisp/load.lisp b/src/main/lisp/load.lisp index 74c7fc0..bc54223 100644 --- a/src/main/lisp/load.lisp +++ b/src/main/lisp/load.lisp @@ -1,5 +1,14 @@ (format T "SLT Interpret ~S~%" +slt-interpret+) +(case +slt-interpret+ + (:sbcl (unless (string= "SBCL" + (lisp-implementation-type)) + (format *error-output* "Invalid lisp instance. Maybe a configuration error? This is not SBCL!~%") + (exit 1))) + (otherwise + (format *error-output* "Unsupported lisp instance. Maybe a configuration error?~%") + (exit 1))) + (load (merge-pathnames "swank/swank.lisp" *load-truename*)) (load (merge-pathnames "slt/slt.lisp" *load-truename*)) diff --git a/src/main/lisp/swank/swank.lisp b/src/main/lisp/swank/swank.lisp index 4c9f54e..4645354 100644 --- a/src/main/lisp/swank/swank.lisp +++ b/src/main/lisp/swank/swank.lisp @@ -4,6 +4,8 @@ (in-package :swank) +(setf *SOURCE-SNIPPET-SIZE* 0) + (export 'find-source-location) (defslimefun slt-eval (string) @@ -60,18 +62,18 @@ format suitable for Emacs." :position offset :filename filename)))))) -(defun get-all-symbols-with-prefix (prefix) - (let ((all (get-all-symbols))) - (loop for data-pair in all - when (prefix-match-p prefix (first data-pair)) - collect data-pair))) - (defun get-all-symbols () (let ((data '())) (do-symbols (s) (push (list (unparse-symbol s) s (symbol-package s)) data)) (remove-duplicates data :key (lambda (e) (second e))))) +(defun get-all-symbols-with-prefix (prefix) + (let ((all (get-all-symbols))) + (loop for data-pair in all + when (prefix-match-p prefix (first data-pair)) + collect data-pair))) + (defun find-reference-class-filter (symbol package) (find-class symbol NIL)) @@ -79,8 +81,7 @@ format suitable for Emacs." (let ((apply-func (cond ((eq type :class) #'find-reference-class-filter) (T (lambda (symbol package) T))))) - (let ((filtered-symbols (get-all-symbols-with-prefix prefix)) - (*source-snippet-size* 0)) + (let ((filtered-symbols (get-all-symbols-with-prefix prefix))) (loop for data-pair in filtered-symbols when (funcall apply-func (second data-pair) (third data-pair)) collect diff --git a/src/main/resources/messages/SltBundle.properties b/src/main/resources/messages/SltBundle.properties index d187d88..07cec6c 100644 --- a/src/main/resources/messages/SltBundle.properties +++ b/src/main/resources/messages/SltBundle.properties @@ -6,7 +6,7 @@ slt.error.sbclstart=Error starting sbcl slt.error.sbclstop=Error stopping sbcl # SDK -slt.sdk.name=SBCl +slt.environment.sbcl=SBCL # Documentation elements slt.documentation.types.symbol=Symbol @@ -96,36 +96,36 @@ slt.ui.projectsettings.sdk.restart.yes=Yes slt.ui.projectsettings.sdk.restart.no=No slt.ui.settings.sdk=Common Lisp SDKs slt.ui.settings.sdk.table.column.name=Name -slt.ui.settings.sdk.table.column.executable=Executable +slt.ui.settings.sdk.table.column.type=Executable slt.ui.settings.sdk.table.column.quicklisp=Quicklisp Path -slt.ui.settings.sdk.edit=Edit SBCL SDK -slt.ui.settings.sdk.add=Add New SBCL SDK -slt.ui.settings.sdk.download=Download New SBCL SDK (Windows Only) -slt.ui.settings.sdk.remove=Remove SBCL SDK +slt.ui.settings.sdk.edit=Edit an SDK +slt.ui.settings.sdk.add=Add New SDK +slt.ui.settings.sdk.download=Download New SDK (Windows Only) +slt.ui.settings.sdk.remove=Remove SDK slt.ui.settings.sdk.editor.title.new=New Common Lisp SDK slt.ui.settings.sdk.editor.title.edit=Editing Common Lisp SDK -slt.ui.settings.sdk.editor.verify=Verify SBCL SDK +slt.ui.settings.sdk.editor.sbcl.process.verify=Verify SBCL SDK slt.ui.settings.sdk.editor.save=Save slt.ui.settings.sdk.editor.name=SDK name slt.ui.settings.sdk.editor.name.default=SBCL -slt.ui.settings.sdk.editor.executable=SBCL executable +slt.ui.settings.sdk.editor.sbcl.process.executable=SBCL executable slt.ui.settings.sdk.editor.executable.select=Please Select SBCL Executable -slt.ui.settings.sdk.editor.core=SBCL core (optional) +slt.ui.settings.sdk.editor.sbcl.process.core=SBCL core (optional) slt.ui.settings.sdk.editor.core.select=Please Select SBCL Core slt.ui.settings.sdk.editor.quicklisp=SBCL quicklisp path # suppress inspection "GrazieInspection" slt.ui.settings.sdk.editor.quicklisp.select=Please Select Quicklisp setup.lisp File slt.ui.settings.sdk.editor.notverified.title=Verification required -slt.ui.settings.sdk.editor.notverified.message=Please Verify SBCL SDK +slt.ui.settings.sdk.editor.sbcl.process.notverified.message=Please Verify SBCL SDK slt.ui.settings.sdk.editor.verifying=Verifying SBCL SDK slt.ui.settings.sdk.editor.verifying.cancel=Cancel Verification -slt.ui.settings.sdk.editor.verifying.error=Failed to verify SBCL installation +slt.ui.settings.sdk.editor.sbcl.process.verifying.error=Failed to verify SBCL installation slt.ui.settings.sdk.editor.verifying.error.title=Failed -slt.ui.settings.sdk.download.downloading=Downloading SBCL +slt.ui.settings.sdk.download.sbcl.downloading=Downloading SBCL slt.ui.settings.sdk.download.cancel=Cancel slt.ui.settings.sdk.download.downloading.quicklisp.title=Downloading quicklisp slt.ui.settings.sdk.download.installing.quicklisp.title=Installing quicklisp -slt.ui.settings.sdk.download.failed=Failed to automatically download and install SBCL. Please try manual installation! +slt.ui.settings.sdk.download.failed=Failed to automatically download and install SDK. Please try manual installation! slt.ui.settings.sdk.download.failed.title=Failed slt.ui.settings.indent.name=Common Lisp Indentation slt.ui.settings.indent.project.name=Common Lisp Indentation (Project) From 732728ad87e3b5210048c5f6ec7138aad3822495 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Wed, 1 Feb 2023 00:03:59 +0100 Subject: [PATCH 06/21] shitton of optimizations, jfc --- .../slt/plugin/SltDocumentationProvider.java | 27 +++- .../com/en_circle/slt/plugin/SymbolState.java | 5 - .../autocomplete/HeadCompletionProvider.java | 2 +- .../slt/plugin/environment/Environment.java | 8 +- .../annotators/SymbolAnnotator.java | 66 ++++++++- .../plugin/lisp/LispSymbolPresentation.java | 2 +- .../references/SltLazyElementResolve.java | 27 ++++ .../slt/plugin/references/SltReference.java | 27 +++- .../services/lisp/LispEnvironmentService.java | 7 +- .../lisp/LispEnvironmentServiceImpl.java | 78 +++++----- .../SltLispEnvironmentSymbolCache.java | 137 ++++++++++++------ .../slt/plugin/swank/SlimeListener.java | 3 +- .../slt/plugin/ui/SltGeneralLog.java | 3 + .../en_circle/slt/tools/BufferedString.java | 12 +- .../en_circle/slt/tools/LocationUtils.java | 13 +- .../slt/tools/SltApplicationUtils.java | 22 ++- src/main/lisp/load.lisp | 26 +++- src/main/lisp/slt/slt.lisp | 5 +- src/main/lisp/swank/swank-sbcl.lisp | 29 +++- src/main/lisp/swank/swank.lisp | 4 +- src/main/resources/META-INF/plugin.xml | 3 +- 21 files changed, 377 insertions(+), 129 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/references/SltLazyElementResolve.java diff --git a/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java b/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java index fb8d856..ae7cd00 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java +++ b/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java @@ -4,7 +4,6 @@ import com.en_circle.slt.plugin.lisp.LispParserUtil; import com.en_circle.slt.plugin.lisp.psi.LispList; import com.en_circle.slt.plugin.lisp.psi.LispSymbol; -import com.en_circle.slt.plugin.lisp.psi.impl.LispPsiImplUtil; import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.intellij.lang.documentation.AbstractDocumentationProvider; import com.intellij.openapi.util.text.HtmlBuilder; @@ -20,12 +19,15 @@ public class SltDocumentationProvider extends AbstractDocumentationProvider { @Override public @Nullable @Nls String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) { if (originalElement != null) - element = originalElement; + element = decideOnElement(element, originalElement); - String text = LispPsiImplUtil.getSExpressionHead(element); - if (text != null) { + if (!(element instanceof LispSymbol)) + element = PsiTreeUtil.getParentOfType(element, LispSymbol.class); + + if (element instanceof LispSymbol) { + String text = ((LispSymbol) element).getName(); String packageName = LispParserUtil.getPackage(element); - SymbolState state = LispEnvironmentService.getInstance(element.getProject()).refreshSymbolFromServer(packageName, text, element); + SymbolState state = LispEnvironmentService.getInstance(element.getProject()).refreshSymbolFromServer(packageName, text); switch (state.binding) { case NONE: return SltBundle.message("slt.documentation.types.symbol") + " " + text; @@ -53,19 +55,28 @@ public class SltDocumentationProvider extends AbstractDocumentationProvider { @Override public @Nullable @Nls String generateDoc(PsiElement element, @Nullable PsiElement originalElement) { if (originalElement != null) - element = originalElement; + element = decideOnElement(element, originalElement); - element = PsiTreeUtil.getParentOfType(element, LispSymbol.class); + if (!(element instanceof LispSymbol)) + element = PsiTreeUtil.getParentOfType(element, LispSymbol.class); if (element != null) { String text = element.getText(); String packageName = LispParserUtil.getPackage(element); - SymbolState state = LispEnvironmentService.getInstance(element.getProject()).refreshSymbolFromServer(packageName, text, element); + SymbolState state = LispEnvironmentService.getInstance(element.getProject()).refreshSymbolFromServer(packageName, text); return asHtml(state, packageName, element); } return null; } + private PsiElement decideOnElement(PsiElement element, PsiElement originalElement) { + if (element == null) + return originalElement; + if (element instanceof LispSymbol) + return element; + return originalElement; + } + private String asHtml(SymbolState state, String packageName, PsiElement element) { HtmlBuilder builder = new HtmlBuilder(); String documentation = StringUtils.replace(StringUtils.replace(state.documentation, " ", " "), diff --git a/src/main/java/com/en_circle/slt/plugin/SymbolState.java b/src/main/java/com/en_circle/slt/plugin/SymbolState.java index 63717b3..d3b02c0 100644 --- a/src/main/java/com/en_circle/slt/plugin/SymbolState.java +++ b/src/main/java/com/en_circle/slt/plugin/SymbolState.java @@ -1,12 +1,8 @@ package com.en_circle.slt.plugin; import com.en_circle.slt.plugin.swank.components.SourceLocation; -import com.intellij.openapi.vfs.VirtualFile; -import java.lang.ref.WeakReference; -import java.util.HashSet; import java.util.Objects; -import java.util.Set; public class SymbolState { @@ -17,7 +13,6 @@ public class SymbolState { public SymbolBinding binding = SymbolBinding.NONE; public String documentation; - public Set> containerFiles = new HashSet<>(); public SourceLocation location = new SourceLocation(); public SymbolState(String name, String packageName, String symbolName) { diff --git a/src/main/java/com/en_circle/slt/plugin/autocomplete/HeadCompletionProvider.java b/src/main/java/com/en_circle/slt/plugin/autocomplete/HeadCompletionProvider.java index 8a2d538..fbcbadf 100644 --- a/src/main/java/com/en_circle/slt/plugin/autocomplete/HeadCompletionProvider.java +++ b/src/main/java/com/en_circle/slt/plugin/autocomplete/HeadCompletionProvider.java @@ -40,7 +40,7 @@ protected void addCompletions(@NotNull CompletionParameters parameters, @NotNull for (LispElement element : innerList.getItems()) { if (element instanceof LispString str) { SymbolState state = LispEnvironmentService.getInstance(project) - .refreshSymbolFromServer(null, str.getValue(), null); + .refreshSymbolFromServer(null, str.getValue()); LookupElementBuilder builder = LookupElementBuilder.create(str.getValue()); if (state.binding == SymbolBinding.MACRO) { builder = builder.withIcon(Nodes.Template); diff --git a/src/main/java/com/en_circle/slt/plugin/environment/Environment.java b/src/main/java/com/en_circle/slt/plugin/environment/Environment.java index dfc5545..85d6595 100644 --- a/src/main/java/com/en_circle/slt/plugin/environment/Environment.java +++ b/src/main/java/com/en_circle/slt/plugin/environment/Environment.java @@ -5,9 +5,9 @@ import com.en_circle.slt.plugin.sdk.LispSdk; import com.en_circle.slt.plugin.ui.sdk.SdkConfigurationSBCLProcess; import com.en_circle.slt.plugin.ui.sdk.SdkDialogProvider; -import com.en_circle.slt.tools.ProjectUtils; import com.en_circle.slt.tools.platform.DownloadLispAction; import com.en_circle.slt.tools.platform.DownloadSBCLAction; +import com.intellij.openapi.project.Project; import java.util.function.Supplier; @@ -32,12 +32,12 @@ public Supplier getEnvironmentCreator() { @SuppressWarnings("unchecked") @Override public , R extends SltLispEnvironmentConfiguration> - SltLispEnvironmentConfiguration.Builder buildConfiguration(LispSdk sdk) { + SltLispEnvironmentConfiguration.Builder buildConfiguration(LispSdk sdk, Project project) { return (Builder) new SltSBCLEnvironmentConfiguration.Builder() .setExecutable(sdk.sbclExecutable) .setCore(sdk.sbclCorePath) .setQuicklispStartScriptPath(sdk.quickLispPath) - .setProjectDirectory(ProjectUtils.getCurrentProject().getBasePath()); + .setProjectDirectory(project.getBasePath()); } @Override @@ -64,7 +64,7 @@ public static abstract class EnvironmentDefinition { public abstract Class getDownloadActionDef(); public abstract Supplier getEnvironmentCreator(); public abstract , R extends SltLispEnvironmentConfiguration> - SltLispEnvironmentConfiguration.Builder buildConfiguration(LispSdk sdk); + SltLispEnvironmentConfiguration.Builder buildConfiguration(LispSdk sdk, Project project); public abstract SdkDialogProvider getDialogProvider(); } diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java index 1c8d847..61c890b 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java @@ -2,24 +2,70 @@ import com.en_circle.slt.plugin.SymbolState; import com.en_circle.slt.plugin.highlights.SltHighlighterColors; +import com.en_circle.slt.plugin.highlights.annotators.SymbolAnnotator.AnnotationResult; import com.en_circle.slt.plugin.lisp.LispParserUtil; import com.en_circle.slt.plugin.lisp.psi.LispSymbol; +import com.en_circle.slt.plugin.lisp.psi.LispVisitor; import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; +import com.en_circle.slt.plugin.services.lisp.components.SltLispEnvironmentSymbolCache.BatchedSymbolRefreshAction; import com.intellij.lang.annotation.AnnotationHolder; -import com.intellij.lang.annotation.Annotator; +import com.intellij.lang.annotation.ExternalAnnotator; +import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -public class SymbolAnnotator implements Annotator { +public class SymbolAnnotator extends ExternalAnnotator { @Override - public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { - if (element instanceof LispSymbol) { - String text = element.getText(); - String packageName = LispParserUtil.getPackage(element); - SymbolState state = LispEnvironmentService.getInstance(element.getProject()).refreshSymbolFromServer(packageName, text, element); - setHighlight(element, text, holder, state); + public @Nullable BatchedSymbolRefreshAction collectInformation(@NotNull PsiFile file, @NotNull Editor editor, boolean hasErrors) { + BatchedSymbolRefreshAction holder = LispEnvironmentService.getInstance(file.getProject()).refreshSymbolsFromServer(); + + file.accept(new LispVisitor() { + + @Override + public void visitSymbol(@NotNull LispSymbol element) { + String text = element.getText(); + String packageName = LispParserUtil.getPackage(element); + holder.add(text, packageName); + } + + @Override + public void visitElement(@NotNull PsiElement element) { + element.acceptChildren(this); + } + }); + + return holder; + } + + @Override + public @Nullable AnnotationResult doAnnotate(BatchedSymbolRefreshAction collectedInfo) { + if (collectedInfo != null) { + boolean result = collectedInfo.getResult(); + return result ? AnnotationResult.OK : AnnotationResult.FAILED; } + return AnnotationResult.FAILED; + } + + @Override + public void apply(@NotNull PsiFile file, AnnotationResult annotationResult, @NotNull AnnotationHolder holder) { + file.accept(new LispVisitor() { + + @Override + public void visitSymbol(@NotNull LispSymbol element) { + String text = element.getText(); + String packageName = LispParserUtil.getPackage(element); + SymbolState state = LispEnvironmentService.getInstance(element.getProject()).refreshSymbolFromServer(packageName, text); + setHighlight(element, text, holder, state); + } + + @Override + public void visitElement(@NotNull PsiElement element) { + element.acceptChildren(this); + } + }); } private void setHighlight(PsiElement element, String name, AnnotationHolder holder, SymbolState state) { @@ -64,4 +110,8 @@ private void setHighlight(PsiElement element, String name, AnnotationHolder hold break; } } + + public enum AnnotationResult { + OK, FAILED + } } diff --git a/src/main/java/com/en_circle/slt/plugin/lisp/LispSymbolPresentation.java b/src/main/java/com/en_circle/slt/plugin/lisp/LispSymbolPresentation.java index 68de30b..2d9331e 100644 --- a/src/main/java/com/en_circle/slt/plugin/lisp/LispSymbolPresentation.java +++ b/src/main/java/com/en_circle/slt/plugin/lisp/LispSymbolPresentation.java @@ -29,7 +29,7 @@ public LispSymbolPresentation(com.en_circle.slt.plugin.lisp.psi.LispSymbol symbo private SymbolState refreshState() { return LispEnvironmentService.getInstance(symbol.getProject()) - .refreshSymbolFromServer(packageName, symbol.getName(), symbol); + .refreshSymbolFromServer(packageName, symbol.getName()); } @Override diff --git a/src/main/java/com/en_circle/slt/plugin/references/SltLazyElementResolve.java b/src/main/java/com/en_circle/slt/plugin/references/SltLazyElementResolve.java new file mode 100644 index 0000000..093856e --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/references/SltLazyElementResolve.java @@ -0,0 +1,27 @@ +package com.en_circle.slt.plugin.references; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.ResolveResult; +import org.jetbrains.annotations.Nullable; + +public class SltLazyElementResolve implements ResolveResult { + + private final PsiFile file; + private final int offset; + + public SltLazyElementResolve(PsiFile file, int offset) { + this.file = file; + this.offset = offset; + } + + @Override + public @Nullable PsiElement getElement() { + return file.findElementAt(offset); + } + + @Override + public boolean isValidResult() { + return false; + } +} diff --git a/src/main/java/com/en_circle/slt/plugin/references/SltReference.java b/src/main/java/com/en_circle/slt/plugin/references/SltReference.java index 5235ee6..bf97784 100644 --- a/src/main/java/com/en_circle/slt/plugin/references/SltReference.java +++ b/src/main/java/com/en_circle/slt/plugin/references/SltReference.java @@ -11,13 +11,14 @@ import com.en_circle.slt.plugin.swank.components.SourceLocation; import com.en_circle.slt.plugin.swank.requests.Xrefs; import com.en_circle.slt.plugin.swank.requests.Xrefs.XrefType; -import com.en_circle.slt.tools.LocationUtils; import com.en_circle.slt.tools.SltApplicationUtils; import com.intellij.lang.ASTNode; import com.intellij.lang.FileASTNode; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; @@ -48,18 +49,27 @@ ResolveResult[] resolveInner(boolean incompleteCode) { String symbolName = myElement.getName(); String packageName = LispParserUtil.getPackage(myElement); - SymbolState state = LispEnvironmentService.getInstance(myElement.getProject()).refreshSymbolFromServer(packageName, symbolName, myElement); + SymbolState state = LispEnvironmentService.getInstance(myElement.getProject()).refreshSymbolFromServer(packageName, symbolName); SourceLocation location = state.location; LispToplevel topLevel = PsiTreeUtil.getParentOfType(myElement, LispToplevel.class); if (location.isFile()) { VirtualFile vf = LocalFileSystem.getInstance().findFileByIoFile(new File(location.getLocation())); if (vf != null) { - PsiFile file = PsiManager.getInstance(myElement.getProject()).findFile(vf); + CachedValuesManager cachedValuesManager = CachedValuesManager.getManager(myElement.getProject()); + PsiFile file = cachedValuesManager.createCachedValue(() -> { + PsiFile f = PsiManager.getInstance(myElement.getProject()).findFile(vf); + if (f != null) { + FileASTNode node = f.getNode(); + node.getFirstChildNode(); + } + return CachedValueProvider.Result.create(f, vf); + }).getValue(); if (file != null) { FileASTNode node = file.getNode(); if (node != null) { ASTNode reference = node.findLeafElementAt(location.getPosition()); + if (reference != null) { PsiElement referenceElement = reference.getPsi(); if (referenceElement != null) { @@ -178,8 +188,15 @@ private ResolveResult[] gatherReferences(LispElement form) { } private ResolveResult convertLocationToReference(SourceLocation location, String name) { - return LocationUtils.convertFromLocationToSymbol(myElement.getProject(), location, name, - PsiElementResolveResult::new); + if (!location.isPrecise()) + return null; + VirtualFile vf = LocalFileSystem.getInstance().findFileByIoFile(new File(location.getLocation())); + if (vf == null) + return null; + PsiFile f = PsiManager.getInstance(myElement.getProject()).findFile(vf); + if (f == null) + return null; + return new SltLazyElementResolve(f, location.getPosition()); } @Override diff --git a/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentService.java b/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentService.java index 56f7f80..a39c316 100644 --- a/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentService.java +++ b/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentService.java @@ -5,6 +5,7 @@ import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltLispOutputChangedListener; import com.en_circle.slt.plugin.lisp.lisp.LispElement; import com.en_circle.slt.plugin.lisp.psi.LispList; +import com.en_circle.slt.plugin.services.lisp.components.SltLispEnvironmentSymbolCache.BatchedSymbolRefreshAction; import com.en_circle.slt.plugin.swank.SlimeListener.DebugInterface; import com.en_circle.slt.plugin.swank.SlimeListener.RequestResponseLogger; import com.en_circle.slt.plugin.swank.SlimeRequest; @@ -36,9 +37,13 @@ static LispEnvironmentService getInstance(Project project) { void sendToLisp(SlimeRequest request, boolean startServer) throws Exception; + void sendToLisp(SlimeRequest request, boolean startServer, Runnable onFailureServerState) throws Exception; + String getGlobalPackage(); - SymbolState refreshSymbolFromServer(String packageName, String symbolName, PsiElement element); + SymbolState refreshSymbolFromServer(String packageName, String symbolName); + + BatchedSymbolRefreshAction refreshSymbolsFromServer(); LispEnvironmentState getState(); diff --git a/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java b/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java index 6860c74..fd78b22 100644 --- a/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java +++ b/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java @@ -5,7 +5,6 @@ import com.en_circle.slt.plugin.environment.SltLispEnvironment; import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; import com.en_circle.slt.plugin.environment.SltLispEnvironmentConfiguration; -import com.en_circle.slt.plugin.environment.SltProcessException; import com.en_circle.slt.plugin.lisp.lisp.LispContainer; import com.en_circle.slt.plugin.lisp.lisp.LispElement; import com.en_circle.slt.plugin.lisp.psi.LispList; @@ -15,12 +14,13 @@ import com.en_circle.slt.plugin.services.lisp.components.SltIndentationContainer; import com.en_circle.slt.plugin.services.lisp.components.SltLispEnvironmentMacroExpandCache; import com.en_circle.slt.plugin.services.lisp.components.SltLispEnvironmentSymbolCache; +import com.en_circle.slt.plugin.services.lisp.components.SltLispEnvironmentSymbolCache.BatchedSymbolRefreshAction; import com.en_circle.slt.plugin.swank.SlimeListener; import com.en_circle.slt.plugin.swank.SlimeListener.DebugInterface; import com.en_circle.slt.plugin.swank.SlimeListener.RequestResponseLogger; import com.en_circle.slt.plugin.swank.SlimeRequest; import com.en_circle.slt.plugin.swank.SwankClient; -import com.en_circle.slt.tools.ProjectUtils; +import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; @@ -81,7 +81,7 @@ public boolean configured() { } environmentProvider = sdk.getEnvironment().getDefinition().getEnvironmentCreator(); - configurationBuilder = sdk.getEnvironment().getDefinition().buildConfiguration(sdk); + configurationBuilder = sdk.getEnvironment().getDefinition().buildConfiguration(sdk, project); // TODO: add UI resolve actions here @@ -112,13 +112,13 @@ public void start() { doStart(); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(ProjectUtils.getCurrentProject(), e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); } }); } private void ensureToolWindowIsOpen() { - ToolWindow toolWindow = ToolWindowManager.getInstance(ProjectUtils.getCurrentProject()) + ToolWindow toolWindow = ToolWindowManager.getInstance(project) .getToolWindow("Common Lisp"); assert toolWindow != null; toolWindow.show(); @@ -130,7 +130,7 @@ public void stop() { doStop(); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstop"), e); - Messages.showErrorDialog(ProjectUtils.getCurrentProject(), e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.stop")); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.stop")); } } @@ -139,7 +139,7 @@ private boolean doStart() throws Exception { if (configurationBuilder == null) { if (!configured()) { log.warn(SltBundle.message("slt.error.sbclstart")); - Messages.showErrorDialog(ProjectUtils.getCurrentProject(), + Messages.showErrorDialog(project, SltBundle.message("slt.ui.errors.sbcl.start.noconf"), SltBundle.message("slt.ui.errors.sbcl.start")); return false; @@ -158,12 +158,14 @@ private boolean doStart() throws Exception { environment = environmentProvider.get(); environment.start(configuration); - slimeListener = new SlimeListener(ProjectUtils.getCurrentProject(), true, logger, debugInterface); + slimeListener = new SlimeListener(project, true, logger, debugInterface); client = new SwankClient("127.0.0.1", environment.getSwankPort(), slimeListener); for (LispEnvironmentListener listener : serverListeners) { listener.onPostStart(); } + + DaemonCodeAnalyzer.getInstance(project).restart(); } finally { starting = false; } @@ -204,33 +206,38 @@ public void sendToLisp(SlimeRequest request) throws Exception { @Override public void sendToLisp(SlimeRequest request, boolean startServer) throws Exception { - if (startServer && environment == null || !environment.isActive()) { - ApplicationManager.getApplication().invokeLater(() -> { - starting = true; + sendToLisp(request, startServer, null); + } + + @Override + public void sendToLisp(SlimeRequest request, boolean startServer, Runnable onFailureServerState) throws Exception { + if (environment == null || !environment.isActive()) { + if (startServer) { ApplicationManager.getApplication().invokeLater(() -> { - try { - ensureToolWindowIsOpen(); - if (!doStart()) { - return; + starting = true; + ApplicationManager.getApplication().invokeLater(() -> { + try { + ensureToolWindowIsOpen(); + if (!doStart()) { + if (onFailureServerState != null) + onFailureServerState.run(); + return; + } + + doSend(request); + } catch (Exception e) { + log.warn(SltBundle.message("slt.error.sbclstart"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); } - - doSend(request); - } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(ProjectUtils.getCurrentProject(), e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); - } + }); }); - }); - return; - } - - if (environment == null || !environment.isActive()) { - if (!startServer) - return; // ignored - throw new SltProcessException("server offline"); + } else { + if (onFailureServerState != null) + onFailureServerState.run(); + } + } else { + doSend(request); } - - doSend(request); } private void doSend(SlimeRequest request) { @@ -245,8 +252,13 @@ public String getGlobalPackage() { } @Override - public SymbolState refreshSymbolFromServer(String packageName, String symbolName, PsiElement element) { - return symbolCache.refreshSymbolFromServer(packageName, symbolName, element); + public SymbolState refreshSymbolFromServer(String packageName, String symbolName) { + return symbolCache.refreshSymbolFromServer(packageName, symbolName); + } + + @Override + public BatchedSymbolRefreshAction refreshSymbolsFromServer() { + return symbolCache.createNewBatch(); } @Override diff --git a/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java b/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java index 493002f..8582669 100644 --- a/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java +++ b/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java @@ -7,21 +7,22 @@ import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentState; import com.en_circle.slt.plugin.swank.components.SourceLocation; import com.en_circle.slt.plugin.swank.requests.EvalAndGrab; +import com.en_circle.slt.tools.SltApplicationUtils; import com.google.common.collect.Lists; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiElement; -import com.intellij.util.FileContentUtilCore; +import com.intellij.util.Consumer; +import com.intellij.util.concurrency.FutureResult; import org.apache.commons.lang3.StringUtils; -import java.lang.ref.WeakReference; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import java.util.stream.Collectors; public class SltLispEnvironmentSymbolCache extends Thread { + // TODO: Rewrite with events, if possible + private final Map symbolInformation = Collections.synchronizedMap(new HashMap<>()); private final List symbolRefreshQueue = Collections.synchronizedList(new ArrayList<>()); @@ -66,12 +67,9 @@ public void terminate() { active = false; } - public SymbolState refreshSymbolFromServer(String packageName, String symbolName, PsiElement element) { + public SymbolState refreshSymbolFromServer(String packageName, String symbolName) { SymbolState state = getOrCreateBinding(packageName, symbolName); SymbolState undefinedSymbol = getOrCreateBinding(null, symbolName); - if (element != null) { - state.containerFiles.add(new WeakReference<>(element.getContainingFile().getVirtualFile())); - } SymbolBinding currentBinding = state.binding; if (currentBinding == SymbolBinding.NONE) { symbolRefreshQueue.add(state); @@ -85,6 +83,51 @@ public SymbolState refreshSymbolFromServer(String packageName, String symbolName return state; } + private void refreshBatchedSymbols(BatchedSymbolRefreshAction action, Consumer onFinish) { + HashSet duplicityState = new HashSet<>(); + List withoutDuplicity = action.states.stream() + .filter(s -> { + boolean isDuplicit = duplicityState.contains(s); + duplicityState.add(s); + return !isDuplicit; + }).filter(this::removeBad).collect(Collectors.toList()); + + try { + if (LispEnvironmentService.getInstance(project).getState() == LispEnvironmentState.READY) { + refreshSymbolsBatched(withoutDuplicity, onFinish); + } else { + onFinish.consume(true); + } + } catch (Exception e) { + onFinish.consume(false); + } + +// List> batched = new ArrayList<>(Lists.partition(withoutDuplicity, 500)); +// List> futures = new ArrayList<>(); +// for (List batch : batched) { +// CompletableFuture future = new CompletableFuture<>(); +// ApplicationManager.getApplication().executeOnPooledThread(() -> { +// try { +// refreshSymbolsBatched(batch, future); +// } catch (Exception e) { +// throw new RuntimeException(e); +// } +// }); +// futures.add(future); +// } +// +// boolean success = true; +// for (Future future : futures) { +// try { +// future.get(120, TimeUnit.SECONDS); +// } catch (Exception e) { +// success = false; +// } +// } +// +// onFinish.consume(success); + } + private SymbolState getOrCreateBinding(String packageName, String symbolName) { if (symbolName.contains("::")) { String[] parts = symbolName.split(Pattern.quote("::")); @@ -135,6 +178,10 @@ private boolean removeBad(SymbolState symbolState) { } private void refreshSymbolsBatched(List refreshStates) throws Exception { + refreshSymbolsBatched(refreshStates, null); + } + + private void refreshSymbolsBatched(List refreshStates, Consumer requestFinished) throws Exception { String request = "(" + refreshStates.stream().map(x -> x.name.toUpperCase() + " ").collect(Collectors.joining()) + ")"; request = StringUtils.replace(request, "\"", "\\\""); @@ -144,7 +191,6 @@ private void refreshSymbolsBatched(List refreshStates) throws Excep "(slt-core:analyze-symbols (slt-core:read-fix-packages \"%s\"))", request), LispEnvironmentService.getInstance(project).getGlobalPackage(), true, (result, stdout, parsed) -> { - Set toRefresh = new HashSet<>(); if (parsed.size() == 1 && parsed.get(0).getType() == LispElementType.CONTAINER) { int ix = 0; LispContainer data = (LispContainer) parsed.get(0); @@ -160,84 +206,59 @@ private void refreshSymbolsBatched(List refreshStates) throws Excep SymbolState state = refreshStates.get(ix++); if (state != null) { String symValue = ((LispSymbol) list.getItems().get(1)).getValue().toUpperCase(); - boolean changed = false; state.timestamp = System.currentTimeMillis(); switch (symValue) { case ":CLASS": - changed |= state.binding != SymbolBinding.CLASS; state.binding = SymbolBinding.CLASS; break; case ":METHOD": - changed |= state.binding != SymbolBinding.METHOD; state.binding = SymbolBinding.METHOD; break; case ":SPECIAL-FORM": - changed |= state.binding != SymbolBinding.SPECIAL_FORM; state.binding = SymbolBinding.SPECIAL_FORM; break; case ":MACRO": - changed |= state.binding != SymbolBinding.MACRO; state.binding = SymbolBinding.MACRO; break; case ":FUNCTION": - changed |= state.binding != SymbolBinding.FUNCTION; state.binding = SymbolBinding.FUNCTION; break; case ":CONSTANT": - changed |= state.binding != SymbolBinding.CONSTANT; state.binding = SymbolBinding.CONSTANT; break; case ":KEYWORD": - changed |= state.binding != SymbolBinding.KEYWORD; state.binding = SymbolBinding.KEYWORD; break; case ":SPECIAL": - changed |= state.binding != SymbolBinding.SPECIAL_VARIABLE; state.binding = SymbolBinding.SPECIAL_VARIABLE; break; default: - changed |= state.binding != SymbolBinding.NONE; state.binding = SymbolBinding.NONE; break; } - boolean hasDoc = state.documentation != null; state.documentation = null; if (list.getItems().get(2) instanceof LispString) { state.documentation = ((LispString) list.getItems().get(2)).getValue(); - if (!hasDoc) { - changed = true; - } } if (list.getItems().get(3) instanceof LispContainer) { SourceLocation location = new SourceLocation((LispContainer) list.getItems().get(3)); if (!state.location.equals(location)) { state.location = location; - changed = true; } } - - if (changed) { - for (WeakReference wvf : state.containerFiles) { - VirtualFile vf = wvf.get(); - if (vf != null) { - toRefresh.add(vf); - } - } - state.containerFiles.clear(); - } } } } - if (!toRefresh.isEmpty()) { - ApplicationManager.getApplication().invokeLater(() -> { - for (VirtualFile vf : toRefresh) { - FileContentUtilCore.reparseFiles(vf); - } - }); + if (requestFinished != null) { + requestFinished.consume(true); } - }), false); + }), false, () -> { + if (requestFinished != null) { + requestFinished.consume(false); + } + }); } public void clear() { @@ -245,4 +266,36 @@ public void clear() { symbolRefreshQueue.clear(); } + public BatchedSymbolRefreshAction createNewBatch() { + return new BatchedSymbolRefreshAction(); + } + + public class BatchedSymbolRefreshAction { + + private final List states = new ArrayList<>(); + + public BatchedSymbolRefreshAction() { + + } + + public boolean getResult() { + return SltApplicationUtils.processAsync(() -> { + FutureResult waitForResult = new FutureResult<>(); + refreshBatchedSymbols(this, waitForResult::set); + try { + return waitForResult.get(200, TimeUnit.SECONDS); + } catch (Exception e) { + return false; + } + }); + } + + public void add(String name, String packageName) { + states.add(getOrCreateBinding(packageName, name)); + states.add(getOrCreateBinding(null, name)); + } + + } + + } diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java index 4edbbc5..d9a3126 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java @@ -54,7 +54,8 @@ public void onSwankMessage(SwankPacket packet) { String data = packet.getSentData(); if (fromUi) { - ApplicationManager.getApplication().invokeLater(() -> resolve(data)); + ApplicationManager.getApplication().executeOnPooledThread(() -> + ApplicationManager.getApplication().runReadAction(() -> resolve(data))); } else { resolve(data); } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/SltGeneralLog.java b/src/main/java/com/en_circle/slt/plugin/ui/SltGeneralLog.java index 741411c..16ac410 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/SltGeneralLog.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/SltGeneralLog.java @@ -8,6 +8,7 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.tabs.TabInfo; +import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -131,11 +132,13 @@ public String getTitle() { @Override public void logRequest(String request) { + request = StringUtils.truncate(request, 0, 4069); bufferedString.append("\n\n" + request); } @Override public void logResponse(String response) { + response = StringUtils.truncate(response, 0, 4069); bufferedString.append("\n\n" + response); } } diff --git a/src/main/java/com/en_circle/slt/tools/BufferedString.java b/src/main/java/com/en_circle/slt/tools/BufferedString.java index 6c08127..c97d8c1 100644 --- a/src/main/java/com/en_circle/slt/tools/BufferedString.java +++ b/src/main/java/com/en_circle/slt/tools/BufferedString.java @@ -18,7 +18,7 @@ public BufferedString(Consumer simpleAdd, Consumer completeReset this.completeReset = completeReset; } - public void append(String data) { + public synchronized void append(String data) { int len = data.length(); chunks.add(data); size += len; @@ -48,26 +48,26 @@ private void truncateAndSet() { completeReset.accept(toString()); } - public void clear() { + public synchronized void clear() { clearNoCall(); completeReset.accept(""); } - public void clearNoCall() { + public synchronized void clearNoCall() { chunks.clear(); size = 0; } @Override - public String toString() { + public synchronized String toString() { return chunks.stream().filter(Objects::nonNull).collect(Collectors.joining("")); } - public int getMaxSize() { + public synchronized int getMaxSize() { return maxSize; } - public void setMaxSize(int maxSize) { + public synchronized void setMaxSize(int maxSize) { this.maxSize = maxSize; } } diff --git a/src/main/java/com/en_circle/slt/tools/LocationUtils.java b/src/main/java/com/en_circle/slt/tools/LocationUtils.java index 16b2ab6..3662cc8 100644 --- a/src/main/java/com/en_circle/slt/tools/LocationUtils.java +++ b/src/main/java/com/en_circle/slt/tools/LocationUtils.java @@ -11,6 +11,8 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiTreeUtil; import java.io.File; @@ -23,11 +25,20 @@ public static X convertFromLocationToSymbol(Project project, SourceLocation if (location.isFile()) { VirtualFile vf = LocalFileSystem.getInstance().findFileByIoFile(new File(location.getLocation())); if (vf != null) { - PsiFile file = PsiManager.getInstance(project).findFile(vf); + CachedValuesManager cachedValuesManager = CachedValuesManager.getManager(project); + PsiFile file = cachedValuesManager.createCachedValue(() -> { + PsiFile f = PsiManager.getInstance(project).findFile(vf); + if (f != null) { + FileASTNode node = f.getNode(); + node.getFirstChildNode(); + } + return CachedValueProvider.Result.create(f, vf); + }).getValue(); if (file != null) { FileASTNode node = file.getNode(); if (node != null) { ASTNode reference = node.findLeafElementAt(location.getPosition()); + if (reference != null) { PsiElement referenceElement = reference.getPsi(); LispSymbol ls = PsiTreeUtil.getParentOfType(referenceElement, LispSymbol.class); diff --git a/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java b/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java index 03f8b98..2377cae 100644 --- a/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java +++ b/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java @@ -9,6 +9,7 @@ import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; import org.awaitility.Awaitility; import org.awaitility.core.ConditionTimeoutException; import org.awaitility.pollinterval.FixedPollInterval; @@ -59,13 +60,15 @@ public static Future getAsyncResultNoProgress(Project project, Function { BlockingQueue pointer = new ArrayBlockingQueue<>(1); - SlimeRequest r = request.apply(result -> { - try { - pointer.put(result); - } catch (Exception ignored) { + SlimeRequest r = request.apply(result -> + ApplicationManager.getApplication().invokeLater(() -> + ApplicationManager.getApplication().runWriteAction(() -> { + try { + pointer.put(result); + } catch (Exception ignored) { - } - }); + } + }))); LispEnvironmentService.getInstance(project).sendToLisp(r, startLisp); try { Awaitility.await() @@ -97,4 +100,11 @@ public static X getAsyncResultCheckCancellation(Project project, Function T processAsync(Computable supplier) { + try { + return ApplicationManager.getApplication().executeOnPooledThread(supplier::get).get(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } } diff --git a/src/main/lisp/load.lisp b/src/main/lisp/load.lisp index bc54223..e7606fe 100644 --- a/src/main/lisp/load.lisp +++ b/src/main/lisp/load.lisp @@ -1,13 +1,35 @@ (format T "SLT Interpret ~S~%" +slt-interpret+) +(defun quit (&optional code) + ;; This group from "clocc-port/ext.lisp" + #+allegro (excl:exit code) + #+clisp (#+lisp=cl ext:quit #-lisp=cl lisp:quit code) + #+cmu (ext:quit code) + #+cormanlisp (win32:exitprocess code) + #+gcl (lisp:bye code) ; XXX Or is it LISP::QUIT? + #+lispworks (lw:quit :status code) + #+lucid (lcl:quit code) + #+sbcl (sb-ext:exit :code code) + ;; This group from Maxima + #+kcl (lisp::bye) ; XXX Does this take an arg? + #+scl (ext:quit code) ; XXX Pretty sure this *does*. + #+(or openmcl mcl) (ccl::quit) + #+abcl (cl-user::quit) + #+ecl (si:quit) + ;; This group from + #+poplog (poplog::bye) ; XXX Does this take an arg? + #-(or allegro clisp cmu cormanlisp gcl lispworks lucid sbc + kcl scl openmcl mcl abcl ecl) + (error 'not-implemented :proc (list 'quit code))) + (case +slt-interpret+ (:sbcl (unless (string= "SBCL" (lisp-implementation-type)) (format *error-output* "Invalid lisp instance. Maybe a configuration error? This is not SBCL!~%") - (exit 1))) + (quit 1))) (otherwise (format *error-output* "Unsupported lisp instance. Maybe a configuration error?~%") - (exit 1))) + (quit 1))) (load (merge-pathnames "swank/swank.lisp" *load-truename*)) (load (merge-pathnames "slt/slt.lisp" *load-truename*)) diff --git a/src/main/lisp/slt/slt.lisp b/src/main/lisp/slt/slt.lisp index 4fcd590..a6b59d9 100644 --- a/src/main/lisp/slt/slt.lisp +++ b/src/main/lisp/slt/slt.lisp @@ -11,8 +11,7 @@ (defun analyze-symbol (test-sym) (cons test-sym - (let ((*standard-output* (make-string-output-stream)) - (swank::*source-snippet-size* 0)) + (let ((*standard-output* (make-string-output-stream))) (cond ((not test-sym) (list NIL NIL NIL)) ((and (fboundp test-sym) @@ -80,6 +79,8 @@ #'reader-recover) (ECLECTOR.READER:PACKAGE-DOES-NOT-EXIST #'reader-recover) + (ECLECTOR.READER:TWO-PACKAGE-MARKERS-MUST-BE-ADJACENT + #'reader-recover) (error (lambda (c) (format *error-output* "general error: ~S ~%" c)))) (eclector.reader:read-from-string str))) diff --git a/src/main/lisp/swank/swank-sbcl.lisp b/src/main/lisp/swank/swank-sbcl.lisp index b13025c..6379d61 100644 --- a/src/main/lisp/swank/swank-sbcl.lisp +++ b/src/main/lisp/swank/swank-sbcl.lisp @@ -5,6 +5,33 @@ (export 'ensure-printable-object) (export 'code-location-source-form) +(in-package :swank/sbcl) + +(defun form-number-position (definition-source stream) + (let* ((tlf-number (car (sb-introspect:definition-source-form-path definition-source))) + (form-number (sb-introspect:definition-source-form-number definition-source))) + (multiple-value-bind (tlf pos-map) (read-source-form tlf-number stream) + (let* ((path-table (sb-di::form-number-translations tlf 0)) + (path (cond ((<= (length path-table) form-number) + ; (warn "inconsistent form-number-translations") ; this fucks up stderr wtf + (list 0)) + (t + (reverse (cdr (aref path-table form-number))))))) + (source-path-source-position path tlf pos-map))))) + +(defun stream-source-position (code-location stream) + (let* ((cloc (sb-debug::maybe-block-start-location code-location)) + (tlf-number (sb-di::code-location-toplevel-form-offset cloc)) + (form-number (sb-di::code-location-form-number cloc))) + (multiple-value-bind (tlf pos-map) (read-source-form tlf-number stream) + (let* ((path-table (sb-di::form-number-translations tlf 0)) + (path (cond ((<= (length path-table) form-number) + ; (warn "inconsistent form-number-translations") ; same as above + (list 0)) + (t + (reverse (cdr (aref path-table form-number))))))) + (source-path-source-position path tlf pos-map))))) + (in-package :swank) (defun print-frame-call-place (frame) @@ -12,4 +39,4 @@ (SB-DEBUG:frame-call frame) (declare (ignore args info)) (let ((name (SB-DEBUG:ensure-printable-object name))) - name))) + name))) \ No newline at end of file diff --git a/src/main/lisp/swank/swank.lisp b/src/main/lisp/swank/swank.lisp index 4645354..6bb209e 100644 --- a/src/main/lisp/swank/swank.lisp +++ b/src/main/lisp/swank/swank.lisp @@ -2,10 +2,12 @@ (when (eq +slt-interpret+ :sbcl) (load (merge-pathnames "swank-sbcl.lisp" *load-truename*))) -(in-package :swank) +(in-package swank/source-file-cache) (setf *SOURCE-SNIPPET-SIZE* 0) +(in-package :swank) + (export 'find-source-location) (defslimefun slt-eval (string) diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 2ea73a7..01a6dbb 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -93,7 +93,8 @@ - + From 78dfa489892811183a38664734dd426440902836 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Wed, 1 Feb 2023 00:05:10 +0100 Subject: [PATCH 07/21] cleanup --- CHANGELOG.md | 1 + .../SltLispEnvironmentSymbolCache.java | 25 ------------------- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21ec43b..ea24d4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Fixes - Fixed tests +- Speed optimizations ## 0.3.0 230108 diff --git a/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java b/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java index 8582669..77b42d7 100644 --- a/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java +++ b/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java @@ -101,31 +101,6 @@ private void refreshBatchedSymbols(BatchedSymbolRefreshAction action, Consumer> batched = new ArrayList<>(Lists.partition(withoutDuplicity, 500)); -// List> futures = new ArrayList<>(); -// for (List batch : batched) { -// CompletableFuture future = new CompletableFuture<>(); -// ApplicationManager.getApplication().executeOnPooledThread(() -> { -// try { -// refreshSymbolsBatched(batch, future); -// } catch (Exception e) { -// throw new RuntimeException(e); -// } -// }); -// futures.add(future); -// } -// -// boolean success = true; -// for (Future future : futures) { -// try { -// future.get(120, TimeUnit.SECONDS); -// } catch (Exception e) { -// success = false; -// } -// } -// -// onFinish.consume(success); } private SymbolState getOrCreateBinding(String packageName, String symbolName) { From 7fd9bfaeb38509d27048c57956af9a51b7aa7629 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Wed, 1 Feb 2023 09:10:39 +0100 Subject: [PATCH 08/21] quick speed improvement --- .../slt/plugin/highlights/annotators/SymbolAnnotator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java index 61c890b..f3258ae 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java @@ -51,6 +51,9 @@ public void visitElement(@NotNull PsiElement element) { @Override public void apply(@NotNull PsiFile file, AnnotationResult annotationResult, @NotNull AnnotationHolder holder) { + if (annotationResult == AnnotationResult.FAILED) + return; + file.accept(new LispVisitor() { @Override From 213ffc7e813be92574209b1f3dc8617161ac4072 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Wed, 1 Feb 2023 09:26:01 +0100 Subject: [PATCH 09/21] code cleanup to pass inspections --- .../highlights/BraceHighlightService.java | 20 +++++++++++++++++++ .../highlights/SltBraceHighlighter.java | 15 +++++++------- src/main/resources/META-INF/plugin.xml | 2 ++ 3 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/highlights/BraceHighlightService.java diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/BraceHighlightService.java b/src/main/java/com/en_circle/slt/plugin/highlights/BraceHighlightService.java new file mode 100644 index 0000000..f2d335e --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/highlights/BraceHighlightService.java @@ -0,0 +1,20 @@ +package com.en_circle.slt.plugin.highlights; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.project.Project; + +public class BraceHighlightService implements Disposable { + + public static BraceHighlightService getService(Project project) { + return project.getService(BraceHighlightService.class); + } + + public BraceHighlightService(Project project) { + + } + + @Override + public void dispose() { + + } +} diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/SltBraceHighlighter.java b/src/main/java/com/en_circle/slt/plugin/highlights/SltBraceHighlighter.java index 32d5bf2..ef010b6 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/SltBraceHighlighter.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/SltBraceHighlighter.java @@ -5,8 +5,6 @@ import com.en_circle.slt.plugin.lisp.psi.LispTypes; import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory; import com.intellij.codeInsight.highlighting.BraceHighlightingHandler; -import com.intellij.codeInsight.highlighting.BraceMatchingUtil; -import com.intellij.codeInsight.highlighting.BraceMatchingUtil.BraceHighlightingAndNavigationContext; import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.codeInsight.template.impl.TemplateState; import com.intellij.injected.editor.EditorWindow; @@ -25,7 +23,6 @@ import com.intellij.openapi.editor.markup.HighlighterLayer; import com.intellij.openapi.editor.markup.HighlighterTargetArea; import com.intellij.openapi.editor.markup.RangeHighlighter; -import com.intellij.openapi.extensions.ExtensionPointUtil; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManagerEvent; import com.intellij.openapi.fileEditor.FileEditorManagerListener; @@ -35,7 +32,6 @@ import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupActivity; -import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiBinaryFile; @@ -69,9 +65,7 @@ public void runActivity(@NotNull Project project) { return; } - Disposable activityDisposable = ExtensionPointUtil.createExtensionDisposable(this, StartupActivity.POST_STARTUP_ACTIVITY); - // lul they have this in code with warning... - Disposer.register(project, activityDisposable); + Disposable activityDisposable = BraceHighlightService.getService(project); registerListeners(project, activityDisposable); } @@ -339,7 +333,7 @@ private void onCaretUpdate(Editor editor, Project project) { } @Nullable - private static BraceMatchingUtil.BraceHighlightingAndNavigationContext computeHighlightingAndNavigationContext(@NotNull Editor editor, + private static BraceHighlightingAndNavigationContext computeHighlightingAndNavigationContext(@NotNull Editor editor, @NotNull PsiFile file, int offset) { EditorHighlighter highlighter = BraceHighlightingHandler.getLazyParsableHighlighterIfAny(file.getProject(), editor, file); @@ -507,4 +501,9 @@ private static void advance(@NotNull HighlighterIterator iterator, boolean forwa iterator.retreat(); } } + + public record BraceHighlightingAndNavigationContext(int currentBraceOffset, int navigationOffset, + boolean isCaretAfterBrace) { + } + } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 01a6dbb..a1ddbfa 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -46,6 +46,8 @@ + + From e2fe34eec9d3f8bf90845b71130aab6b69d6c388 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Thu, 2 Feb 2023 18:05:06 +0100 Subject: [PATCH 10/21] thread list --- CHANGELOG.md | 4 + README.md | 3 +- .../slt/plugin/SltWindowFactory.java | 9 + .../slt/plugin/actions/EvalActionBase.java | 12 +- .../lisp/LispEnvironmentServiceImpl.java | 18 +- .../SltLispEnvironmentSymbolCache.java | 2 +- .../slt/plugin/swank/SlimeListener.java | 12 + .../slt/plugin/swank/SwankPacket.java | 15 + .../plugin/swank/components/ThreadInfo.java | 91 ++++++ .../slt/plugin/swank/requests/KillThread.java | 45 +++ .../plugin/swank/requests/ListThreads.java | 44 +++ .../plugin/swank/requests/SuspendThread.java | 45 +++ .../plugin/ui/PackageSelectorComponent.java | 4 +- .../slt/plugin/ui/SltCoreWindow.java | 44 ++- .../slt/plugin/ui/SltPackageWidget.java | 7 +- .../slt/plugin/ui/console/SltConsole.java | 4 +- .../slt/plugin/ui/debug/SltDebuggerImpl.java | 16 +- .../slt/plugin/ui/debug/SltFrameConsole.java | 4 +- .../slt/plugin/ui/debug/SltFrameInfo.java | 4 +- .../slt/plugin/ui/debug/SltInspector.java | 20 +- .../plugin/ui/instance/EmptyInfoPanel.java | 49 ++++ .../plugin/ui/instance/InstanceInfoPanel.java | 74 +++++ .../instance/InstanceInfoPanelComponent.java | 14 + .../slt/plugin/ui/instance/ThreadList.java | 265 ++++++++++++++++++ .../resources/messages/SltBundle.properties | 23 +- 25 files changed, 752 insertions(+), 76 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/swank/components/ThreadInfo.java create mode 100644 src/main/java/com/en_circle/slt/plugin/swank/requests/KillThread.java create mode 100644 src/main/java/com/en_circle/slt/plugin/swank/requests/ListThreads.java create mode 100644 src/main/java/com/en_circle/slt/plugin/swank/requests/SuspendThread.java create mode 100644 src/main/java/com/en_circle/slt/plugin/ui/instance/EmptyInfoPanel.java create mode 100644 src/main/java/com/en_circle/slt/plugin/ui/instance/InstanceInfoPanel.java create mode 100644 src/main/java/com/en_circle/slt/plugin/ui/instance/InstanceInfoPanelComponent.java create mode 100644 src/main/java/com/en_circle/slt/plugin/ui/instance/ThreadList.java diff --git a/CHANGELOG.md b/CHANGELOG.md index ea24d4a..0d8abae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## 0.3.1 +### Added + +- Thread list with actions + ### Changes - SLT library is now formatted into multiple chunks diff --git a/README.md b/README.md index f3e6758..1914a72 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,8 @@ You can also open this as a project in Intellij Idea. * [ ] Actions * [ ] Inspection eval * [ ] Walkable debugger without actions -* [ ] Breakpoints + * [ ] Breakpoints + * Currently impossible to do correctly with sbcl, investigating other options * [x] Documentation * [x] Macro expand in documentation * Macro expand requires you to hover element twice for now diff --git a/src/main/java/com/en_circle/slt/plugin/SltWindowFactory.java b/src/main/java/com/en_circle/slt/plugin/SltWindowFactory.java index 35b7255..cbada83 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltWindowFactory.java +++ b/src/main/java/com/en_circle/slt/plugin/SltWindowFactory.java @@ -2,6 +2,7 @@ import com.en_circle.slt.plugin.ui.SltCoreWindow; import com.en_circle.slt.plugin.ui.debug.SltDebuggers; +import com.en_circle.slt.plugin.ui.instance.InstanceInfoPanel; import com.intellij.openapi.project.Project; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowFactory; @@ -21,6 +22,14 @@ public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindo toolWindow.getContentManager().addContent(content); } + { + InstanceInfoPanel infoPanel = new InstanceInfoPanel(toolWindow); + ContentFactory contentFactory = ContentFactory.getInstance(); + Content content = contentFactory.createContent(infoPanel.getContent(), + SltBundle.message("slt.ui.instanceinfo.title"), false); + toolWindow.getContentManager().addContent(content); + } + { SltDebuggers debugger = new SltDebuggers(toolWindow); ContentFactory contentFactory = ContentFactory.getInstance(); diff --git a/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java b/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java index 5228b69..28be35e 100644 --- a/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java +++ b/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java @@ -43,8 +43,8 @@ protected void evaluate(Project project, String buffer, String packageName, Runn try { LispEnvironmentService.getInstance(project).sendToLisp(Eval.eval(buffer, packageName, result -> callback.run()), true); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } @@ -53,8 +53,8 @@ protected void evaluateRegion(Project project, String buffer, String packageName LispEnvironmentService.getInstance(project).sendToLisp(EvalFromVirtualFile .eval(buffer, filename, bufferPosition, lineno, charno, packageName, result -> callback.run()), true); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } @@ -63,8 +63,8 @@ public static void evaluateFile(Project project, String filename, VirtualFile vi LispEnvironmentService.getInstance(project).sendToLisp(LoadFile.loadFile(filename), true); FileContentUtilCore.reparseFiles(virtualFile); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } diff --git a/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java b/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java index fd78b22..bfbea87 100644 --- a/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java +++ b/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java @@ -111,8 +111,8 @@ public void start() { ensureToolWindowIsOpen(); doStart(); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } }); } @@ -129,8 +129,8 @@ public void stop() { try { doStop(); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstop"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.stop")); + log.warn(SltBundle.message("slt.error.stop"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.stop")); } } @@ -138,10 +138,10 @@ private boolean doStart() throws Exception { try { if (configurationBuilder == null) { if (!configured()) { - log.warn(SltBundle.message("slt.error.sbclstart")); + log.warn(SltBundle.message("slt.error.start")); Messages.showErrorDialog(project, - SltBundle.message("slt.ui.errors.sbcl.start.noconf"), - SltBundle.message("slt.ui.errors.sbcl.start")); + SltBundle.message("slt.ui.errors.lisp.start.noconf"), + SltBundle.message("slt.ui.errors.lisp.start")); return false; } } @@ -226,8 +226,8 @@ public void sendToLisp(SlimeRequest request, boolean startServer, Runnable onFai doSend(request); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } }); }); diff --git a/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java b/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java index 77b42d7..09aa654 100644 --- a/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java +++ b/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java @@ -33,7 +33,7 @@ public SltLispEnvironmentSymbolCache(Project project) { this.project = project; setDaemon(true); - setName("SBCL Symbol Cache Thread"); + setName("SLT Symbol Cache Thread"); } @Override diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java index d9a3126..89822bb 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java @@ -154,6 +154,18 @@ private void processReturn(LispContainer reply) { if (request instanceof CompleteSearch completeSearch) { completeSearch.processReply((LispContainer) reply.getItems().get(1)); } + + if (request instanceof ListThreads listThreads) { + listThreads.processReply((LispContainer) reply.getItems().get(1)); + } + + if (request instanceof KillThread killThread) { + killThread.processReply((LispContainer) reply.getItems().get(1)); + } + + if (request instanceof SuspendThread suspendThread) { + suspendThread.processReply((LispContainer) reply.getItems().get(1)); + } } finally { requests.remove(replyId.getValue()); } diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java b/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java index 849bd4e..2055c10 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java @@ -264,6 +264,21 @@ public static SwankPacket completeSearch(String prefix, String type, String thre return new SwankPacket(formatted); } + public static SwankPacket dumpThreads(BigInteger continuation) { + String formatted = String.format("(:emacs-rex (swank:list-threads) \":CL-USER\" T %s)", continuation); + return new SwankPacket(formatted); + } + + public static SwankPacket breakThread(BigInteger thread, BigInteger continuation) { + String formatted = String.format("(:emacs-rex (swank:debug-nth-thread %s) \":CL-USER\" T %s)", thread, continuation); + return new SwankPacket(formatted); + } + + public static SwankPacket killThread(BigInteger thread, BigInteger continuation) { + String formatted = String.format("(:emacs-rex (swank:kill-nth-thread %s) \":CL-USER\" T %s)", thread, continuation); + return new SwankPacket(formatted); + } + private int length; private String expressionSource; diff --git a/src/main/java/com/en_circle/slt/plugin/swank/components/ThreadInfo.java b/src/main/java/com/en_circle/slt/plugin/swank/components/ThreadInfo.java new file mode 100644 index 0000000..60ef3b3 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/swank/components/ThreadInfo.java @@ -0,0 +1,91 @@ +package com.en_circle.slt.plugin.swank.components; + +import com.en_circle.slt.plugin.lisp.lisp.*; + +import java.util.*; + +public class ThreadInfo { + + private int maxHeaders; + private final Map headers = new LinkedHashMap<>(); + private final List data = new ArrayList<>(); + + public ThreadInfo(LispContainer info) { + if (info.getItems().size() > 0) { + parseHeaders(info.getItems().get(0)); + } + if (info.getItems().size() > 1) { + for (int ix = 1; ix < info.getItems().size(); ix++) { + addThreadRown(info.getItems().get(ix)); + } + } + } + + private void addThreadRown(LispElement element) { + if (element instanceof LispContainer c) { + Object[] rowData = new Object[maxHeaders]; + int ix = 0; + for (LispElement e : c.getItems()) { + if (headers.containsValue(ix)) { + if (e instanceof LispString str) { + rowData[ix] = str.getValue(); + } else if (e instanceof LispInteger integer) { + rowData[ix] = integer.getValue(); + } else if (e instanceof LispAtom){ + rowData[ix] = e.toString(); + } + } + ++ix; + } + data.add(rowData); + } + } + + private void parseHeaders(LispElement element) { + if (element instanceof LispContainer c) { + int ix = 0; + for (LispElement e : c.getItems()) { + if (e instanceof LispSymbol s) { + headers.put(s.getValue().toUpperCase(), ix); + } + ++ix; + } + maxHeaders = ix; + } + } + + public int getMaxHeaders() { + return maxHeaders; + } + + public int getRowCount() { + return data.size(); + } + + public Collection getHeaders() { + return headers.keySet(); + } + + public String getHeader(int row) { + return new ArrayList<>(getHeaders()).get(row); + } + + public String getDataString(int row, int cell) { + Object data = getData(row, cell); + if (data == null) { + return ""; + } + return Objects.toString(data); + } + + public Object getData(int row, int cell) { + if (row < data.size()) { + if (cell < maxHeaders) { + return data.get(row)[cell]; + } + } + return null; + } + + +} diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/KillThread.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/KillThread.java new file mode 100644 index 0000000..2b29bef --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/KillThread.java @@ -0,0 +1,45 @@ +package com.en_circle.slt.plugin.swank.requests; + +import com.en_circle.slt.plugin.lisp.lisp.LispContainer; +import com.en_circle.slt.plugin.lisp.lisp.LispSymbol; +import com.en_circle.slt.plugin.swank.SlimeRequest; +import com.en_circle.slt.plugin.swank.SwankPacket; + +import java.math.BigInteger; + +public class KillThread extends SlimeRequest { + + public static SlimeRequest kill(BigInteger id, Callback callback) { + return new KillThread(id, callback); + } + + private final BigInteger id; + private final Callback callback; + + private KillThread(BigInteger id, Callback callback) { + this.id = id; + this.callback = callback; + } + + public void processReply(LispContainer data) { + if (isOk(data)) { + callback.onResult(); + } + } + + private boolean isOk(LispContainer data) { + return data.getItems().size() > 0 && + data.getItems().get(0) instanceof LispSymbol && + ":ok".equals(((LispSymbol) data.getItems().get(0)).getValue()); + } + + @Override + public SwankPacket createPacket(BigInteger requestId) { + return SwankPacket.killThread(id, requestId); + } + + public interface Callback { + void onResult(); + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/ListThreads.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/ListThreads.java new file mode 100644 index 0000000..f461e9c --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/ListThreads.java @@ -0,0 +1,44 @@ +package com.en_circle.slt.plugin.swank.requests; + +import com.en_circle.slt.plugin.lisp.lisp.LispContainer; +import com.en_circle.slt.plugin.lisp.lisp.LispSymbol; +import com.en_circle.slt.plugin.swank.SlimeRequest; +import com.en_circle.slt.plugin.swank.SwankPacket; +import com.en_circle.slt.plugin.swank.components.ThreadInfo; + +import java.math.BigInteger; + +public class ListThreads extends SlimeRequest { + + public static SlimeRequest dumpThreads(Callback callback) { + return new ListThreads(callback); + } + + private final Callback callback; + + private ListThreads(Callback callback) { + this.callback = callback; + } + + @Override + public SwankPacket createPacket(BigInteger requestId) { + return SwankPacket.dumpThreads(requestId); + } + + public void processReply(LispContainer data) { + if (isOk(data)) { + callback.onResult(new ThreadInfo((LispContainer) data.getItems().get(1))); + } + } + + private boolean isOk(LispContainer data) { + return data.getItems().size() > 0 && + data.getItems().get(0) instanceof LispSymbol && + ":ok".equals(((LispSymbol) data.getItems().get(0)).getValue()); + } + + public interface Callback { + void onResult(ThreadInfo result); + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/SuspendThread.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/SuspendThread.java new file mode 100644 index 0000000..3fafb94 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/SuspendThread.java @@ -0,0 +1,45 @@ +package com.en_circle.slt.plugin.swank.requests; + +import com.en_circle.slt.plugin.lisp.lisp.LispContainer; +import com.en_circle.slt.plugin.lisp.lisp.LispSymbol; +import com.en_circle.slt.plugin.swank.SlimeRequest; +import com.en_circle.slt.plugin.swank.SwankPacket; + +import java.math.BigInteger; + +public class SuspendThread extends SlimeRequest { + + public static SlimeRequest suspend(BigInteger id, Callback callback) { + return new SuspendThread(id, callback); + } + + private final BigInteger id; + private final Callback callback; + + private SuspendThread(BigInteger id, Callback callback) { + this.id = id; + this.callback = callback; + } + + public void processReply(LispContainer data) { + if (isOk(data)) { + callback.onResult(); + } + } + + private boolean isOk(LispContainer data) { + return data.getItems().size() > 0 && + data.getItems().get(0) instanceof LispSymbol && + ":ok".equals(((LispSymbol) data.getItems().get(0)).getValue()); + } + + @Override + public SwankPacket createPacket(BigInteger requestId) { + return SwankPacket.breakThread(id, requestId); + } + + public interface Callback { + void onResult(); + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java b/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java index baba28c..0582552 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java @@ -64,9 +64,9 @@ public void refresh() { resolvePackages(parsed); }), false); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); + log.warn(SltBundle.message("slt.error.start"), e); Messages.showErrorDialog(ProjectManager.getInstance().getDefaultProject(), - e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java b/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java index 13aa498..2083b03 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java @@ -1,7 +1,6 @@ package com.en_circle.slt.plugin.ui; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.SltCommonLispFileType; import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentListener; @@ -12,15 +11,9 @@ import com.intellij.icons.AllIcons.Actions; import com.intellij.icons.AllIcons.General; import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindow; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; import com.intellij.ui.tabs.impl.JBTabsImpl; -import com.intellij.util.FileContentUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -72,14 +65,14 @@ public SltCoreWindow(ToolWindow toolWindow) { private void createSbclControls() { DefaultActionGroup controlGroup = new DefaultActionGroup(); - controlGroup.add(new StartSbclAction()); + controlGroup.add(new StartLispAction()); controlGroup.add(new StopSbclAction()); controlGroup.addSeparator(); controlGroup.add(new ConsoleWindowAction()); JPanel west = new JPanel(new BorderLayout()); ActionToolbar toolbar = ActionManager.getInstance() - .createActionToolbar("SltProcessWindowSbclEvent", controlGroup, false); + .createActionToolbar("SltProcessWindowEvent", controlGroup, false); toolbar.setTargetComponent(content); west.add(toolbar.getComponent(), BorderLayout.NORTH); content.add(west, BorderLayout.WEST); @@ -87,16 +80,6 @@ private void createSbclControls() { public void start() { LispEnvironmentService.getInstance(project).start(); - - PsiManager psiManager = PsiManager.getInstance(project); - List toReparse = new ArrayList<>(); - for (VirtualFile vf : FileEditorManager.getInstance(project).getOpenFiles()) { - PsiFile psiFile = psiManager.findFile(vf); - if (psiFile != null && psiFile.getFileType().equals(SltCommonLispFileType.INSTANCE)) { - toReparse.add(vf); - } - } - FileContentUtil.reparseFiles(project, toReparse, false); } public void stop() { @@ -170,15 +153,20 @@ public Project getProject() { return project; } - private class StartSbclAction extends AnAction { + private class StartLispAction extends AnAction { - private StartSbclAction() { + private StartLispAction() { super(SltBundle.message("slt.ui.process.startinstance"), "", AllIcons.RunConfigurations.TestState.Run); } @Override public void actionPerformed(@NotNull AnActionEvent e) { - ApplicationManager.getApplication().invokeLater(SltCoreWindow.this::start); + start(); + } + + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.EDT; } @Override @@ -200,6 +188,11 @@ public void actionPerformed(@NotNull AnActionEvent e) { stop(); } + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.EDT; + } + @Override public void update(@NotNull AnActionEvent e) { super.update(e); @@ -211,7 +204,7 @@ public void update(@NotNull AnActionEvent e) { private class ConsoleWindowAction extends AnAction { private ConsoleWindowAction() { - super(SltBundle.message("slt.ui.process.openrepl.sbcl"), "", General.Add); + super(SltBundle.message("slt.ui.process.openrepl"), "", General.Add); } @Override @@ -219,6 +212,11 @@ public void actionPerformed(@NotNull AnActionEvent e) { addRepl(); } + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.EDT; + } + @Override public void update(@NotNull AnActionEvent e) { super.update(e); diff --git a/src/main/java/com/en_circle/slt/plugin/ui/SltPackageWidget.java b/src/main/java/com/en_circle/slt/plugin/ui/SltPackageWidget.java index 83ddd24..283f2d7 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/SltPackageWidget.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/SltPackageWidget.java @@ -1,6 +1,7 @@ package com.en_circle.slt.plugin.ui; import com.en_circle.slt.plugin.SltBundle; +import com.en_circle.slt.plugin.SltCommonLispFileType; import com.en_circle.slt.plugin.lisp.LispParserUtil; import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentState; @@ -154,8 +155,10 @@ private void updatePosition(Editor editor) { Document document = editor.getDocument(); PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document); if (psiFile != null) { - int caretOffset = ex.getExpectedCaretOffset(); - packageName = LispParserUtil.getPackage(psiFile, caretOffset, LispParserUtil.NULL_RETURN); + if (psiFile.getFileType() == SltCommonLispFileType.INSTANCE) { + int caretOffset = ex.getExpectedCaretOffset(); + packageName = LispParserUtil.getPackage(psiFile, caretOffset, LispParserUtil.NULL_RETURN); + } } if (statusBar != null) { statusBar.updateWidget(ID()); diff --git a/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java b/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java index 0ea137b..511024d 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java @@ -82,8 +82,8 @@ protected void eval(String data) { result -> languageConsole.print(result + "\n", ConsoleViewContentType.NORMAL_OUTPUT))); } } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java index 786bea4..3ac0b26 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java @@ -194,8 +194,8 @@ private void actionAccepted(SltDebugAction action, SltDebugInfo debugInfo) { LispEnvironmentService.getInstance(parent.getProject()).sendToLisp(InvokeNthRestart.nthRestart(debugInfo.getThreadId(), BigInteger.valueOf(ix), debugInfo.getDebugLevel(), "NIL", "NIL", () -> {})); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(parent.getProject(), e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(parent.getProject(), e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } else { List arguments = new ArrayList<>(); @@ -218,8 +218,8 @@ private void actionAccepted(SltDebugAction action, SltDebugInfo debugInfo) { LispEnvironmentService.getInstance(parent.getProject()).sendToLisp(InvokeNthRestart.nthRestart(debugInfo.getThreadId(), BigInteger.valueOf(ix), debugInfo.getDebugLevel(), args, rest, () -> {})); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(parent.getProject(), e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(parent.getProject(), e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } @@ -261,8 +261,8 @@ private void stackframeClicked(SltDebugStackTraceElement element, SltDebugInfo d }); }), true); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(parent.getProject(), e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(parent.getProject(), e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } @@ -270,8 +270,8 @@ private void close() { try { LispEnvironmentService.getInstance(parent.getProject()).sendToLisp(new ThrowToToplevel(lastDebugId)); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(parent.getProject(), e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(parent.getProject(), e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameConsole.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameConsole.java index 87282f3..2e9d8ff 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameConsole.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameConsole.java @@ -39,8 +39,8 @@ protected void eval(String data) { })); } } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java index 5829bd6..416f5d7 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java @@ -121,8 +121,8 @@ private void reloadLocals() { }); }), false); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java index ecbc4fa..31ba1ae 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java @@ -71,8 +71,8 @@ public void loadLocal(Local local, BigInteger frame) { .sendToLisp(InspectFrameVar.inspectVariable(BigInteger.valueOf(local.ix), frame, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } @@ -137,8 +137,8 @@ private void navigate(String description) { .sendToLisp(InspectNth.inspectVariable(ix, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } @@ -155,8 +155,8 @@ public void actionPerformed(@NotNull AnActionEvent event) { .sendToLisp(InspectorAction.action(ActionType.GO_BACK, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } @@ -181,8 +181,8 @@ public void actionPerformed(@NotNull AnActionEvent event) { .sendToLisp(InspectorAction.action(ActionType.GO_FORWARD, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } @@ -207,8 +207,8 @@ public void actionPerformed(@NotNull AnActionEvent event) { .sendToLisp(InspectorAction.action(ActionType.REFRESH, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/instance/EmptyInfoPanel.java b/src/main/java/com/en_circle/slt/plugin/ui/instance/EmptyInfoPanel.java new file mode 100644 index 0000000..21a0548 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/ui/instance/EmptyInfoPanel.java @@ -0,0 +1,49 @@ +package com.en_circle.slt.plugin.ui.instance; + +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; +import com.intellij.openapi.project.Project; + +import javax.swing.*; +import java.awt.*; + +public class EmptyInfoPanel implements InstanceInfoPanelComponent { + + private JPanel content; + + @Override + public Component create(Project project) { + content = new JPanel(new BorderLayout()); + return content; + } + + @Override + public Component getComponent() { + return content; + } + + @Override + public void onOutputChanged(SltOutput output, String newData) { + + } + + @Override + public void onPreStart() { + + } + + @Override + public void onPostStart() { + + } + + @Override + public void onPreStop() { + + } + + @Override + public void onPostStop() { + + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/ui/instance/InstanceInfoPanel.java b/src/main/java/com/en_circle/slt/plugin/ui/instance/InstanceInfoPanel.java new file mode 100644 index 0000000..f5ff94a --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/ui/instance/InstanceInfoPanel.java @@ -0,0 +1,74 @@ +package com.en_circle.slt.plugin.ui.instance; + +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentListener; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.wm.ToolWindow; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; + +public class InstanceInfoPanel implements LispEnvironmentListener { + + private final JPanel content; + private final List panels = new ArrayList<>(); + + public InstanceInfoPanel(ToolWindow toolWindow) { + Project project = toolWindow.getProject(); + LispEnvironmentService.getInstance(project).addServerListener(this); + content = new JPanel(); + content.setLayout(new BoxLayout(content, BoxLayout.LINE_AXIS)); + + addInfoPanel(new ThreadList()); + addInfoPanel(new EmptyInfoPanel()); + + for (InstanceInfoPanelComponent component : panels) { + content.add(component.create(project)); + } + } + + private void addInfoPanel(InstanceInfoPanelComponent component) { + panels.add(component); + } + + public JComponent getContent() { + return content; + } + + @Override + public void onOutputChanged(SltOutput output, String newData) { + for (InstanceInfoPanelComponent component : panels) { + component.onOutputChanged(output, newData); + } + } + + @Override + public void onPreStart() { + for (InstanceInfoPanelComponent component : panels) { + component.onPreStart(); + } + } + + @Override + public void onPostStart() { + for (InstanceInfoPanelComponent component : panels) { + component.onPostStart(); + } + } + + @Override + public void onPreStop() { + for (InstanceInfoPanelComponent component : panels) { + component.onPreStop(); + } + } + + @Override + public void onPostStop() { + for (InstanceInfoPanelComponent component : panels) { + component.onPostStop(); + } + } +} diff --git a/src/main/java/com/en_circle/slt/plugin/ui/instance/InstanceInfoPanelComponent.java b/src/main/java/com/en_circle/slt/plugin/ui/instance/InstanceInfoPanelComponent.java new file mode 100644 index 0000000..305670c --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/ui/instance/InstanceInfoPanelComponent.java @@ -0,0 +1,14 @@ +package com.en_circle.slt.plugin.ui.instance; + +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentListener; +import com.intellij.openapi.project.Project; + +import java.awt.*; + +public interface InstanceInfoPanelComponent extends LispEnvironmentListener { + + Component create(Project project); + Component getComponent(); + + +} diff --git a/src/main/java/com/en_circle/slt/plugin/ui/instance/ThreadList.java b/src/main/java/com/en_circle/slt/plugin/ui/instance/ThreadList.java new file mode 100644 index 0000000..3119f01 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/ui/instance/ThreadList.java @@ -0,0 +1,265 @@ +package com.en_circle.slt.plugin.ui.instance; + +import com.en_circle.slt.plugin.SltBundle; +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentState; +import com.en_circle.slt.plugin.swank.components.ThreadInfo; +import com.en_circle.slt.plugin.swank.requests.KillThread; +import com.en_circle.slt.plugin.swank.requests.ListThreads; +import com.en_circle.slt.plugin.swank.requests.SuspendThread; +import com.intellij.icons.AllIcons.Actions; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.table.JBTable; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.swing.*; +import javax.swing.event.TableModelListener; +import javax.swing.table.TableModel; +import java.awt.*; +import java.math.BigInteger; + +public class ThreadList implements InstanceInfoPanelComponent { + private static final Logger log = LoggerFactory.getLogger(ThreadList.class); + + private Project project; + private JPanel content; + private JPanel tableContainer; + private JBTable table = null; + private ThreadInfo info; + + @Override + public Component create(Project project) { + this.project = project; + content = new JPanel(new BorderLayout()); + + DefaultActionGroup controlGroup = new DefaultActionGroup(); + controlGroup.add(new RefreshLispThreads()); + controlGroup.add(new BreakThread()); + controlGroup.add(new TerminateThread()); + JPanel west = new JPanel(new BorderLayout()); + ActionToolbar toolbar = ActionManager.getInstance() + .createActionToolbar("ThreadList", controlGroup, false); + toolbar.setTargetComponent(content); + west.add(toolbar.getComponent(), BorderLayout.NORTH); + content.add(west, BorderLayout.WEST); + + tableContainer = new JPanel(new BorderLayout()); + tableContainer.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), + SltBundle.message("slt.ui.instanceinfo.threads.title"))); + content.add(tableContainer, BorderLayout.CENTER); + + table = new JBTable(); + table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + table.setColumnSelectionAllowed(false); + tableContainer.add(new JBScrollPane(table), BorderLayout.CENTER); + tableContainer.add(table.getTableHeader(), BorderLayout.NORTH); + + return content; + } + + @Override + public Component getComponent() { + return content; + } + + private void refreshThreads() { + try { + LispEnvironmentService.getInstance(project) + .sendToLisp(ListThreads.dumpThreads((info) -> + ApplicationManager.getApplication().invokeLater(() -> regenerateTable(info))), false); + } catch (Exception e) { + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); + } + } + + private void regenerateTable(ThreadInfo info) { + this.info = info; + table.setModel(new TableModel() { + + @Override + public int getRowCount() { + return info.getRowCount(); + } + + @Override + public int getColumnCount() { + return info.getMaxHeaders(); + } + + @Nls + @Override + public String getColumnName(int columnIndex) { + return info.getHeader(columnIndex); + } + + @Override + public Class getColumnClass(int columnIndex) { + return String.class; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return info.getDataString(rowIndex, columnIndex); + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + + } + + @Override + public void addTableModelListener(TableModelListener l) { + + } + + @Override + public void removeTableModelListener(TableModelListener l) { + + } + }); + } + + private void pauseThread() { + int row = table.getSelectionModel().getSelectedIndices()[0]; + Object id = info.getData(row, 0); + if (id instanceof BigInteger lispId) { + try { + LispEnvironmentService.getInstance(project) + .sendToLisp(SuspendThread.suspend(lispId, + () -> ApplicationManager.getApplication().invokeLater(this::refreshThreads)), false); + } catch (Exception e) { + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); + } + } + } + + private void terminateThread() { + int row = table.getSelectionModel().getSelectedIndices()[0]; + Object id = info.getData(row, 0); + if (id instanceof BigInteger lispId) { + try { + LispEnvironmentService.getInstance(project) + .sendToLisp(KillThread.kill(lispId, + () -> ApplicationManager.getApplication().invokeLater(this::refreshThreads)), false); + } catch (Exception e) { + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); + } + } + } + + @Override + public void onOutputChanged(SltOutput output, String newData) { + + } + + @Override + public void onPreStart() { + + } + + @Override + public void onPostStart() { + refreshThreads(); + } + + @Override + public void onPreStop() { + tableContainer.removeAll(); + } + + @Override + public void onPostStop() { + + } + + private class RefreshLispThreads extends AnAction { + + private RefreshLispThreads() { + super(SltBundle.message("slt.ui.instanceinfo.threads.action.refresh"), "", Actions.Refresh); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + refreshThreads(); + } + + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.EDT; + } + + @Override + public void update(@NotNull AnActionEvent e) { + super.update(e); + + e.getPresentation().setEnabled(LispEnvironmentService.getInstance(project).getState() == LispEnvironmentState.READY); + } + } + + private class BreakThread extends AnAction { + + private BreakThread() { + super(SltBundle.message("slt.ui.instanceinfo.threads.action.break"), "", Actions.Pause); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + pauseThread(); + } + + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.EDT; + } + + @Override + public void update(@NotNull AnActionEvent e) { + super.update(e); + + e.getPresentation().setEnabled(LispEnvironmentService.getInstance(project).getState() == LispEnvironmentState.READY + && !table.getSelectionModel().isSelectionEmpty()); + } + } + + private class TerminateThread extends AnAction { + + private TerminateThread() { + super(SltBundle.message("slt.ui.instanceinfo.threads.action.stop"), "", Actions.Suspend); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + terminateThread(); + } + + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.EDT; + } + + @Override + public void update(@NotNull AnActionEvent e) { + super.update(e); + + e.getPresentation().setEnabled(LispEnvironmentService.getInstance(project).getState() == LispEnvironmentState.READY + && !table.getSelectionModel().isSelectionEmpty()); + } + } + +} diff --git a/src/main/resources/messages/SltBundle.properties b/src/main/resources/messages/SltBundle.properties index 07cec6c..5e1b6d4 100644 --- a/src/main/resources/messages/SltBundle.properties +++ b/src/main/resources/messages/SltBundle.properties @@ -2,8 +2,8 @@ slt.commonlisp=Common Lisp slt.file.description=Common Lisp source file -slt.error.sbclstart=Error starting sbcl -slt.error.sbclstop=Error stopping sbcl +slt.error.start=Error starting lisp +slt.error.stop=Error stopping lisp # SDK slt.environment.sbcl=SBCL @@ -22,9 +22,9 @@ slt.documentation.types.method=Method slt.documentation.macroexpand.generating=Generating macro expansion, hover again to see it # UI -slt.ui.errors.sbcl.start=Failed to Start SBCL -slt.ui.errors.sbcl.stop=Failed to Stop SBCL -slt.ui.errors.sbcl.start.noconf=No Lisp SDK selected. Please select SDK in project menu. +slt.ui.errors.lisp.start=Failed to Start Lisp +slt.ui.errors.lisp.stop=Failed to Stop Lisp +slt.ui.errors.lisp.start.noconf=No Lisp SDK selected. Please select SDK in project menu. slt.ui.packageselector.title=Current package: slt.ui.packageselector.refresh=Refresh Packages @@ -44,11 +44,11 @@ slt.ui.colorsettings.class=Class slt.ui.colorsettings.method=Method # Process -slt.ui.process.title=SBCL Process +slt.ui.process.title=Lisp Process slt.ui.process.processpid=Lisp Process Pid: slt.ui.process.startinstance=Start Lisp Instance slt.ui.process.stopinstance=Stop Lisp Instance -slt.ui.process.openrepl.sbcl=Create Lisp REPL +slt.ui.process.openrepl=Create Lisp REPL slt.ui.process.gl.clear=Clear Text slt.ui.process.gl.wrap=Soft Wrap slt.ui.process.gl.scroll=Scroll to End @@ -61,7 +61,7 @@ slt.ui.repl.close=Close slt.ui.repl.title=REPL # Debuggers -slt.ui.debuggers.title=SBCL Debuggers +slt.ui.debuggers.title=Lisp Debuggers slt.ui.debugger.title=Debugger # slt.ui.debugger.close=Close slt.ui.debugger.errormessage=Error Message: @@ -85,6 +85,13 @@ slt.ui.inspector.navigation.back=Go Back in History slt.ui.inspector.navigation.forward=Go Forward in History slt.ui.inspector.navigation.refresh=Refresh Currently Inspected Object +# instance info +slt.ui.instanceinfo.title=Lisp Instance Information +slt.ui.instanceinfo.threads.title=Threads +slt.ui.instanceinfo.threads.action.refresh=Refresh Thread List +slt.ui.instanceinfo.threads.action.break=Break Thread +slt.ui.instanceinfo.threads.action.stop=Terminate Thread + # Settings slt.ui.projectsettings.sdk=Common Lisp SDK slt.ui.projectsettings.sdk.selector=Common lisp SDK From 7524c9e177ce251c9e031f165570ad781853fa6a Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Thu, 2 Feb 2023 20:45:54 +0100 Subject: [PATCH 11/21] thread list - working interrupts / kills --- .../slt/plugin/SltWindowFactory.java | 4 + .../slt/plugin/ui/SltCoreWindow.java | 23 +++- .../slt/plugin/ui/SltGeneralLog.java | 97 +++++------------ .../plugin/ui/SltOutputHandlerComponent.java | 100 ++++++------------ .../en_circle/slt/plugin/ui/SltUIService.java | 16 +++ .../slt/plugin/ui/debug/SltDebuggerImpl.java | 15 +-- .../slt/plugin/ui/debug/SltDebuggers.java | 15 ++- .../slt/plugin/ui/instance/ThreadList.java | 36 +++---- .../slt/tools/SltApplicationUtils.java | 4 + src/main/resources/META-INF/plugin.xml | 2 + 10 files changed, 138 insertions(+), 174 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/ui/SltUIService.java diff --git a/src/main/java/com/en_circle/slt/plugin/SltWindowFactory.java b/src/main/java/com/en_circle/slt/plugin/SltWindowFactory.java index cbada83..31abc3c 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltWindowFactory.java +++ b/src/main/java/com/en_circle/slt/plugin/SltWindowFactory.java @@ -1,9 +1,11 @@ package com.en_circle.slt.plugin; import com.en_circle.slt.plugin.ui.SltCoreWindow; +import com.en_circle.slt.plugin.ui.SltUIService; import com.en_circle.slt.plugin.ui.debug.SltDebuggers; import com.en_circle.slt.plugin.ui.instance.InstanceInfoPanel; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowFactory; import com.intellij.ui.content.Content; @@ -20,6 +22,8 @@ public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindo Content content = contentFactory.createContent(sltCoreWindow.getContent(), SltBundle.message("slt.ui.process.title"), false); toolWindow.getContentManager().addContent(content); + + Disposer.register(SltUIService.getInstance(project), sltCoreWindow); } { diff --git a/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java b/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java index 2083b03..e704ffc 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java @@ -10,8 +10,10 @@ import com.intellij.icons.AllIcons; import com.intellij.icons.AllIcons.Actions; import com.intellij.icons.AllIcons.General; +import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.wm.ToolWindow; import com.intellij.ui.tabs.impl.JBTabsImpl; import org.jetbrains.annotations.NotNull; @@ -22,7 +24,7 @@ import java.util.Collections; import java.util.List; -public class SltCoreWindow implements LispEnvironmentListener { +public class SltCoreWindow implements LispEnvironmentListener, Disposable { private final Project project; private final JTextField process; @@ -36,9 +38,17 @@ public SltCoreWindow(ToolWindow toolWindow) { LispEnvironmentService.getInstance(project).addServerListener(this); content = new JPanel(new BorderLayout()); - components.add(new SltOutputHandlerComponent(this, SltOutput.STDOUT)); - components.add(new SltOutputHandlerComponent(this, SltOutput.STDERR)); - SltGeneralLog generalLog = new SltGeneralLog(); + SltOutputHandlerComponent outputHandlerComponent = new SltOutputHandlerComponent(project, SltOutput.STDOUT); + components.add(outputHandlerComponent); + Disposer.register(this, outputHandlerComponent); + + outputHandlerComponent = new SltOutputHandlerComponent(project, SltOutput.STDERR); + components.add(outputHandlerComponent); + Disposer.register(this, outputHandlerComponent); + + SltGeneralLog generalLog = new SltGeneralLog(project); + Disposer.register(this, generalLog); + components.add(generalLog); LispEnvironmentService.getInstance(project).setRequestResponseLogger(generalLog); @@ -153,6 +163,11 @@ public Project getProject() { return project; } + @Override + public void dispose() { + + } + private class StartLispAction extends AnAction { private StartLispAction() { diff --git a/src/main/java/com/en_circle/slt/plugin/ui/SltGeneralLog.java b/src/main/java/com/en_circle/slt/plugin/ui/SltGeneralLog.java index 16ac410..9a9cc93 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/SltGeneralLog.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/SltGeneralLog.java @@ -3,92 +3,38 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; import com.en_circle.slt.plugin.swank.SlimeListener.RequestResponseLogger; -import com.en_circle.slt.tools.BufferedString; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.*; -import com.intellij.ui.components.JBScrollPane; +import com.intellij.execution.filters.TextConsoleBuilderFactory; +import com.intellij.execution.ui.ConsoleView; +import com.intellij.execution.ui.ConsoleViewContentType; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.ui.tabs.TabInfo; import org.apache.commons.lang3.StringUtils; -import org.jetbrains.annotations.NotNull; import javax.swing.*; -import javax.swing.text.DefaultCaret; import java.awt.*; -public class SltGeneralLog implements SltComponent, RequestResponseLogger { +public class SltGeneralLog implements SltComponent, RequestResponseLogger, Disposable { private final JPanel dataContainer; - private JTextArea area; + private ConsoleView consoleView; private TabInfo tabInfo; - private BufferedString bufferedString; - public SltGeneralLog() { + private final Project project; + + public SltGeneralLog(Project project) { + this.project = project; this.dataContainer = new JPanel(new BorderLayout()); } @Override public TabInfo create() { - area = new JTextArea(); - area.setEditable(false); - DefaultCaret caret = (DefaultCaret) area.getCaret(); - caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); - - JBScrollPane scrollPane = new JBScrollPane(area); - dataContainer.add(scrollPane, BorderLayout.CENTER); - - DefaultActionGroup controlGroup = new DefaultActionGroup(); - ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar("SltProcessWindowWrapEvent", controlGroup, false); - toolbar.setTargetComponent(dataContainer); - dataContainer.add(toolbar.getComponent(), BorderLayout.EAST); - - bufferedString = new BufferedString(data -> SwingUtilities.invokeLater(() -> { - area.setText(area.getText() + data); - if (caret.getUpdatePolicy() == DefaultCaret.ALWAYS_UPDATE) - area.setCaretPosition(area.getDocument().getLength()); - }), fullData -> SwingUtilities.invokeLater(() -> { - area.setText(fullData); - if (caret.getUpdatePolicy() == DefaultCaret.ALWAYS_UPDATE) - area.setCaretPosition(area.getDocument().getLength()); - })); - - controlGroup.add(new AnAction(SltBundle.message("slt.ui.process.gl.clear"), "", AllIcons.Actions.GC) { - - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - bufferedString.clear(); - } - }); - controlGroup.add(new ToggleAction(SltBundle.message("slt.ui.process.gl.wrap"), "", AllIcons.Actions.ToggleSoftWrap) { - - @Override - public boolean isSelected(@NotNull AnActionEvent e) { - return area.getLineWrap(); - } - - @Override - public void setSelected(@NotNull AnActionEvent e, boolean state) { - area.setLineWrap(state); - } - - }); - controlGroup.add(new ToggleAction(SltBundle.message("slt.ui.process.gl.scroll"), "", AllIcons.RunConfigurations.Scroll_down) { - - @Override - public boolean isSelected(@NotNull AnActionEvent e) { - return caret.getUpdatePolicy() == DefaultCaret.ALWAYS_UPDATE; - } - - @Override - public void setSelected(@NotNull AnActionEvent e, boolean state) { - if (state) { - caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); - area.setCaretPosition(area.getDocument().getLength()); - } else { - caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); - } - } - - }); + consoleView = TextConsoleBuilderFactory.getInstance() + .createBuilder(project) + .getConsole(); + Disposer.register(this, consoleView); + dataContainer.add(consoleView.getComponent()); tabInfo = new TabInfo(dataContainer); tabInfo.setText(getTitle()); @@ -133,12 +79,17 @@ public String getTitle() { @Override public void logRequest(String request) { request = StringUtils.truncate(request, 0, 4069); - bufferedString.append("\n\n" + request); + consoleView.print("\n\n" + request, ConsoleViewContentType.LOG_INFO_OUTPUT); } @Override public void logResponse(String response) { response = StringUtils.truncate(response, 0, 4069); - bufferedString.append("\n\n" + response); + consoleView.print("\n\n" + response, ConsoleViewContentType.LOG_INFO_OUTPUT); + } + + @Override + public void dispose() { + } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/SltOutputHandlerComponent.java b/src/main/java/com/en_circle/slt/plugin/ui/SltOutputHandlerComponent.java index 4ec8b73..06ca091 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/SltOutputHandlerComponent.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/SltOutputHandlerComponent.java @@ -2,26 +2,29 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.*; -import com.intellij.ui.components.JBScrollPane; +import com.intellij.execution.filters.TextConsoleBuilderFactory; +import com.intellij.execution.ui.ConsoleView; +import com.intellij.execution.ui.ConsoleViewContentType; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.ui.tabs.TabInfo; -import org.apache.commons.lang3.StringUtils; -import org.jetbrains.annotations.NotNull; import javax.swing.*; -import javax.swing.text.DefaultCaret; import java.awt.*; -public class SltOutputHandlerComponent implements SltComponent { +public class SltOutputHandlerComponent implements SltComponent, Disposable { private final SltOutput output; private final JPanel dataContainer; - private JTextArea area; private TabInfo tabInfo; + private ConsoleView consoleView; + private final Project project; + private boolean firstStart = true; - public SltOutputHandlerComponent(SltCoreWindow coreWindow, SltOutput output) { + public SltOutputHandlerComponent(Project project, SltOutput output) { this.output = output; + this.project = project; this.dataContainer = new JPanel(new BorderLayout()); } @@ -31,63 +34,25 @@ public SltOutput getOutput() { @Override public TabInfo create() { - area = new JTextArea(); - area.setEditable(false); - DefaultCaret caret = (DefaultCaret) area.getCaret(); - caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); - - JBScrollPane scrollPane = new JBScrollPane(area); - dataContainer.add(scrollPane, BorderLayout.CENTER); - - DefaultActionGroup controlGroup = new DefaultActionGroup(); - ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar("SltProcessWindowWrapEvent", controlGroup, false); - toolbar.setTargetComponent(dataContainer); - dataContainer.add(toolbar.getComponent(), BorderLayout.EAST); - - controlGroup.add(new AnAction(SltBundle.message("slt.ui.process.gl.clear"), "", AllIcons.Actions.GC) { - - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - area.setText(""); - } - }); - controlGroup.add(new ToggleAction(SltBundle.message("slt.ui.process.gl.wrap"), "", AllIcons.Actions.ToggleSoftWrap) { - - @Override - public boolean isSelected(@NotNull AnActionEvent e) { - return area.getLineWrap(); - } - - @Override - public void setSelected(@NotNull AnActionEvent e, boolean state) { - area.setLineWrap(state); - } - - }); - controlGroup.add(new ToggleAction(SltBundle.message("slt.ui.process.gl.scroll"), "", AllIcons.RunConfigurations.Scroll_down) { - - @Override - public boolean isSelected(@NotNull AnActionEvent e) { - return caret.getUpdatePolicy() == DefaultCaret.ALWAYS_UPDATE; - } - - @Override - public void setSelected(@NotNull AnActionEvent e, boolean state) { - if (state) { - caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); - area.setCaretPosition(area.getDocument().getLength()); - } else { - caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); - } - } - - }); + consoleView = TextConsoleBuilderFactory.getInstance() + .createBuilder(project) + .getConsole(); + Disposer.register(this, consoleView); + dataContainer.add(consoleView.getComponent()); tabInfo = new TabInfo(dataContainer); tabInfo.setText(getTitle()); return tabInfo; } + private ConsoleViewContentType getOutputType() { + if (output == SltOutput.STDERR) { + return ConsoleViewContentType.ERROR_OUTPUT; + } else { + return ConsoleViewContentType.SYSTEM_OUTPUT; + } + } + @Override public TabInfo getTabInfo() { return tabInfo; @@ -95,23 +60,20 @@ public TabInfo getTabInfo() { @Override public void onPreStart() { - if (StringUtils.isNotBlank(area.getText())) { - area.setText(area.getText() + "\n\n***\n\n"); + if (!firstStart) { + consoleView.print("\n\n***\n\n", getOutputType()); } } @Override public void onPostStart() { - + firstStart = false; } @Override public void handleOutput(SltOutput output, String data) { if (output == this.output) { - area.setText(area.getText() + data); - DefaultCaret caret = (DefaultCaret) area.getCaret(); - if (caret.getUpdatePolicy() == DefaultCaret.ALWAYS_UPDATE) - area.setCaretPosition(area.getDocument().getLength()); + consoleView.print(data, getOutputType()); } } @@ -131,4 +93,8 @@ public String getTitle() { SltBundle.message("slt.ui.process.log.output.title"); } + @Override + public void dispose() { + + } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/SltUIService.java b/src/main/java/com/en_circle/slt/plugin/ui/SltUIService.java new file mode 100644 index 0000000..7d6dc63 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/ui/SltUIService.java @@ -0,0 +1,16 @@ +package com.en_circle.slt.plugin.ui; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.project.Project; + +public class SltUIService implements Disposable { + + public static SltUIService getInstance(Project project) { + return project.getService(SltUIService.class); + } + + @Override + public void dispose() { + + } +} diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java index 3ac0b26..339974a 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java @@ -252,13 +252,14 @@ private void stackframeClicked(SltDebugStackTraceElement element, SltDebugInfo d try { LispEnvironmentService.getInstance(parent.getProject()).sendToLisp(FrameLocalsAndCatchTags.getLocals(BigInteger.valueOf(ix), debugInfo.getThreadId(), result -> { - ApplicationManager.getApplication().runWriteAction(() -> { - SltFrameInfo frameInfo = new SltFrameInfo(parent.getProject(), debugInfo.getThreadId(), BigInteger.valueOf(ix), - element.getFramePackage()); - singleFrameComponent.removeAll(); - singleFrameComponent.add(frameInfo.getContent(), BorderLayout.CENTER); - frameInfo.refreshFrameValues(result); - }); + ApplicationManager.getApplication().invokeLater(() -> + ApplicationManager.getApplication().runWriteAction(() -> { + SltFrameInfo frameInfo = new SltFrameInfo(parent.getProject(), debugInfo.getThreadId(), BigInteger.valueOf(ix), + element.getFramePackage()); + singleFrameComponent.removeAll(); + singleFrameComponent.add(frameInfo.getContent(), BorderLayout.CENTER); + frameInfo.refreshFrameValues(result); + })); }), true); } catch (Exception e) { log.warn(SltBundle.message("slt.error.start"), e); diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggers.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggers.java index bb2e642..f8edff6 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggers.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggers.java @@ -14,8 +14,7 @@ import javax.swing.*; import java.awt.*; import java.math.BigInteger; -import java.util.HashMap; -import java.util.Map; +import java.util.*; public class SltDebuggers implements DebugInterface, LispEnvironmentListener { @@ -23,7 +22,8 @@ public class SltDebuggers implements DebugInterface, LispEnvironmentListener { private final JPanel content; private final JBTabsImpl tabs; - private final Map activeDebuggers = new HashMap<>(); + private final Map activeDebuggers = Collections.synchronizedMap(new HashMap<>()); + private final Set toActivateDebuggers = Collections.synchronizedSet(new HashSet<>()); private Content self; public SltDebuggers(ToolWindow toolWindow) { @@ -50,6 +50,11 @@ public void onDebugCreate(SltDebugInfo info) { debugger.redraw(info); activeDebuggers.put(info.getThreadId(), debugger); tabs.addTab(debugger.getTab()); + if (toActivateDebuggers.contains(info.getThreadId())) { + toActivateDebuggers.remove(info.getThreadId()); + + onDebugActivate(info.getThreadId(), null); + } } }); } @@ -62,6 +67,8 @@ public void onDebugActivate(BigInteger debugId, BigInteger level) { tabs.select(activeDebuggers.get(debugId).getTab(), true); tabs.requestFocusInWindow(); toolWindow.getContentManager().setSelectedContent(self, true); + } else { + toActivateDebuggers.add(debugId); } }); } @@ -71,6 +78,8 @@ public void onDebugReturn(BigInteger debugId, BigInteger level) { ApplicationManager.getApplication().invokeLater(() -> { if (activeDebuggers.containsKey(debugId)) { removeDebugger(activeDebuggers.get(debugId), debugId); + } else { + toActivateDebuggers.remove(debugId); } }); } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/instance/ThreadList.java b/src/main/java/com/en_circle/slt/plugin/ui/instance/ThreadList.java index 3119f01..3690d8d 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/instance/ThreadList.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/instance/ThreadList.java @@ -135,31 +135,27 @@ public void removeTableModelListener(TableModelListener l) { private void pauseThread() { int row = table.getSelectionModel().getSelectedIndices()[0]; - Object id = info.getData(row, 0); - if (id instanceof BigInteger lispId) { - try { - LispEnvironmentService.getInstance(project) - .sendToLisp(SuspendThread.suspend(lispId, - () -> ApplicationManager.getApplication().invokeLater(this::refreshThreads)), false); - } catch (Exception e) { - log.warn(SltBundle.message("slt.error.start"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); - } + BigInteger lispId = BigInteger.valueOf(row); + try { + LispEnvironmentService.getInstance(project) + .sendToLisp(SuspendThread.suspend(lispId, + () -> ApplicationManager.getApplication().invokeLater(this::refreshThreads)), false); + } catch (Exception e) { + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } private void terminateThread() { int row = table.getSelectionModel().getSelectedIndices()[0]; - Object id = info.getData(row, 0); - if (id instanceof BigInteger lispId) { - try { - LispEnvironmentService.getInstance(project) - .sendToLisp(KillThread.kill(lispId, - () -> ApplicationManager.getApplication().invokeLater(this::refreshThreads)), false); - } catch (Exception e) { - log.warn(SltBundle.message("slt.error.start"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); - } + BigInteger lispId = BigInteger.valueOf(row); + try { + LispEnvironmentService.getInstance(project) + .sendToLisp(KillThread.kill(lispId, + () -> ApplicationManager.getApplication().invokeLater(this::refreshThreads)), false); + } catch (Exception e) { + log.warn(SltBundle.message("slt.error.start"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start")); } } diff --git a/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java b/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java index 2377cae..a206c76 100644 --- a/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java +++ b/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java @@ -5,6 +5,7 @@ import com.en_circle.slt.plugin.swank.SlimeRequest; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.ApplicationUtil; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.progress.ProgressManager; @@ -34,6 +35,9 @@ public static X getAsyncResultNoThrow(Project project, Function, try { return getAsyncResult(project, request, startLisp); } catch (Exception e) { + if (e instanceof ProcessCanceledException) + return null; + log.warn(e.getMessage()); return null; } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index a1ddbfa..5d82f4b 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -48,6 +48,8 @@ + + From a7446fc78f29688d9d5bbfd9c00cad1e95b0d046 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Thu, 2 Feb 2023 22:52:48 +0100 Subject: [PATCH 12/21] version --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 89cb1c6..5696f90 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "com.en_circle.slt" -version = "0.4.0" +version = "0.3.1" repositories { mavenCentral() From 89d0dbd776057986ad0cc1c3790fb96216ddb392 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Fri, 3 Feb 2023 08:42:36 +0100 Subject: [PATCH 13/21] refactor into two projects --- README.md | 4 +++- .../com/en_circle/slt/tools/RoswellUtils.java | 15 --------------- src/main/resources/META-INF/plugin.xml | 11 +++++------ 3 files changed, 8 insertions(+), 22 deletions(-) delete mode 100644 src/main/java/com/en_circle/slt/tools/RoswellUtils.java diff --git a/README.md b/README.md index 1914a72..384d2ed 100644 --- a/README.md +++ b/README.md @@ -92,4 +92,6 @@ This project is licensed under [Apache License v2](LICENSE.txt). ### What does SLT even mean? -SLT - Speech Language Therapy. Only cure for LISP! \ No newline at end of file +SLT - Speech Language Therapy. Only cure for LISP! + +Also, backronym for Superior Lisp Tooling! \ No newline at end of file diff --git a/src/main/java/com/en_circle/slt/tools/RoswellUtils.java b/src/main/java/com/en_circle/slt/tools/RoswellUtils.java deleted file mode 100644 index 0e59f74..0000000 --- a/src/main/java/com/en_circle/slt/tools/RoswellUtils.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.en_circle.slt.tools; - -public class RoswellUtils { - - public static boolean exists() { - try { - Runtime.getRuntime().exec("ros"); - return true; - } catch (Exception ignored) { - - } - return false; - } - -} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 5d82f4b..5c20c0c 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -24,7 +24,7 @@ - @@ -38,18 +38,17 @@ - + + + - - - - From 7213430f175c4157c9bdda8a27ad428d5c370a5d Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Fri, 3 Feb 2023 08:46:58 +0100 Subject: [PATCH 14/21] refactor into two projects --- .gitmodules | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1d8155c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "SLT-Core"] + path = src/main/lisp + url = https://github.com/Enerccio/SLT-core/ \ No newline at end of file From d147a81e4f67aefe7aa89f3320be29ac30933ca8 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Fri, 3 Feb 2023 08:47:39 +0100 Subject: [PATCH 15/21] refactor into two projects --- src/main/lisp/load.lisp | 37 --------- src/main/lisp/slt/slt-sbcl.lisp | 4 - src/main/lisp/slt/slt.lisp | 91 -------------------- src/main/lisp/swank/swank-backend.lisp | 2 - src/main/lisp/swank/swank-sbcl.lisp | 42 ---------- src/main/lisp/swank/swank.lisp | 111 ------------------------- 6 files changed, 287 deletions(-) delete mode 100644 src/main/lisp/load.lisp delete mode 100644 src/main/lisp/slt/slt-sbcl.lisp delete mode 100644 src/main/lisp/slt/slt.lisp delete mode 100644 src/main/lisp/swank/swank-backend.lisp delete mode 100644 src/main/lisp/swank/swank-sbcl.lisp delete mode 100644 src/main/lisp/swank/swank.lisp diff --git a/src/main/lisp/load.lisp b/src/main/lisp/load.lisp deleted file mode 100644 index e7606fe..0000000 --- a/src/main/lisp/load.lisp +++ /dev/null @@ -1,37 +0,0 @@ -(format T "SLT Interpret ~S~%" +slt-interpret+) - -(defun quit (&optional code) - ;; This group from "clocc-port/ext.lisp" - #+allegro (excl:exit code) - #+clisp (#+lisp=cl ext:quit #-lisp=cl lisp:quit code) - #+cmu (ext:quit code) - #+cormanlisp (win32:exitprocess code) - #+gcl (lisp:bye code) ; XXX Or is it LISP::QUIT? - #+lispworks (lw:quit :status code) - #+lucid (lcl:quit code) - #+sbcl (sb-ext:exit :code code) - ;; This group from Maxima - #+kcl (lisp::bye) ; XXX Does this take an arg? - #+scl (ext:quit code) ; XXX Pretty sure this *does*. - #+(or openmcl mcl) (ccl::quit) - #+abcl (cl-user::quit) - #+ecl (si:quit) - ;; This group from - #+poplog (poplog::bye) ; XXX Does this take an arg? - #-(or allegro clisp cmu cormanlisp gcl lispworks lucid sbc - kcl scl openmcl mcl abcl ecl) - (error 'not-implemented :proc (list 'quit code))) - -(case +slt-interpret+ - (:sbcl (unless (string= "SBCL" - (lisp-implementation-type)) - (format *error-output* "Invalid lisp instance. Maybe a configuration error? This is not SBCL!~%") - (quit 1))) - (otherwise - (format *error-output* "Unsupported lisp instance. Maybe a configuration error?~%") - (quit 1))) - -(load (merge-pathnames "swank/swank.lisp" *load-truename*)) -(load (merge-pathnames "slt/slt.lisp" *load-truename*)) - -(in-package :cl-user) \ No newline at end of file diff --git a/src/main/lisp/slt/slt-sbcl.lisp b/src/main/lisp/slt/slt-sbcl.lisp deleted file mode 100644 index 58d2443..0000000 --- a/src/main/lisp/slt/slt-sbcl.lisp +++ /dev/null @@ -1,4 +0,0 @@ -(in-package :slt-core) - -(defun specialp (test-sym) - (eq (sb-cltl2:variable-information test-sym) :special)) \ No newline at end of file diff --git a/src/main/lisp/slt/slt.lisp b/src/main/lisp/slt/slt.lisp deleted file mode 100644 index a6b59d9..0000000 --- a/src/main/lisp/slt/slt.lisp +++ /dev/null @@ -1,91 +0,0 @@ -(defpackage :slt-core - (:use :cl :swank) - (:export analyze-symbol analyze-symbols read-fix-packages list-package-names - initialize-or-get-debug-context debug-context debug-frame-variable register-variable - )) - -(when (eq +slt-interpret+ :sbcl) - (load (merge-pathnames "slt-sbcl.lisp" *load-truename*))) - -(in-package :slt-core) - -(defun analyze-symbol (test-sym) - (cons test-sym - (let ((*standard-output* (make-string-output-stream))) - (cond - ((not test-sym) (list NIL NIL NIL)) - ((and (fboundp test-sym) - (typep (symbol-function test-sym) 'generic-function)) - (progn - (describe test-sym) - (list :method (get-output-stream-string *standard-output*) - (swank:find-source-location (symbol-function test-sym))))) - ((special-operator-p test-sym) (list :special-form NIL NIL)) - ((macro-function test-sym) (progn - (describe test-sym) - (list - :macro - (get-output-stream-string *standard-output*) - (swank:find-source-location (symbol-function test-sym))))) - ((fboundp test-sym) (progn - (describe test-sym) - (list - :function - (get-output-stream-string *standard-output*) - (swank:find-source-location (symbol-function test-sym))))) - ((specialp test-sym) (progn - (describe test-sym) - (list :special (get-output-stream-string *standard-output*) NIL))) - ((keywordp test-sym) (progn - (describe test-sym) - (list :keyword (get-output-stream-string *standard-output*) NIL))) - ((constantp test-sym) (progn - (describe test-sym) - (list :constant (get-output-stream-string *standard-output*) NIL))) - ((find-class test-sym NIL) (progn - (describe test-sym) - (list :class (get-output-stream-string *standard-output*) - (swank:find-source-location (find-class test-sym))))) - (T (list NIL NIL NIL)))))) - -(defun analyze-symbols (symbols) - (map 'list #'analyze-symbol symbols)) - -(defun reader-recover (c) - (declare (ignorable c)) - (let ((restart (find-restart 'eclector.reader:recover))) - (when restart - (invoke-restart restart)))) - -(defun reader-recover (c) - (declare (ignorable c)) - (let ((restart (find-restart 'eclector.reader:recover))) - (when restart - (invoke-restart restart)))) - -(defun reader-user-anyway (c) - (declare (ignorable c)) - (let ((restart (find-restart 'eclector.reader::use-anyway))) - (when restart - (invoke-restart restart)))) - -(defun read-fix-packages (str) - (handler-bind - ((ECLECTOR.READER:SYMBOL-NAME-MUST-NOT-END-WITH-PACKAGE-MARKER - #'reader-recover) - (ECLECTOR.READER:SYMBOL-IS-NOT-EXTERNAL - #'reader-user-anyway) - (ECLECTOR.READER:SYMBOL-DOES-NOT-EXIST - #'reader-recover) - (ECLECTOR.READER:PACKAGE-DOES-NOT-EXIST - #'reader-recover) - (ECLECTOR.READER:TWO-PACKAGE-MARKERS-MUST-BE-ADJACENT - #'reader-recover) - (error (lambda (c) - (format *error-output* "general error: ~S ~%" c)))) - (eclector.reader:read-from-string str))) - -(defun list-package-names () - (let ((packages (list-all-packages))) - (loop for package in packages collect - (package-name package)))) \ No newline at end of file diff --git a/src/main/lisp/swank/swank-backend.lisp b/src/main/lisp/swank/swank-backend.lisp deleted file mode 100644 index 4ee393a..0000000 --- a/src/main/lisp/swank/swank-backend.lisp +++ /dev/null @@ -1,2 +0,0 @@ -(in-package swank/backend) - diff --git a/src/main/lisp/swank/swank-sbcl.lisp b/src/main/lisp/swank/swank-sbcl.lisp deleted file mode 100644 index 6379d61..0000000 --- a/src/main/lisp/swank/swank-sbcl.lisp +++ /dev/null @@ -1,42 +0,0 @@ -(in-package sb-debug) - -(export 'frame-code-location) -(export 'frame-call) -(export 'ensure-printable-object) -(export 'code-location-source-form) - -(in-package :swank/sbcl) - -(defun form-number-position (definition-source stream) - (let* ((tlf-number (car (sb-introspect:definition-source-form-path definition-source))) - (form-number (sb-introspect:definition-source-form-number definition-source))) - (multiple-value-bind (tlf pos-map) (read-source-form tlf-number stream) - (let* ((path-table (sb-di::form-number-translations tlf 0)) - (path (cond ((<= (length path-table) form-number) - ; (warn "inconsistent form-number-translations") ; this fucks up stderr wtf - (list 0)) - (t - (reverse (cdr (aref path-table form-number))))))) - (source-path-source-position path tlf pos-map))))) - -(defun stream-source-position (code-location stream) - (let* ((cloc (sb-debug::maybe-block-start-location code-location)) - (tlf-number (sb-di::code-location-toplevel-form-offset cloc)) - (form-number (sb-di::code-location-form-number cloc))) - (multiple-value-bind (tlf pos-map) (read-source-form tlf-number stream) - (let* ((path-table (sb-di::form-number-translations tlf 0)) - (path (cond ((<= (length path-table) form-number) - ; (warn "inconsistent form-number-translations") ; same as above - (list 0)) - (t - (reverse (cdr (aref path-table form-number))))))) - (source-path-source-position path tlf pos-map))))) - -(in-package :swank) - -(defun print-frame-call-place (frame) - (multiple-value-bind (name args info) - (SB-DEBUG:frame-call frame) - (declare (ignore args info)) - (let ((name (SB-DEBUG:ensure-printable-object name))) - name))) \ No newline at end of file diff --git a/src/main/lisp/swank/swank.lisp b/src/main/lisp/swank/swank.lisp deleted file mode 100644 index 6bb209e..0000000 --- a/src/main/lisp/swank/swank.lisp +++ /dev/null @@ -1,111 +0,0 @@ -(load (merge-pathnames "swank-backend.lisp" *load-truename*)) -(when (eq +slt-interpret+ :sbcl) - (load (merge-pathnames "swank-sbcl.lisp" *load-truename*))) - -(in-package swank/source-file-cache) - -(setf *SOURCE-SNIPPET-SIZE* 0) - -(in-package :swank) - -(export 'find-source-location) - -(defslimefun slt-eval (string) - (let ((*echo-area-prefix* "")) - (with-buffer-syntax () - (with-retry-restart (:msg "Retry SLIME interactive evaluation request.") - (let ((values (multiple-value-list (eval (from-string string))))) - (finish-output) - (format-values-for-echo-area values)))))) - -(defslimefun invoke-nth-restart-slt (sldb-level n args rest) - (when (= sldb-level *sldb-level*) - (let ((restart (nth-restart n)) - (parsed-args (from-string args)) - (parsed-rest (from-string rest))) - (when restart - (if (or parsed-args parsed-rest) - (apply #'invoke-restart (concatenate 'list (list restart) parsed-args parsed-rest)) - (invoke-restart restart)))))) - -(defun format-restarts-for-emacs () - "Return a list of restarts for *swank-debugger-condition* in a -format suitable for Emacs." - (let ((*print-right-margin* most-positive-fixnum)) - (loop for restart in *sldb-restarts* collect - (list (format nil "~:[~;*~]~a" - (eq restart *sldb-quit-restart*) - (restart-name restart)) - (with-output-to-string (stream) - (without-printing-errors (:object restart - :stream stream - :msg "<>") - (princ restart stream))) - (swank-backend:arglist (slot-value restart 'function)))))) - -(defslimefun backtrace (start end) - (loop for frame in (compute-backtrace start end) - for i from start collect - (list i (frame-to-string frame) - (format NIL "~S" (print-frame-call-place frame)) - (frame-source-location i) - (let ((pkg (frame-package i))) - (cond - (pkg (package-name pkg)) - (T NIL)))))) - -(defslimefun compile-string-region-slt (string buffer offset filename package) - (with-buffer-syntax () - (collect-notes - (lambda () - (let ((*compile-print* t) (*compile-verbose* nil) (*package* (find-package package))) - (swank-compile-string string - :buffer buffer - :position offset - :filename filename)))))) - -(defun get-all-symbols () - (let ((data '())) - (do-symbols (s) - (push (list (unparse-symbol s) s (symbol-package s)) data)) - (remove-duplicates data :key (lambda (e) (second e))))) - -(defun get-all-symbols-with-prefix (prefix) - (let ((all (get-all-symbols))) - (loop for data-pair in all - when (prefix-match-p prefix (first data-pair)) - collect data-pair))) - -(defun find-reference-class-filter (symbol package) - (find-class symbol NIL)) - -(defun get-reference-prefix (prefix type) - (let ((apply-func (cond - ((eq type :class) #'find-reference-class-filter) - (T (lambda (symbol package) T))))) - (let ((filtered-symbols (get-all-symbols-with-prefix prefix))) - (loop for data-pair in filtered-symbols - when (funcall apply-func (second data-pair) (third data-pair)) - collect - (let* ((symbol (second data-pair)) - (str (first data-pair)) - (package (third data-pair)) - (strpackage (format NIL "~S" package))) - (cond - ((not symbol) (list str strpackage NIL NIL)) - ((macro-function symbol) (list str strpackage :macro (find-source-location (symbol-function symbol)))) - ((and (fboundp symbol) - (typep (symbol-function symbol) 'generic-function)) - (list str strpackage :method (find-source-location (symbol-function symbol)))) - ((fboundp symbol) (list str strpackage :function (find-source-location (symbol-function symbol)))) - ((find-class symbol NIL) (list str strpackage :class (find-source-location (find-class symbol)))) - (T (list str strpackage NIL NIL)))))))) - -(defslimefun find-reference-prefix (prefix type) - (let ((references (get-reference-prefix prefix type))) - (when references - (sort references #'string< :key (lambda (x) (first x)))))) - -(export 'slt-eval) -(export 'compile-string-region-slt) -(export 'find-reference-prefix) \ No newline at end of file From 79b4eb5ce35f1a051d3b639c7dddeadfa7a45ffa Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Fri, 3 Feb 2023 08:49:27 +0100 Subject: [PATCH 16/21] refactor into two projects --- .gitmodules | 4 ++-- src/main/lisp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 160000 src/main/lisp diff --git a/.gitmodules b/.gitmodules index 1d8155c..54c1d72 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "SLT-Core"] +[submodule "src/main/lisp"] path = src/main/lisp - url = https://github.com/Enerccio/SLT-core/ \ No newline at end of file + url = https://github.com/Enerccio/SLT-core.git diff --git a/src/main/lisp b/src/main/lisp new file mode 160000 index 0000000..3ba9dc0 --- /dev/null +++ b/src/main/lisp @@ -0,0 +1 @@ +Subproject commit 3ba9dc06c8dfe0ebd33d11358359de5e60b4165c From ae53f50bf712e5088243d2402a27aec4283042f8 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Fri, 3 Feb 2023 14:00:09 +0100 Subject: [PATCH 17/21] refactor back to one project --- .gitmodules | 3 --- build.gradle.kts | 5 ++++- src/main/resources/META-INF/plugin.xml | 4 ++-- .../{Asdf System.asdf.ft => Asdf System.asd.ft} | 0 src/main/resources/templates/en_US/initscript.cl | 5 ++++- 5 files changed, 10 insertions(+), 7 deletions(-) delete mode 100644 .gitmodules rename src/main/resources/fileTemplates/{Asdf System.asdf.ft => Asdf System.asd.ft} (100%) diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 54c1d72..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "src/main/lisp"] - path = src/main/lisp - url = https://github.com/Enerccio/SLT-core.git diff --git a/build.gradle.kts b/build.gradle.kts index 5696f90..e045788 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -49,7 +49,10 @@ tasks { from("src/main/lisp") archiveFileName.set("slt.zip") destinationDirectory.set(File("build/resources/main")) - include("**/*.*") + include("**/*.lisp") + include("**/*.cl") + include("**/*.asdf") + include("LICENSE.txt") doFirst { println("Zipping SLT to " + destinationDirectory.get()) diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 5c20c0c..79749ba 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -53,10 +53,10 @@ - + diff --git a/src/main/resources/fileTemplates/Asdf System.asdf.ft b/src/main/resources/fileTemplates/Asdf System.asd.ft similarity index 100% rename from src/main/resources/fileTemplates/Asdf System.asdf.ft rename to src/main/resources/fileTemplates/Asdf System.asd.ft diff --git a/src/main/resources/templates/en_US/initscript.cl b/src/main/resources/templates/en_US/initscript.cl index b99edc0..8ba3558 100644 --- a/src/main/resources/templates/en_US/initscript.cl +++ b/src/main/resources/templates/en_US/initscript.cl @@ -1,4 +1,7 @@ -(in-package :cl) +(defpackage :slt + (:use :cl) + (:export +slt-interpret+)) + (defconstant +slt-interpret+ ~interpret~ "Defines current slt interpret. For SBCL the value is :sbcl") From de256af8aded1f5f634dda04a7697d1cb3269434 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Fri, 3 Feb 2023 14:03:57 +0100 Subject: [PATCH 18/21] refactor back to one project --- src/main/lisp | 1 - src/main/lisp/load.lisp | 38 +++++++++ src/main/lisp/slt/slt-sbcl.lisp | 4 + src/main/lisp/slt/slt.lisp | 91 ++++++++++++++++++++ src/main/lisp/swank/swank-backend.lisp | 2 + src/main/lisp/swank/swank-sbcl.lisp | 42 ++++++++++ src/main/lisp/swank/swank.lisp | 111 +++++++++++++++++++++++++ 7 files changed, 288 insertions(+), 1 deletion(-) delete mode 160000 src/main/lisp create mode 100644 src/main/lisp/load.lisp create mode 100644 src/main/lisp/slt/slt-sbcl.lisp create mode 100644 src/main/lisp/slt/slt.lisp create mode 100644 src/main/lisp/swank/swank-backend.lisp create mode 100644 src/main/lisp/swank/swank-sbcl.lisp create mode 100644 src/main/lisp/swank/swank.lisp diff --git a/src/main/lisp b/src/main/lisp deleted file mode 160000 index 3ba9dc0..0000000 --- a/src/main/lisp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3ba9dc06c8dfe0ebd33d11358359de5e60b4165c diff --git a/src/main/lisp/load.lisp b/src/main/lisp/load.lisp new file mode 100644 index 0000000..610a99c --- /dev/null +++ b/src/main/lisp/load.lisp @@ -0,0 +1,38 @@ +(eval-when (:execute) + (format T "SLT Interpret ~S~%" slt:+slt-interpret+)) + +(defun portable-quit (&optional code) + ;; This group from "clocc-port/ext.lisp" + #+allegro (excl:exit code) + #+clisp (#+lisp=cl ext:quit #-lisp=cl lisp:quit code) + #+cmu (ext:quit code) + #+cormanlisp (win32:exitprocess code) + #+gcl (lisp:bye code) ; XXX Or is it LISP::QUIT? + #+lispworks (lw:quit :status code) + #+lucid (lcl:quit code) + #+sbcl (sb-ext:exit :code code) + ;; This group from Maxima + #+kcl (lisp::bye) ; XXX Does this take an arg? + #+scl (ext:quit code) ; XXX Pretty sure this *does*. + #+(or openmcl mcl) (ccl::quit) + #+abcl (cl-user::quit) + #+ecl (si:quit) + ;; This group from + #+poplog (poplog::bye) ; XXX Does this take an arg? + #-(or allegro clisp cmu cormanlisp gcl lispworks lucid sbc + kcl scl openmcl mcl abcl ecl) + (error 'not-implemented :proc (list 'quit code))) + +(case slt:+slt-interpret+ + (:sbcl (unless (string= "SBCL" + (lisp-implementation-type)) + (format *error-output* "Invalid lisp instance. Maybe a configuration error? This is not SBCL!~%") + (portable-quit 1))) + (otherwise + (format *error-output* "Unsupported lisp instance. Maybe a configuration error?~%") + (portable-quit 1))) + +(load (merge-pathnames "swank/swank.lisp" *load-truename*)) +(load (merge-pathnames "slt/slt.lisp" *load-truename*)) + +(in-package :cl-user) \ No newline at end of file diff --git a/src/main/lisp/slt/slt-sbcl.lisp b/src/main/lisp/slt/slt-sbcl.lisp new file mode 100644 index 0000000..58d2443 --- /dev/null +++ b/src/main/lisp/slt/slt-sbcl.lisp @@ -0,0 +1,4 @@ +(in-package :slt-core) + +(defun specialp (test-sym) + (eq (sb-cltl2:variable-information test-sym) :special)) \ No newline at end of file diff --git a/src/main/lisp/slt/slt.lisp b/src/main/lisp/slt/slt.lisp new file mode 100644 index 0000000..a4a9f10 --- /dev/null +++ b/src/main/lisp/slt/slt.lisp @@ -0,0 +1,91 @@ +(defpackage :slt-core + (:use :slt :cl :swank) + (:export analyze-symbol analyze-symbols read-fix-packages list-package-names + initialize-or-get-debug-context debug-context debug-frame-variable register-variable + )) + +(when (eq slt:+slt-interpret+ :sbcl) + (load (merge-pathnames "slt-sbcl.lisp" *load-truename*))) + +(in-package :slt-core) + +(defun analyze-symbol (test-sym) + (cons test-sym + (let ((*standard-output* (make-string-output-stream))) + (cond + ((not test-sym) (list NIL NIL NIL)) + ((and (fboundp test-sym) + (typep (symbol-function test-sym) 'generic-function)) + (progn + (describe test-sym) + (list :method (get-output-stream-string *standard-output*) + (swank:find-source-location (symbol-function test-sym))))) + ((special-operator-p test-sym) (list :special-form NIL NIL)) + ((macro-function test-sym) (progn + (describe test-sym) + (list + :macro + (get-output-stream-string *standard-output*) + (swank:find-source-location (symbol-function test-sym))))) + ((fboundp test-sym) (progn + (describe test-sym) + (list + :function + (get-output-stream-string *standard-output*) + (swank:find-source-location (symbol-function test-sym))))) + ((specialp test-sym) (progn + (describe test-sym) + (list :special (get-output-stream-string *standard-output*) NIL))) + ((keywordp test-sym) (progn + (describe test-sym) + (list :keyword (get-output-stream-string *standard-output*) NIL))) + ((constantp test-sym) (progn + (describe test-sym) + (list :constant (get-output-stream-string *standard-output*) NIL))) + ((find-class test-sym NIL) (progn + (describe test-sym) + (list :class (get-output-stream-string *standard-output*) + (swank:find-source-location (find-class test-sym))))) + (T (list NIL NIL NIL)))))) + +(defun analyze-symbols (symbols) + (map 'list #'analyze-symbol symbols)) + +(defun reader-recover (c) + (declare (ignorable c)) + (let ((restart (find-restart 'eclector.reader:recover))) + (when restart + (invoke-restart restart)))) + +(defun reader-recover (c) + (declare (ignorable c)) + (let ((restart (find-restart 'eclector.reader:recover))) + (when restart + (invoke-restart restart)))) + +(defun reader-user-anyway (c) + (declare (ignorable c)) + (let ((restart (find-restart 'eclector.reader::use-anyway))) + (when restart + (invoke-restart restart)))) + +(defun read-fix-packages (str) + (handler-bind + ((ECLECTOR.READER:SYMBOL-NAME-MUST-NOT-END-WITH-PACKAGE-MARKER + #'reader-recover) + (ECLECTOR.READER:SYMBOL-IS-NOT-EXTERNAL + #'reader-user-anyway) + (ECLECTOR.READER:SYMBOL-DOES-NOT-EXIST + #'reader-recover) + (ECLECTOR.READER:PACKAGE-DOES-NOT-EXIST + #'reader-recover) + (ECLECTOR.READER:TWO-PACKAGE-MARKERS-MUST-BE-ADJACENT + #'reader-recover) + (error (lambda (c) + (format *error-output* "general error: ~S ~%" c)))) + (eclector.reader:read-from-string str))) + +(defun list-package-names () + (let ((packages (list-all-packages))) + (loop for package in packages collect + (package-name package)))) \ No newline at end of file diff --git a/src/main/lisp/swank/swank-backend.lisp b/src/main/lisp/swank/swank-backend.lisp new file mode 100644 index 0000000..4ee393a --- /dev/null +++ b/src/main/lisp/swank/swank-backend.lisp @@ -0,0 +1,2 @@ +(in-package swank/backend) + diff --git a/src/main/lisp/swank/swank-sbcl.lisp b/src/main/lisp/swank/swank-sbcl.lisp new file mode 100644 index 0000000..6379d61 --- /dev/null +++ b/src/main/lisp/swank/swank-sbcl.lisp @@ -0,0 +1,42 @@ +(in-package sb-debug) + +(export 'frame-code-location) +(export 'frame-call) +(export 'ensure-printable-object) +(export 'code-location-source-form) + +(in-package :swank/sbcl) + +(defun form-number-position (definition-source stream) + (let* ((tlf-number (car (sb-introspect:definition-source-form-path definition-source))) + (form-number (sb-introspect:definition-source-form-number definition-source))) + (multiple-value-bind (tlf pos-map) (read-source-form tlf-number stream) + (let* ((path-table (sb-di::form-number-translations tlf 0)) + (path (cond ((<= (length path-table) form-number) + ; (warn "inconsistent form-number-translations") ; this fucks up stderr wtf + (list 0)) + (t + (reverse (cdr (aref path-table form-number))))))) + (source-path-source-position path tlf pos-map))))) + +(defun stream-source-position (code-location stream) + (let* ((cloc (sb-debug::maybe-block-start-location code-location)) + (tlf-number (sb-di::code-location-toplevel-form-offset cloc)) + (form-number (sb-di::code-location-form-number cloc))) + (multiple-value-bind (tlf pos-map) (read-source-form tlf-number stream) + (let* ((path-table (sb-di::form-number-translations tlf 0)) + (path (cond ((<= (length path-table) form-number) + ; (warn "inconsistent form-number-translations") ; same as above + (list 0)) + (t + (reverse (cdr (aref path-table form-number))))))) + (source-path-source-position path tlf pos-map))))) + +(in-package :swank) + +(defun print-frame-call-place (frame) + (multiple-value-bind (name args info) + (SB-DEBUG:frame-call frame) + (declare (ignore args info)) + (let ((name (SB-DEBUG:ensure-printable-object name))) + name))) \ No newline at end of file diff --git a/src/main/lisp/swank/swank.lisp b/src/main/lisp/swank/swank.lisp new file mode 100644 index 0000000..6bb209e --- /dev/null +++ b/src/main/lisp/swank/swank.lisp @@ -0,0 +1,111 @@ +(load (merge-pathnames "swank-backend.lisp" *load-truename*)) +(when (eq +slt-interpret+ :sbcl) + (load (merge-pathnames "swank-sbcl.lisp" *load-truename*))) + +(in-package swank/source-file-cache) + +(setf *SOURCE-SNIPPET-SIZE* 0) + +(in-package :swank) + +(export 'find-source-location) + +(defslimefun slt-eval (string) + (let ((*echo-area-prefix* "")) + (with-buffer-syntax () + (with-retry-restart (:msg "Retry SLIME interactive evaluation request.") + (let ((values (multiple-value-list (eval (from-string string))))) + (finish-output) + (format-values-for-echo-area values)))))) + +(defslimefun invoke-nth-restart-slt (sldb-level n args rest) + (when (= sldb-level *sldb-level*) + (let ((restart (nth-restart n)) + (parsed-args (from-string args)) + (parsed-rest (from-string rest))) + (when restart + (if (or parsed-args parsed-rest) + (apply #'invoke-restart (concatenate 'list (list restart) parsed-args parsed-rest)) + (invoke-restart restart)))))) + +(defun format-restarts-for-emacs () + "Return a list of restarts for *swank-debugger-condition* in a +format suitable for Emacs." + (let ((*print-right-margin* most-positive-fixnum)) + (loop for restart in *sldb-restarts* collect + (list (format nil "~:[~;*~]~a" + (eq restart *sldb-quit-restart*) + (restart-name restart)) + (with-output-to-string (stream) + (without-printing-errors (:object restart + :stream stream + :msg "<>") + (princ restart stream))) + (swank-backend:arglist (slot-value restart 'function)))))) + +(defslimefun backtrace (start end) + (loop for frame in (compute-backtrace start end) + for i from start collect + (list i (frame-to-string frame) + (format NIL "~S" (print-frame-call-place frame)) + (frame-source-location i) + (let ((pkg (frame-package i))) + (cond + (pkg (package-name pkg)) + (T NIL)))))) + +(defslimefun compile-string-region-slt (string buffer offset filename package) + (with-buffer-syntax () + (collect-notes + (lambda () + (let ((*compile-print* t) (*compile-verbose* nil) (*package* (find-package package))) + (swank-compile-string string + :buffer buffer + :position offset + :filename filename)))))) + +(defun get-all-symbols () + (let ((data '())) + (do-symbols (s) + (push (list (unparse-symbol s) s (symbol-package s)) data)) + (remove-duplicates data :key (lambda (e) (second e))))) + +(defun get-all-symbols-with-prefix (prefix) + (let ((all (get-all-symbols))) + (loop for data-pair in all + when (prefix-match-p prefix (first data-pair)) + collect data-pair))) + +(defun find-reference-class-filter (symbol package) + (find-class symbol NIL)) + +(defun get-reference-prefix (prefix type) + (let ((apply-func (cond + ((eq type :class) #'find-reference-class-filter) + (T (lambda (symbol package) T))))) + (let ((filtered-symbols (get-all-symbols-with-prefix prefix))) + (loop for data-pair in filtered-symbols + when (funcall apply-func (second data-pair) (third data-pair)) + collect + (let* ((symbol (second data-pair)) + (str (first data-pair)) + (package (third data-pair)) + (strpackage (format NIL "~S" package))) + (cond + ((not symbol) (list str strpackage NIL NIL)) + ((macro-function symbol) (list str strpackage :macro (find-source-location (symbol-function symbol)))) + ((and (fboundp symbol) + (typep (symbol-function symbol) 'generic-function)) + (list str strpackage :method (find-source-location (symbol-function symbol)))) + ((fboundp symbol) (list str strpackage :function (find-source-location (symbol-function symbol)))) + ((find-class symbol NIL) (list str strpackage :class (find-source-location (find-class symbol)))) + (T (list str strpackage NIL NIL)))))))) + +(defslimefun find-reference-prefix (prefix type) + (let ((references (get-reference-prefix prefix type))) + (when references + (sort references #'string< :key (lambda (x) (first x)))))) + +(export 'slt-eval) +(export 'compile-string-region-slt) +(export 'find-reference-prefix) \ No newline at end of file From 21652258b45ff125bc7b9aca0bf70d5e3349cfb3 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Fri, 3 Feb 2023 17:19:44 +0100 Subject: [PATCH 19/21] fixed grammar, prepared for argslist --- .../en_circle/slt/plugin/lisp/LispLexer.java | 338 +++++++++--------- .../en_circle/slt/plugin/lisp/LispParser.java | 5 +- .../slt/plugin/lisp/psi/LispTypes.java | 3 +- .../highlights/SltStaticHighlighter.java | 4 +- .../annotators/SymbolAnnotator.java | 12 +- .../com/en_circle/slt/plugin/lisp/Lisp.bnf | 2 +- .../com/en_circle/slt/plugin/lisp/Lisp.flex | 9 +- .../slt/plugin/lisp/LispParserUtil.java | 190 ++++++++++ .../lisp/LispEnvironmentServiceImpl.java | 2 + src/main/lisp/swank/swank.lisp | 9 +- .../resources/templates/en_US/initscript.cl | 1 + 11 files changed, 403 insertions(+), 172 deletions(-) diff --git a/src/main/gen/com/en_circle/slt/plugin/lisp/LispLexer.java b/src/main/gen/com/en_circle/slt/plugin/lisp/LispLexer.java index 607f307..379b87b 100644 --- a/src/main/gen/com/en_circle/slt/plugin/lisp/LispLexer.java +++ b/src/main/gen/com/en_circle/slt/plugin/lisp/LispLexer.java @@ -24,22 +24,23 @@ class LispLexer implements FlexLexer { /** lexical states */ public static final int YYINITIAL = 0; - public static final int LINE_COMMENT = 2; - public static final int STRING = 4; - public static final int STRING_ESCAPE = 6; - public static final int SHARPSIGN = 8; - public static final int BIT_ARRAY = 10; - public static final int CHARACTER = 12; - public static final int BLOCK_COMMENT = 14; - public static final int BLOCK_COMMENT_TEST = 16; - public static final int BINARY_NUM = 18; - public static final int OCTAL_NUM = 20; - public static final int RADIX_NUM = 22; - public static final int HEX_NUM = 24; - public static final int STEP8 = 26; - public static final int STEP8ESCAPE = 28; - public static final int STEP9 = 30; - public static final int STEP9ESCAPE = 32; + public static final int UNQUOTE_STATE = 2; + public static final int LINE_COMMENT = 4; + public static final int STRING = 6; + public static final int STRING_ESCAPE = 8; + public static final int SHARPSIGN = 10; + public static final int BIT_ARRAY = 12; + public static final int CHARACTER = 14; + public static final int BLOCK_COMMENT = 16; + public static final int BLOCK_COMMENT_TEST = 18; + public static final int BINARY_NUM = 20; + public static final int OCTAL_NUM = 22; + public static final int RADIX_NUM = 24; + public static final int HEX_NUM = 26; + public static final int STEP8 = 28; + public static final int STEP8ESCAPE = 30; + public static final int STEP9 = 32; + public static final int STEP9ESCAPE = 34; /** * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l @@ -50,7 +51,7 @@ class LispLexer implements FlexLexer { private static final int ZZ_LEXSTATE[] = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, - 16, 16 + 16, 16, 17, 17 }; /** @@ -72,11 +73,11 @@ public static int ZZ_CMAP(int ch) { /* The ZZ_CMAP_A table has 256 entries */ static final char ZZ_CMAP_A[] = zzUnpackCMap( - "\11\0\1\1\1\14\1\0\1\1\1\14\22\0\1\1\1\17\1\10\1\12\3\17\1\6\1\4\1\5\1\20"+ - "\1\23\1\3\1\24\1\25\1\26\2\40\6\41\2\16\1\21\1\7\1\2\1\22\3\17\1\27\1\30\1"+ - "\31\3\42\10\32\1\33\1\34\1\32\1\35\1\36\4\32\1\37\2\32\1\17\1\15\3\17\1\11"+ - "\1\27\1\30\1\31\3\42\10\32\1\33\1\34\1\32\1\35\1\36\4\32\1\37\2\32\1\17\1"+ - "\13\2\17\201\0"); + "\11\0\1\1\1\15\1\0\1\1\1\15\22\0\1\1\1\20\1\10\1\12\3\20\1\6\1\4\1\5\1\21"+ + "\1\24\1\3\1\25\1\26\1\27\2\41\6\42\2\17\1\22\1\7\1\2\1\23\2\20\1\14\1\30\1"+ + "\31\1\32\3\43\10\33\1\34\1\35\1\33\1\36\1\37\4\33\1\40\2\33\1\20\1\16\3\20"+ + "\1\11\1\30\1\31\1\32\3\43\10\33\1\34\1\35\1\33\1\36\1\37\4\33\1\40\2\33\1"+ + "\20\1\13\2\20\201\0"); /** * Translates DFA states to action switch labels. @@ -84,16 +85,16 @@ public static int ZZ_CMAP(int ch) { private static final int [] ZZ_ACTION = zzUnpackAction(); private static final String ZZ_ACTION_PACKED_0 = - "\21\0\1\1\1\2\1\3\1\4\1\5\1\6\1\7"+ + "\22\0\1\1\1\2\1\3\1\4\1\5\1\6\1\7"+ "\1\10\1\11\1\12\1\13\1\14\1\15\1\16\1\17"+ "\1\20\1\21\1\22\1\23\1\24\1\25\1\26\1\27"+ "\1\30\1\31\1\32\1\33\1\34\1\35\1\36\1\37"+ "\1\40\1\41\1\42\1\43\1\44\1\45\1\46\1\47"+ "\1\50\1\51\1\52\1\53\1\54\1\55\1\56\1\57"+ - "\1\60\1\61\1\62\1\63\1\64"; + "\1\60\1\61\1\62\1\63\1\64\1\65\1\66"; private static int [] zzUnpackAction() { - int [] result = new int[69]; + int [] result = new int[72]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -118,18 +119,18 @@ private static int zzUnpackAction(String packed, int offset, int [] result) { private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\43\0\106\0\151\0\214\0\257\0\322\0\365"+ - "\0\u0118\0\u013b\0\u015e\0\u0181\0\u01a4\0\u01c7\0\u01ea\0\u020d"+ - "\0\u0230\0\u0253\0\u0276\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253"+ - "\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253"+ - "\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253"+ - "\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253"+ - "\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253"+ - "\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253"+ - "\0\u0253\0\u0253\0\u0253\0\u0253\0\u0253"; + "\0\0\0\44\0\110\0\154\0\220\0\264\0\330\0\374"+ + "\0\u0120\0\u0144\0\u0168\0\u018c\0\u01b0\0\u01d4\0\u01f8\0\u021c"+ + "\0\u0240\0\u0264\0\u0288\0\u02ac\0\u0288\0\u0288\0\u0288\0\u0288"+ + "\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288"+ + "\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288"+ + "\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288"+ + "\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288"+ + "\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288"+ + "\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288\0\u0288"; private static int [] zzUnpackRowMap() { - int [] result = new int[69]; + int [] result = new int[72]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -152,23 +153,24 @@ private static int zzUnpackRowMap(String packed, int offset, int [] result) { private static final int [] ZZ_TRANS = zzUnpackTrans(); private static final String ZZ_TRANS_PACKED_0 = - "\1\22\1\23\1\24\1\25\1\26\1\27\1\30\1\31"+ - "\1\32\1\33\1\34\1\35\1\23\1\22\25\24\14\36"+ - "\1\37\36\36\1\40\4\36\1\41\25\36\43\32\3\22"+ - "\1\42\1\43\1\22\1\44\3\42\1\45\1\46\1\22"+ - "\1\47\1\36\1\42\1\50\1\51\1\52\1\53\1\54"+ - "\1\55\1\42\1\56\1\57\1\60\1\42\1\61\1\62"+ - "\1\63\1\64\1\65\2\36\1\42\13\66\1\36\24\66"+ - "\1\36\2\66\43\67\13\36\1\70\27\36\12\46\1\71"+ - "\30\46\26\72\1\36\11\72\1\36\2\72\26\73\1\36"+ - "\11\73\2\36\1\73\16\74\1\36\7\74\15\36\16\75"+ - "\1\36\7\75\4\36\6\75\3\36\1\0\1\76\1\77"+ - "\7\76\1\77\1\100\1\76\1\101\25\77\43\102\1\0"+ - "\12\77\1\103\1\77\1\104\25\77\43\105\44\0\1\23"+ - "\12\0\1\23\26\0"; + "\1\23\1\24\1\25\1\26\1\27\1\30\1\31\1\32"+ + "\1\33\1\34\1\35\1\36\1\25\1\24\1\23\25\25"+ + "\14\37\1\40\27\37\15\41\1\42\36\41\1\43\5\41"+ + "\1\44\25\41\44\33\3\23\1\45\1\46\1\23\1\47"+ + "\3\45\1\50\1\51\1\45\1\23\1\52\1\41\1\45"+ + "\1\53\1\54\1\55\1\56\1\57\1\60\1\45\1\61"+ + "\1\62\1\63\1\45\1\64\1\65\1\66\1\67\1\70"+ + "\2\41\1\45\13\71\1\41\25\71\1\41\2\71\44\72"+ + "\13\41\1\73\30\41\12\51\1\74\31\51\27\75\1\41"+ + "\11\75\1\41\2\75\27\76\1\41\11\76\2\41\1\76"+ + "\17\77\1\41\7\77\15\41\17\100\1\41\7\100\4\41"+ + "\6\100\3\41\1\0\1\101\1\102\7\101\1\102\1\103"+ + "\1\102\1\101\1\104\25\102\44\105\1\0\12\102\1\106"+ + "\2\102\1\107\25\102\44\110\45\0\1\24\13\0\1\24"+ + "\26\0"; private static int [] zzUnpackTrans() { - int [] result = new int[665]; + int [] result = new int[720]; int offset = 0; offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -206,10 +208,10 @@ private static int zzUnpackTrans(String packed, int offset, int [] result) { private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\21\0\1\11\1\1\62\11"; + "\22\0\1\11\1\1\64\11"; private static int [] zzUnpackAttribute() { - int [] result = new int[69]; + int [] result = new int[72]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -535,71 +537,75 @@ else if (zzAtEOF) { case YYINITIAL: { return null; } // fall though - case 70: break; + case 73: break; + case UNQUOTE_STATE: { + yybegin(YYINITIAL); return LispTypes.UNQUOTE; + } // fall though + case 74: break; case LINE_COMMENT: { yybegin(YYINITIAL); return LispTypes.LINE_COMMENT; } // fall though - case 71: break; + case 75: break; case STRING: { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } // fall though - case 72: break; + case 76: break; case STRING_ESCAPE: { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } // fall though - case 73: break; + case 77: break; case SHARPSIGN: { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } // fall though - case 74: break; + case 78: break; case BIT_ARRAY: { yybegin(YYINITIAL); yypushback(1); return LispTypes.BIT_ARRAY; } // fall though - case 75: break; + case 79: break; case CHARACTER: { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } // fall though - case 76: break; + case 80: break; case BLOCK_COMMENT: { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } // fall though - case 77: break; + case 81: break; case BLOCK_COMMENT_TEST: { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } // fall though - case 78: break; + case 82: break; case BINARY_NUM: { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } // fall though - case 79: break; + case 83: break; case OCTAL_NUM: { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } // fall though - case 80: break; + case 84: break; case RADIX_NUM: { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } // fall though - case 81: break; + case 85: break; case HEX_NUM: { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } // fall though - case 82: break; + case 86: break; case STEP8: { yybegin(YYINITIAL); return processBuffer(false); } // fall though - case 83: break; + case 87: break; case STEP8ESCAPE: { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } // fall though - case 84: break; + case 88: break; case STEP9: { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } // fall though - case 85: break; + case 89: break; case STEP9ESCAPE: { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } // fall though - case 86: break; + case 90: break; default: return null; } @@ -610,262 +616,272 @@ else if (zzAtEOF) { { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } // fall through - case 53: break; + case 55: break; case 2: { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; } // fall through - case 54: break; + case 56: break; case 3: { yybegin(STEP8); escapeCount=0; tokenBuffer.setLength(0); tokenBuffer.append(yytext()); } // fall through - case 55: break; + case 57: break; case 4: - { yybegin(YYINITIAL); return LispTypes.COMMA; + { yybegin(UNQUOTE_STATE); } // fall through - case 56: break; + case 58: break; case 5: { yybegin(YYINITIAL); return LispTypes.LPAREN; } // fall through - case 57: break; + case 59: break; case 6: { yybegin(YYINITIAL); return LispTypes.RPAREN; } // fall through - case 58: break; + case 60: break; case 7: { yybegin(YYINITIAL); return LispTypes.QUOTE; } // fall through - case 59: break; + case 61: break; case 8: { yybegin(LINE_COMMENT); } // fall through - case 60: break; + case 62: break; case 9: { yybegin(STRING); } // fall through - case 61: break; + case 63: break; case 10: { yybegin(YYINITIAL); return LispTypes.BACKQUOTE; } // fall through - case 62: break; + case 64: break; case 11: { yybegin(SHARPSIGN); } // fall through - case 63: break; + case 65: break; case 12: { yybegin(STEP9); escapeCount=1; tokenBuffer.setLength(0); } // fall through - case 64: break; + case 66: break; case 13: - { + { yybegin(YYINITIAL); yypushback(1); return LispTypes.UNQUOTE; } // fall through - case 65: break; + case 67: break; case 14: - { yybegin(YYINITIAL); return LispTypes.LINE_COMMENT; + { yybegin(YYINITIAL); return LispTypes.UNQUOTE_SPLICE; } // fall through - case 66: break; + case 68: break; case 15: - { yybegin(YYINITIAL); return LispTypes.STRING_TOKEN; + { } // fall through - case 67: break; + case 69: break; case 16: - { yybegin(STRING_ESCAPE); + { yybegin(YYINITIAL); return LispTypes.LINE_COMMENT; } // fall through - case 68: break; + case 70: break; case 17: - { yybegin(YYINITIAL); return LispTypes.UNDEFINED_SEQUENCE; + { yybegin(YYINITIAL); return LispTypes.STRING_TOKEN; } // fall through - case 69: break; + case 71: break; case 18: - { yybegin(YYINITIAL); return LispTypes.HASH_LPAREN; + { yybegin(STRING_ESCAPE); } // fall through - case 70: break; + case 72: break; case 19: - { yybegin(YYINITIAL); return LispTypes.FUNCTION; + { yybegin(YYINITIAL); return LispTypes.UNDEFINED_SEQUENCE; } // fall through - case 71: break; + case 73: break; case 20: - { yybegin(YYINITIAL); return LispTypes.REFERENCE_LABEL; + { yybegin(YYINITIAL); return LispTypes.HASH_LPAREN; } // fall through - case 72: break; + case 74: break; case 21: - { yybegin(BLOCK_COMMENT); + { yybegin(YYINITIAL); return LispTypes.FUNCTION; } // fall through - case 73: break; + case 75: break; case 22: - { yybegin(CHARACTER); + { yybegin(YYINITIAL); return LispTypes.REFERENCE_LABEL; } // fall through - case 74: break; + case 76: break; case 23: - { yybegin(BIT_ARRAY); + { yybegin(BLOCK_COMMENT); } // fall through - case 75: break; + case 77: break; case 24: - { yybegin(YYINITIAL); return LispTypes.UNINTERN; + { yybegin(CHARACTER); } // fall through - case 76: break; + case 78: break; case 25: - { yybegin(YYINITIAL); return LispTypes.REFERENCE_SET; + { yybegin(BIT_ARRAY); } // fall through - case 77: break; + case 79: break; case 26: - { yybegin(YYINITIAL); return LispTypes.TEST_SUCCESS; + { yybegin(YYINITIAL); return LispTypes.UNINTERN; } // fall through - case 78: break; + case 80: break; case 27: - { yybegin(YYINITIAL); return LispTypes.TEST_FALURE; + { yybegin(YYINITIAL); return LispTypes.REFERENCE_SET; } // fall through - case 79: break; + case 81: break; case 28: - { yybegin(YYINITIAL); return LispTypes.EVAL_VALUE; + { yybegin(YYINITIAL); return LispTypes.TEST_SUCCESS; } // fall through - case 80: break; + case 82: break; case 29: - { yybegin(YYINITIAL); return LispTypes.ARRAY_START; + { yybegin(YYINITIAL); return LispTypes.TEST_FALURE; } // fall through - case 81: break; + case 83: break; case 30: - { yybegin(BINARY_NUM); + { yybegin(YYINITIAL); return LispTypes.EVAL_VALUE; } // fall through - case 82: break; + case 84: break; case 31: - { yybegin(YYINITIAL); return LispTypes.REAL_PAIR_START; + { yybegin(YYINITIAL); return LispTypes.ARRAY_START; } // fall through - case 83: break; + case 85: break; case 32: - { yybegin(OCTAL_NUM); + { yybegin(BINARY_NUM); } // fall through - case 84: break; + case 86: break; case 33: - { yybegin(YYINITIAL); return LispTypes.PATHNAME_INDICATOR; + { yybegin(YYINITIAL); return LispTypes.REAL_PAIR_START; } // fall through - case 85: break; + case 87: break; case 34: - { yybegin(RADIX_NUM); + { yybegin(OCTAL_NUM); } // fall through - case 86: break; + case 88: break; case 35: - { yybegin(YYINITIAL); return LispTypes.STRUCTURE_TOKEN; + { yybegin(YYINITIAL); return LispTypes.PATHNAME_INDICATOR; } // fall through - case 87: break; + case 89: break; case 36: - { yybegin(HEX_NUM); + { yybegin(RADIX_NUM); } // fall through - case 88: break; + case 90: break; case 37: - { yybegin(YYINITIAL); yypushback(1); return LispTypes.BIT_ARRAY; + { yybegin(YYINITIAL); return LispTypes.STRUCTURE_TOKEN; } // fall through - case 89: break; + case 91: break; case 38: - { yybegin(YYINITIAL); return LispTypes.CHARACTER; + { yybegin(HEX_NUM); } // fall through - case 90: break; + case 92: break; case 39: - { yybegin(BLOCK_COMMENT_TEST); + { yybegin(YYINITIAL); yypushback(1); return LispTypes.BIT_ARRAY; } // fall through - case 91: break; + case 93: break; case 40: - { yybegin(YYINITIAL); return LispTypes.BLOCK_COMMENT; + { yybegin(YYINITIAL); return LispTypes.CHARACTER; } // fall through - case 92: break; + case 94: break; case 41: - { yybegin(YYINITIAL); yypushback(1); return LispTypes.BINARY_NUMBER_TOKEN; + { yybegin(BLOCK_COMMENT_TEST); } // fall through - case 93: break; + case 95: break; case 42: - { yybegin(YYINITIAL); yypushback(1); return LispTypes.OCTAL_NUMBER_TOKEN; + { yybegin(YYINITIAL); return LispTypes.BLOCK_COMMENT; } // fall through - case 94: break; + case 96: break; case 43: - { yybegin(YYINITIAL); yypushback(1); return LispTypes.RADIX_NUMBER_TOKEN; + { yybegin(YYINITIAL); yypushback(1); return LispTypes.BINARY_NUMBER_TOKEN; } // fall through - case 95: break; + case 97: break; case 44: - { yybegin(YYINITIAL); yypushback(1); return LispTypes.HEX_NUMBER_TOKEN; + { yybegin(YYINITIAL); yypushback(1); return LispTypes.OCTAL_NUMBER_TOKEN; } // fall through - case 96: break; + case 98: break; case 45: - { yybegin(YYINITIAL); return processBuffer(true); + { yybegin(YYINITIAL); yypushback(1); return LispTypes.RADIX_NUMBER_TOKEN; } // fall through - case 97: break; + case 99: break; case 46: - { tokenBuffer.append(yytext()); + { yybegin(YYINITIAL); yypushback(1); return LispTypes.HEX_NUMBER_TOKEN; } // fall through - case 98: break; + case 100: break; case 47: - { yybegin(STEP9); escapeCount++; + { yybegin(YYINITIAL); return processBuffer(true); } // fall through - case 99: break; + case 101: break; case 48: - { yybegin(STEP8ESCAPE); + { tokenBuffer.append(yytext()); } // fall through - case 100: break; + case 102: break; case 49: - { yybegin(STEP8); tokenBuffer.append(yytext()); + { yybegin(STEP9); escapeCount++; } // fall through - case 101: break; + case 103: break; case 50: - { yybegin(STEP8); escapeCount++; + { yybegin(STEP8ESCAPE); } // fall through - case 102: break; + case 104: break; case 51: - { yybegin(STEP9ESCAPE); + { yybegin(STEP8); tokenBuffer.append(yytext()); } // fall through - case 103: break; + case 105: break; case 52: + { yybegin(STEP8); escapeCount++; + } + // fall through + case 106: break; + case 53: + { yybegin(STEP9ESCAPE); + } + // fall through + case 107: break; + case 54: { yybegin(STEP9); tokenBuffer.append(yytext()); } // fall through - case 104: break; + case 108: break; default: zzScanError(ZZ_NO_MATCH); } diff --git a/src/main/gen/com/en_circle/slt/plugin/lisp/LispParser.java b/src/main/gen/com/en_circle/slt/plugin/lisp/LispParser.java index d3fd7fa..2615945 100644 --- a/src/main/gen/com/en_circle/slt/plugin/lisp/LispParser.java +++ b/src/main/gen/com/en_circle/slt/plugin/lisp/LispParser.java @@ -123,14 +123,15 @@ public static boolean datum(PsiBuilder b, int l) { } /* ********************************************************** */ - // REFERENCE_SET | TEST_SUCCESS | COMMA | BACKQUOTE | QUOTE | FUNCTION + // REFERENCE_SET | TEST_SUCCESS | UNQUOTE | UNQUOTE_SPLICE | BACKQUOTE | QUOTE | FUNCTION public static boolean enhancement(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "enhancement")) return false; boolean r; Marker m = enter_section_(b, l, _NONE_, ENHANCEMENT, ""); r = consumeToken(b, REFERENCE_SET); if (!r) r = consumeToken(b, TEST_SUCCESS); - if (!r) r = consumeToken(b, COMMA); + if (!r) r = consumeToken(b, UNQUOTE); + if (!r) r = consumeToken(b, UNQUOTE_SPLICE); if (!r) r = consumeToken(b, BACKQUOTE); if (!r) r = consumeToken(b, QUOTE); if (!r) r = consumeToken(b, FUNCTION); diff --git a/src/main/gen/com/en_circle/slt/plugin/lisp/psi/LispTypes.java b/src/main/gen/com/en_circle/slt/plugin/lisp/psi/LispTypes.java index 4565471..a0b832d 100644 --- a/src/main/gen/com/en_circle/slt/plugin/lisp/psi/LispTypes.java +++ b/src/main/gen/com/en_circle/slt/plugin/lisp/psi/LispTypes.java @@ -40,7 +40,6 @@ public interface LispTypes { IElementType BIT_ARRAY = new LispTokenType("BIT_ARRAY"); IElementType BLOCK_COMMENT = new LispTokenType("BLOCK_COMMENT"); IElementType CHARACTER = new LispTokenType("CHARACTER"); - IElementType COMMA = new LispTokenType("COMMA"); IElementType DOT = new LispTokenType("DOT"); IElementType EVAL_VALUE = new LispTokenType("EVAL_VALUE"); IElementType FUNCTION = new LispTokenType("FUNCTION"); @@ -66,6 +65,8 @@ public interface LispTypes { IElementType TEST_SUCCESS = new LispTokenType("TEST_SUCCESS"); IElementType UNDEFINED_SEQUENCE = new LispTokenType("UNDEFINED_SEQUENCE"); IElementType UNINTERN = new LispTokenType("UNINTERN"); + IElementType UNQUOTE = new LispTokenType("UNQUOTE"); + IElementType UNQUOTE_SPLICE = new LispTokenType("UNQUOTE_SPLICE"); class Factory { public static PsiElement createElement(ASTNode node) { diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/SltStaticHighlighter.java b/src/main/java/com/en_circle/slt/plugin/highlights/SltStaticHighlighter.java index 2646add..976bb98 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/SltStaticHighlighter.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/SltStaticHighlighter.java @@ -25,7 +25,8 @@ public class SltStaticHighlighter extends SyntaxHighlighterBase { SyntaxHighlighterBase.fillMap(colors, SltHighlighterColors.SUGAR, LispTypes.FUNCTION, LispTypes.UNINTERN, LispTypes.REFERENCE_SET, LispTypes.REFERENCE_LABEL, LispTypes.TEST_SUCCESS, LispTypes.TEST_FALURE, LispTypes.EVAL_VALUE, LispTypes.ARRAY_START, - LispTypes.PATHNAME_INDICATOR, LispTypes.STRUCTURE_TOKEN); + LispTypes.PATHNAME_INDICATOR, LispTypes.STRUCTURE_TOKEN, LispTypes.UNQUOTE, LispTypes.UNQUOTE_SPLICE, + LispTypes.BACKQUOTE, LispTypes.QUOTE); } @Override @@ -37,4 +38,5 @@ public class SltStaticHighlighter extends SyntaxHighlighterBase { public TextAttributesKey @NotNull [] getTokenHighlights(IElementType tokenType) { return SyntaxHighlighterBase.pack(colors.get(tokenType)); } + } diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java index f3258ae..bb7e25b 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java @@ -4,6 +4,7 @@ import com.en_circle.slt.plugin.highlights.SltHighlighterColors; import com.en_circle.slt.plugin.highlights.annotators.SymbolAnnotator.AnnotationResult; import com.en_circle.slt.plugin.lisp.LispParserUtil; +import com.en_circle.slt.plugin.lisp.LispParserUtil.QuoteState; import com.en_circle.slt.plugin.lisp.psi.LispSymbol; import com.en_circle.slt.plugin.lisp.psi.LispVisitor; import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; @@ -58,10 +59,13 @@ public void apply(@NotNull PsiFile file, AnnotationResult annotationResult, @Not @Override public void visitSymbol(@NotNull LispSymbol element) { - String text = element.getText(); - String packageName = LispParserUtil.getPackage(element); - SymbolState state = LispEnvironmentService.getInstance(element.getProject()).refreshSymbolFromServer(packageName, text); - setHighlight(element, text, holder, state); + QuoteState quoteState = LispParserUtil.getQuoteState(element); + if (quoteState == QuoteState.NO_STATE || quoteState == QuoteState.ERROR_STATE) { + String text = element.getText(); + String packageName = LispParserUtil.getPackage(element); + SymbolState state = LispEnvironmentService.getInstance(element.getProject()).refreshSymbolFromServer(packageName, text); + setHighlight(element, text, holder, state); + } } @Override diff --git a/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.bnf b/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.bnf index 28614ba..b9c34e9 100644 --- a/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.bnf +++ b/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.bnf @@ -24,7 +24,7 @@ sexpr ::= (enhancement* datum) | comment comment ::= LINE_COMMENT | BLOCK_COMMENT -enhancement ::= REFERENCE_SET | TEST_SUCCESS | COMMA | BACKQUOTE | QUOTE | FUNCTION +enhancement ::= REFERENCE_SET | TEST_SUCCESS | UNQUOTE | UNQUOTE_SPLICE | BACKQUOTE | QUOTE | FUNCTION datum ::= tested | evaled | pathname | UNDEFINED_SEQUENCE | BIT_ARRAY | CHARACTER | REFERENCE_LABEL | number | real_pair diff --git a/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.flex b/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.flex index 8acaafc..e84321c 100644 --- a/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.flex +++ b/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.flex @@ -31,6 +31,7 @@ IElementType processBuffer(boolean unget) { %} +%state UNQUOTE_STATE %state LINE_COMMENT %state STRING %state STRING_ESCAPE @@ -61,7 +62,7 @@ TERMINATING_MACRO_CHAR=[\"'\(\),;`] [;] { yybegin(LINE_COMMENT); } [\"] { yybegin(STRING); } [`] { yybegin(YYINITIAL); return LispTypes.BACKQUOTE; } - [,] { yybegin(YYINITIAL); return LispTypes.COMMA; } + [,] { yybegin(UNQUOTE_STATE); } [#] { yybegin(SHARPSIGN); } {WHITESPACE_CHARACTER}+ { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; } @@ -71,6 +72,12 @@ TERMINATING_MACRO_CHAR=[\"'\(\),;`] <> { return null; } [^] { yybegin(YYINITIAL); return TokenType.ERROR_ELEMENT; } + { + [@] { yybegin(YYINITIAL); return LispTypes.UNQUOTE_SPLICE; } + <> { yybegin(YYINITIAL); return LispTypes.UNQUOTE; } + [^] { yybegin(YYINITIAL); yypushback(1); return LispTypes.UNQUOTE; } +} + { [\r\n] { yybegin(YYINITIAL); return LispTypes.LINE_COMMENT; } <> { yybegin(YYINITIAL); return LispTypes.LINE_COMMENT; } diff --git a/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java b/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java index 8dd83f3..614b39a 100644 --- a/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java +++ b/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java @@ -10,6 +10,8 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.containers.Stack; import java.util.List; import java.util.function.Function; @@ -139,4 +141,192 @@ public static LispList getIfHead(PsiElement element) { } return null; } + + public static QuoteState getQuoteState(PsiElement o) { + if (o instanceof LispList list) { + return getQuoteState(list); + } else { + QuoteState quoteState = QuoteState.NO_STATE; + + LispSexpr parent = PsiTreeUtil.getParentOfType(o, LispSexpr.class); + if (parent == null) { + return quoteState; + } + + LispList plist = PsiTreeUtil.getParentOfType(o, LispList.class); + + if (plist == null) { + return quoteState; + } + + quoteState = getQuoteState(plist); + if (o instanceof PsiWhiteSpace) { + return quoteState; + } + return getQuoteState(parent, quoteState); + } + } + + public static QuoteState getQuoteState(LispList o) { + QuoteState quoteState = QuoteState.NO_STATE; + LispSexpr sexpr = PsiTreeUtil.getParentOfType(o, LispSexpr.class); + if (sexpr == null) { + return quoteState; + } + PsiElement parent = sexpr.getParent(); + if (parent == null) { + return quoteState; + } else { + if (parent instanceof LispList list) { + QuoteState parentState = getQuoteState(list); + quoteState = combineQuoteStates(quoteState, parentState); + } + } + + return getQuoteState(sexpr, quoteState); + } + + private static QuoteState getQuoteState(LispSexpr self, QuoteState quoteState) { + LispSexpr superExpr = PsiTreeUtil.getParentOfType(self, LispSexpr.class); + if (superExpr != null) { + LispDatum datum = superExpr.getDatum(); + if (datum != null) { + LispList plist = datum.getList(); + if (plist != null) { + LispSexpr first = plist.getSexprList().get(0); + if (first != self) { + if (first.getDatum() != null && first.getDatum().getCompoundSymbol() != null) { + LispSymbol symbol = first.getDatum().getCompoundSymbol().getSymbol(); + QuoteState symbolState = getQuoteStateForSymbol(symbol.getName()); + if (symbolState != QuoteState.NO_STATE) { + boolean checked = false; + for (int i=1; i elementStack = new Stack<>(); + PsiElement e = o; + int parenthesis = 0; + + while (e.getPrevSibling() != null && !(e.getPrevSibling() instanceof LispToplevel)) { + ASTNode node = e.getNode(); + if (parenthesis == 0) { + if (node.getElementType() == LispTypes.RPAREN) { + ++parenthesis; + } else { + elementStack.push(e); + } + } else { + if (node.getElementType() == LispTypes.LPAREN) { + --parenthesis; + } + } + + e = e.getPrevSibling(); + } + + QuoteState quoteState = QuoteState.NO_STATE; + boolean firstElementCheck = false; + for (PsiElement element : elementStack) { + ASTNode node = element.getNode(); + if (node.getElementType() == LispTypes.QUOTE) { + quoteState = combineQuoteStates(QuoteState.QUOTE, quoteState); + } else if (node.getElementType() == LispTypes.UNQUOTE) { + quoteState = combineQuoteStates(QuoteState.UNQUOTE, quoteState); + } else if (node.getElementType() == LispTypes.UNQUOTE_SPLICE) { + quoteState = combineQuoteStates(QuoteState.UNQUOTE_SPLICE, quoteState); + } else if (node.getElementType() == LispTypes.BACKQUOTE) { + quoteState = combineQuoteStates(QuoteState.BACKQUOTE, quoteState); + } else { + if (node.getElementType() == LispTypes.LPAREN) { + firstElementCheck = true; + } + + if (node.getElementType() == LispTypes.SYMBOL_TOKEN && firstElementCheck && node != o.getNode()) { + firstElementCheck = false; + QuoteState state = getQuoteStateForSymbol(node.getText()); + quoteState = combineQuoteStates(state, quoteState); + } + } + } + return quoteState; + } + + public enum QuoteState { + BACKQUOTE, QUOTE, UNQUOTE, UNQUOTE_SPLICE, NO_STATE, ERROR_STATE + } } diff --git a/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java b/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java index bfbea87..643495f 100644 --- a/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java +++ b/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java @@ -21,6 +21,7 @@ import com.en_circle.slt.plugin.swank.SlimeRequest; import com.en_circle.slt.plugin.swank.SwankClient; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; +import com.intellij.codeInsight.hints.ParameterHintsPassFactory; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; @@ -165,6 +166,7 @@ private boolean doStart() throws Exception { listener.onPostStart(); } + ParameterHintsPassFactory.forceHintsUpdateOnNextPass(); DaemonCodeAnalyzer.getInstance(project).restart(); } finally { starting = false; diff --git a/src/main/lisp/swank/swank.lisp b/src/main/lisp/swank/swank.lisp index 6bb209e..d0d0b70 100644 --- a/src/main/lisp/swank/swank.lisp +++ b/src/main/lisp/swank/swank.lisp @@ -106,6 +106,13 @@ format suitable for Emacs." (when references (sort references #'string< :key (lambda (x) (first x)))))) +(defslimefun operator-arglist-list (name package) + (ignore-errors + (let ((args (arglist (parse-symbol name (guess-buffer-package package))))) + (cond ((eq args :not-available) nil) + (t args))))) + (export 'slt-eval) (export 'compile-string-region-slt) -(export 'find-reference-prefix) \ No newline at end of file +(export 'find-reference-prefix) +(export 'operator-arglist-list) diff --git a/src/main/resources/templates/en_US/initscript.cl b/src/main/resources/templates/en_US/initscript.cl index 8ba3558..f5cd1c1 100644 --- a/src/main/resources/templates/en_US/initscript.cl +++ b/src/main/resources/templates/en_US/initscript.cl @@ -2,6 +2,7 @@ (:use :cl) (:export +slt-interpret+)) +(in-package :slt) (defconstant +slt-interpret+ ~interpret~ "Defines current slt interpret. For SBCL the value is :sbcl") From e41b1146bb51ba404886c986a8dd11e1e4045793 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Fri, 3 Feb 2023 19:07:29 +0100 Subject: [PATCH 20/21] working argslist --- CHANGELOG.md | 2 + README.md | 1 + .../en_circle/slt/plugin/lisp/LispParser.java | 30 +++- .../com/en_circle/slt/plugin/lisp/Lisp.bnf | 3 +- .../slt/plugin/params/LispArgslist.java | 23 ++++ .../params/SltParameterInfoHandler.java | 130 ++++++++++++++++++ .../components/SltIndentationContainer.java | 24 +++- .../slt/plugin/swank/SlimeListener.java | 4 + .../slt/plugin/swank/SwankPacket.java | 10 ++ .../slt/plugin/swank/requests/Argslist.java | 48 +++++++ .../slt/tools/SltApplicationUtils.java | 25 ++-- src/main/resources/META-INF/plugin.xml | 2 + .../resources/messages/SltBundle.properties | 2 + src/test/java/ParserTest.java | 110 +-------------- 14 files changed, 282 insertions(+), 132 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/params/LispArgslist.java create mode 100644 src/main/java/com/en_circle/slt/plugin/params/SltParameterInfoHandler.java create mode 100644 src/main/java/com/en_circle/slt/plugin/swank/requests/Argslist.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d8abae..af7d629 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,12 @@ ### Added - Thread list with actions +- Argslist ### Changes - SLT library is now formatted into multiple chunks +- Grammar now properly reacts to user errors or unfinished forms ### Fixes diff --git a/README.md b/README.md index 384d2ed..e7d5291 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ You can also open this as a project in Intellij Idea. * [x] Automatic indentation * [x] REPL * [x] Interactive debugging +* [x] Argument help (Ctrl+P) * [ ] Inspection * [x] Basic inspection * [ ] Actions diff --git a/src/main/gen/com/en_circle/slt/plugin/lisp/LispParser.java b/src/main/gen/com/en_circle/slt/plugin/lisp/LispParser.java index 2615945..2ccf24e 100644 --- a/src/main/gen/com/en_circle/slt/plugin/lisp/LispParser.java +++ b/src/main/gen/com/en_circle/slt/plugin/lisp/LispParser.java @@ -192,14 +192,14 @@ static boolean lispFile(PsiBuilder b, int l) { // LPAREN sexpr* RPAREN public static boolean list(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "list")) return false; - if (!nextTokenIs(b, LPAREN)) return false; - boolean r; - Marker m = enter_section_(b); + boolean r, p; + Marker m = enter_section_(b, l, _NONE_, LIST, ""); r = consumeToken(b, LPAREN); r = r && list_1(b, l + 1); + p = r; // pin = 2 r = r && consumeToken(b, RPAREN); - exit_section_(b, m, LIST, r); - return r; + exit_section_(b, l, m, r, p, LispParser::list_recovery); + return r || p; } // sexpr* @@ -213,6 +213,26 @@ private static boolean list_1(PsiBuilder b, int l) { return true; } + /* ********************************************************** */ + // !(RPAREN | sexpr) + static boolean list_recovery(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "list_recovery")) return false; + boolean r; + Marker m = enter_section_(b, l, _NOT_); + r = !list_recovery_0(b, l + 1); + exit_section_(b, l, m, r, false, null); + return r; + } + + // RPAREN | sexpr + private static boolean list_recovery_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "list_recovery_0")) return false; + boolean r; + r = consumeToken(b, RPAREN); + if (!r) r = sexpr(b, l + 1); + return r; + } + /* ********************************************************** */ // binary_number | octal_number | hex_number | radix_number | integer | ratio | real public static boolean number(PsiBuilder b, int l) { diff --git a/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.bnf b/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.bnf index b9c34e9..a19a2e1 100644 --- a/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.bnf +++ b/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.bnf @@ -43,7 +43,8 @@ array ::= ARRAY_START list structure ::= STRUCTURE_TOKEN list -list ::= LPAREN sexpr* RPAREN +list ::= LPAREN sexpr* RPAREN { pin = 2 recoverWhile=list_recovery } +private list_recovery ::= !(RPAREN | sexpr) pair ::= LPAREN sexpr+ DOT sexpr RPAREN diff --git a/src/main/java/com/en_circle/slt/plugin/params/LispArgslist.java b/src/main/java/com/en_circle/slt/plugin/params/LispArgslist.java new file mode 100644 index 0000000..6cdd5c1 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/params/LispArgslist.java @@ -0,0 +1,23 @@ +package com.en_circle.slt.plugin.params; + +import com.en_circle.slt.plugin.SltBundle; +import com.en_circle.slt.plugin.lisp.lisp.LispElement; +import com.en_circle.slt.plugin.lisp.lisp.LispString; + +public class LispArgslist { + + private final String information; + + public LispArgslist(LispElement data) { + if (data instanceof LispString str) { + this.information = str.getValue(); + } else { + this.information = SltBundle.message("slt.argslist.error"); + } + } + + public String getInformation() { + return information; + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/params/SltParameterInfoHandler.java b/src/main/java/com/en_circle/slt/plugin/params/SltParameterInfoHandler.java new file mode 100644 index 0000000..5aa0189 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/params/SltParameterInfoHandler.java @@ -0,0 +1,130 @@ +package com.en_circle.slt.plugin.params; + +import com.en_circle.slt.plugin.lisp.LispParserUtil; +import com.en_circle.slt.plugin.lisp.LispParserUtil.QuoteState; +import com.en_circle.slt.plugin.lisp.psi.LispList; +import com.en_circle.slt.plugin.lisp.psi.LispSexpr; +import com.en_circle.slt.plugin.lisp.psi.LispSymbol; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentState; +import com.en_circle.slt.plugin.swank.requests.Argslist; +import com.en_circle.slt.tools.SltApplicationUtils; +import com.intellij.lang.parameterInfo.CreateParameterInfoContext; +import com.intellij.lang.parameterInfo.ParameterInfoHandler; +import com.intellij.lang.parameterInfo.ParameterInfoUIContext; +import com.intellij.lang.parameterInfo.UpdateParameterInfoContext; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SltParameterInfoHandler implements ParameterInfoHandler { + + @Override + public @Nullable LispList findElementForParameterInfo(@NotNull CreateParameterInfoContext context) { + LispList candidate = findElementAtOffset(context.getFile(), context.getOffset()); + if (candidate != null) { + if (LispEnvironmentService.getInstance(context.getProject()).getState() == LispEnvironmentState.READY) { + LispSymbol symbol = getHead(candidate); + if (symbol == null) + return null; + + String packageName = LispParserUtil.getPackage(candidate); + Object[] items = SltApplicationUtils.getAsyncResultNoThrow(context.getProject(), finishRequest -> Argslist + .getArgslist(symbol.getName(), packageName, + result -> finishRequest.accept(getCandidateObjects(result)))); + if (items != null) { + context.setItemsToShow(items); + return candidate; + } + } + } + return null; + } + + private LispSymbol getHead(LispList candidate) { + if (candidate.getSexprList().size() > 0) { + LispSexpr sexpr = candidate.getSexprList().get(0); + if (sexpr.getDatum() != null && sexpr.getDatum().getCompoundSymbol() != null) { + return sexpr.getDatum().getCompoundSymbol().getSymbol(); + } + } + return null; + } + + private Object[] getCandidateObjects(LispArgslist result) { + return new Object[] { result }; + } + + @Override + public void showParameterInfo(@NotNull LispList element, @NotNull CreateParameterInfoContext context) { + context.showHint(element, element.getTextRange().getStartOffset() + 1, this); + } + + @Override + public @Nullable LispList findElementForUpdatingParameterInfo(@NotNull UpdateParameterInfoContext context) { + LispList candidate = findElementAtOffset(context.getFile(), context.getOffset()); + if (candidate != null) { + PsiElement current = context.getParameterOwner(); + if (current == null || current == candidate) return candidate; + } + return null; + } + + @Override + public void updateParameterInfo(@NotNull LispList lispList, @NotNull UpdateParameterInfoContext context) { + context.setParameterOwner(lispList); + } + + @Override + public void updateUI(LispArgslist p, @NotNull ParameterInfoUIContext context) { + context.setupUIComponentPresentation(p.getInformation(), 0, 0, false, + false, true, context.getDefaultParameterColor()); + } + + private LispList findElementAtOffset(PsiFile file, int offset) { + PsiElement element = file.findElementAt(offset); + while (element == null || element instanceof PsiWhiteSpace) { + element = file.findElementAt(offset--); + } + + LispList l; + if ((element instanceof LispList)) { + l = (LispList) element; + } else { + l = PsiTreeUtil.getParentOfType(element, LispList.class); + } + + if (l != null) { + QuoteState quoteState = LispParserUtil.getQuoteState(l); + if (quoteState == QuoteState.NO_STATE || quoteState == QuoteState.ERROR_STATE) { + return l; + } + } + return null; + } + +// private LispSexpr @NotNull [] getActualParameters(@NotNull LispList o) { +// List arguments = new ArrayList<>(); +// QuoteState quoteState = LispParserUtil.getQuoteState(o); +// if (quoteState == QuoteState.ERROR_STATE || quoteState == QuoteState.NO_STATE) { +// for (int i=1; i 0) { + --numBraces; + } + } + } + } + } + if (!wasAfter || isUnfinished) { // insert fake element at the end, so we identify correct form state.hasRealElement = false; formText += " 0"; diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java index 89822bb..17da9df 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java @@ -166,6 +166,10 @@ private void processReturn(LispContainer reply) { if (request instanceof SuspendThread suspendThread) { suspendThread.processReply((LispContainer) reply.getItems().get(1)); } + + if (request instanceof Argslist argslist) { + argslist.processReply((LispContainer) reply.getItems().get(1)); + } } finally { requests.remove(replyId.getValue()); } diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java b/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java index 2055c10..9524d7b 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java @@ -279,6 +279,16 @@ public static SwankPacket killThread(BigInteger thread, BigInteger continuation) return new SwankPacket(formatted); } + public static SwankPacket argslist(String symbol, String packageName, BigInteger continuation) { + symbol = StringUtils.replace(symbol, "\\", "\\\\"); + symbol = StringUtils.replace(symbol, "\"", "\\\""); + packageName = StringUtils.replace(packageName, "\\", "\\\\"); + packageName = StringUtils.replace(packageName, "\"", "\\\""); + + String formatted = String.format("(:emacs-rex (swank:operator-arglist \"%s\" \"%s\") \":CL-USER\" T %s)", symbol, packageName, continuation); + return new SwankPacket(formatted); + } + private int length; private String expressionSource; diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/Argslist.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/Argslist.java new file mode 100644 index 0000000..76b4a75 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/Argslist.java @@ -0,0 +1,48 @@ +package com.en_circle.slt.plugin.swank.requests; + +import com.en_circle.slt.plugin.lisp.lisp.LispContainer; +import com.en_circle.slt.plugin.lisp.lisp.LispSymbol; +import com.en_circle.slt.plugin.params.LispArgslist; +import com.en_circle.slt.plugin.swank.SlimeRequest; +import com.en_circle.slt.plugin.swank.SwankPacket; + +import java.math.BigInteger; + +public class Argslist extends SlimeRequest { + + public static SlimeRequest getArgslist(String symbol, String packageName, Callback callback) { + return new Argslist(symbol, packageName, callback); + } + + private final String symbol; + private final String packageName; + private final Callback callback; + + private Argslist(String symbol, String packageName, Callback callback) { + this.symbol = symbol; + this.packageName = packageName; + this.callback = callback; + } + + @Override + public SwankPacket createPacket(BigInteger requestId) { + return SwankPacket.argslist(symbol, packageName, requestId); + } + + public void processReply(LispContainer data) { + if (isOk(data)) { + callback.onResult(new LispArgslist(data.getItems().get(1))); + } + } + + private boolean isOk(LispContainer data) { + return data.getItems().size() > 0 && + data.getItems().get(0) instanceof LispSymbol && + ":ok".equals(((LispSymbol) data.getItems().get(0)).getValue()); + } + + public interface Callback { + void onResult(LispArgslist result); + } + +} diff --git a/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java b/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java index a206c76..1287d9e 100644 --- a/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java +++ b/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java @@ -17,10 +17,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Function; @@ -63,27 +62,25 @@ public static Future getAsyncResultNoProgress(Project project, Function { - BlockingQueue pointer = new ArrayBlockingQueue<>(1); - SlimeRequest r = request.apply(result -> - ApplicationManager.getApplication().invokeLater(() -> - ApplicationManager.getApplication().runWriteAction(() -> { - try { - pointer.put(result); - } catch (Exception ignored) { - - } - }))); + AtomicReference pointer = new AtomicReference<>(null); + SlimeRequest r = request.apply(result -> { + try { + pointer.set(result); + } catch (Exception ignored) { + + } + }); LispEnvironmentService.getInstance(project).sendToLisp(r, startLisp); try { Awaitility.await() .atMost(2, TimeUnit.SECONDS) .pollInterval(new FixedPollInterval(10, TimeUnit.MILLISECONDS)) .failFast(ProgressManager::checkCanceled) - .until(() -> pointer.peek() != null); + .until(() -> pointer.get() != null); } catch (ConditionTimeoutException exception) { return null; } - return pointer.isEmpty() ? null : pointer.take(); + return pointer.get(); }); } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 79749ba..5a08b18 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -95,6 +95,8 @@ + + diff --git a/src/main/resources/messages/SltBundle.properties b/src/main/resources/messages/SltBundle.properties index 5e1b6d4..b6f5221 100644 --- a/src/main/resources/messages/SltBundle.properties +++ b/src/main/resources/messages/SltBundle.properties @@ -5,6 +5,8 @@ slt.file.description=Common Lisp source file slt.error.start=Error starting lisp slt.error.stop=Error stopping lisp +slt.argslist.error=No contextual help found + # SDK slt.environment.sbcl=SBCL diff --git a/src/test/java/ParserTest.java b/src/test/java/ParserTest.java index db59172..440c070 100644 --- a/src/test/java/ParserTest.java +++ b/src/test/java/ParserTest.java @@ -12,113 +12,9 @@ public class ParserTest { public static void main(String[] args) { String data = """ - (:debug 6 1 ("There is no class named COMMON-LISP-USER::COP." " [Condition of type SB-PCL:CLASS-NOT-FOUND-ERROR]" nil) (("ABORT" "Abort compilation." nil) ("*ABORT" "Return to SLIME's top level." (common-lisp:&rest sb-kernel::temp)) ("ABORT" "abort thread (#)" nil)) ((0 "(SB-PCL::FIND-CLASS-FROM-CELL COP # T)" sb-pcl::find-class-from-cell (:location (:file "/usr/share/sbcl-source/src/pcl/macros.lisp") (:position 3107) (:snippet "(error 'class-not-found-error :name symbol)))) - - (defun find-class (symbol &optional (errorp t) environment) - (declare (ignore environment) (explicit-check)) - (find-class-from-cell symbol - (find-classoid-cell symbol) - ")) "SB-PCL") (1 "((SB-C::TOP-LEVEL-FORM (SB-PCL::LOAD-DEFMETHOD (QUOTE STANDARD-METHOD) (QUOTE XANTHYPA) (QUOTE NIL) (LIST (FIND-CLASS (QUOTE COP))) (QUOTE (ROBOCOP)) (LIST* :FUNCTION (LET* (#1=# #1#) (SETF #1# #1#) S.." (sb-c::top-level-form (sb-pcl::load-defmethod (quote common-lisp:standard-method) (quote common-lisp-user::xanthypa) (quote nil) (common-lisp:list (common-lisp:find-class (quote common-lisp-user::cop))) (quote (common-lisp-user::robocop)) (common-lisp:list* :function (common-lisp:let* (# #) (common-lisp:setf # #) sb-pcl::mf) (quote (sb-pcl::plist # sb-pcl::simple-next-method-call t))) (sb-c:source-location))) (:location (:buffer "/home/pvan/test/asd.cl") (:offset 209 0) (:snippet "(defmethod xanthypa ((robocop cop)) - (print cop))")) nil) (2 "(SB-FASL::LOAD-FASL-GROUP #S(SB-FASL::FASL-INPUT :STREAM # :TABLE #(115 #1=\\"/home/pvan/test/asd.cl\\" :EMACS-BUFFER #2=\\"/home/pvan/test/as.." sb-fasl::load-fasl-group (:location (:file "/usr/share/sbcl-source/src/code/load.lisp") (:position 30966) (:snippet "(funcall function fasl-input arg1)) - (2 (funcall function fasl-input arg1 arg2)) - (3 (funcall function fasl-input arg1 arg2 arg3))) - (error \\"corrupt fasl file: FOP code #x~x\\" byte)")) "SB-FASL") (3 "((LAMBDA NIL :IN SB-FASL::LOAD-AS-FASL))" (common-lisp:lambda nil :in sb-fasl::load-as-fasl) (:location (:file "/usr/share/sbcl-source/src/code/load.lisp") (:position 32351) (:snippet "(load-fasl-group fasl-input)) - ;; Nuke the table and stack to avoid keeping garbage on - ;; conservatively collected platforms. - (nuke-fop-vector (%fasl-input-table fasl-input)) - (nuke-fop-vector (%fasl-input-stack fasl-input))))")) nil) (4 "(SB-IMPL::CALL-WITH-LOADER-PACKAGE-NAMES #)" sb-impl::call-with-loader-package-names (:location (:file "/usr/share/sbcl-source/src/code/target-package.lisp") (:position 103223) (:snippet "(funcall function) - (when (and (not boundp) *deferred-package-names*) - (info-maphash - (lambda (name package) - (unless (eq package :deleted) - (dovector (sym (symtbl-cells (package-internal-symbols package))) - (whe")) "SB-IMPL") (5 "(SB-FASL::LOAD-AS-FASL # NIL NIL)" sb-fasl::load-as-fasl (:location (:file "/usr/share/sbcl-source/src/code/load.lisp") (:position 32279) (:snippet "(with-loader-package-names - (unwind-protect - (loop while (load-fasl-group fasl-input)) - ;; Nuke the table and stack to avoid keeping garbage on - ;; conservatively collected platforms. - (nuke-fop-vector (%fasl-input-table")) "SB-FASL") (6 "((LABELS SB-FASL::LOAD-STREAM-1 :IN LOAD) # T)" (common-lisp:labels sb-fasl::load-stream-1 :in common-lisp:load) (:location (:file "/usr/share/sbcl-source/src/code/target-load.lisp") (:position 12454) (:snippet "(load-as-fasl stream verbose (if print t nil)) - ;; FIXME: if *EVALUATOR-MODE* is :INTERPRET, - ;; then this should have nothing whatsoever to do with - ;; compiler-error-resignaling. That's an artifact - ")) nil) (7 "(SB-FASL::CALL-WITH-LOAD-BINDINGS # # T #)" (common-lisp:flet swank/backend:call-with-compilation-hooks :in "/usr/share/common-lisp/source/swank/swank/sbcl.lisp") (:location (:file "/usr/share/common-lisp/source/swank/swank/sbcl.lisp") (:position 25939) (:snippet "(funcall function))) - - ;;; HACK: SBCL 1.2.12 shipped with a bug where - ;;; SB-EXT:RESTRICT-COMPILER-POLICY would signal an error when there - ;;; were no policy restrictions in place. This workaround ensures the - ;;; existence of at least one dummy restriction.")) nil) (10 "((FLET SWANK/BACKEND:SWANK-COMPILE-STRING :IN \\"/usr/share/common-lisp/source/swank/swank/sbcl.lisp\\") \\"(defmethod xanthypa ((robocop cop)) ..)" (common-lisp:flet swank/backend:swank-compile-string :in "/usr/share/common-lisp/source/swank/swank/sbcl.lisp") (:location (:file "/usr/share/common-lisp/source/swank/swank/sbcl.lisp") (:position 30161) (:snippet "(load-it output-file)) - (not failurep)) - (ignore-errors - (delete-file *buffer-tmpfile*) - (delete-file (compile-file-pathname *buffer-tmpfile*))))))) - - ;;;; Definitions - - (defparameter *definition-types* - '(:variable defv")) nil) (11 "((LAMBDA NIL :IN SWANK:COMPILE-STRING-REGION-SLT))" (common-lisp:lambda nil :in swank:compile-string-region-slt) (:location (:file "/src/self/slt/build/idea-sandbox/.slt/SLTinit137/slt.cl") (:position 2993) (:snippet "(swank-compile-string string - :buffer buffer - :position offset - :filename filename)))))) - - (export 'slt-eval) - (export 'compile-string-region-slt) - - (in-package sw")) nil) (12 "((LAMBDA NIL :IN SWANK::COLLECT-NOTES))" (common-lisp:lambda nil :in swank::collect-notes) (:location (:file "/usr/share/common-lisp/source/swank/swank.lisp") (:position 92963) (:snippet "(funcall function)) - (abort () :report \\"Abort compilation.\\" (list nil)))))) - (destructuring-bind (successp &optional loadp faslfile) result - (let ((faslfile (etypecase faslfile - (null nil) - ")) nil) (13 "(SWANK::MEASURE-TIME-INTERVAL #)" swank::measure-time-interval (:location (:file "/usr/share/common-lisp/source/swank/swank.lisp") (:position 91985) (:snippet "(funcall fun) - (/ (- (get-internal-real-time) before) - (coerce internal-time-units-per-second 'float))))) - - (defun make-compiler-note (condition) - \\"Make a compiler note data structure from a compiler-condition.\\" - (declare (type compiler-conditi")) "SWANK") (14 "(SWANK::COLLECT-NOTES #)" swank::collect-notes (:location (:file "/usr/share/common-lisp/source/swank/swank.lisp") (:position 92735) (:snippet "(measure-time-interval - (lambda () - ;; To report location of error-signaling toplevel forms - ;; for errors in EVAL-WHEN or during macroexpansion. - (restart-case (multiple-value-list (funcall function)) - ")) "SWANK") (15 "(SWANK::CALL-WITH-BUFFER-SYNTAX NIL #)" swank::call-with-buffer-syntax (:location (:file "/usr/share/common-lisp/source/swank/swank.lisp") (:position 57735) (:snippet "(call-with-syntax-hooks fun) - (let ((*readtable* *buffer-readtable*)) - (call-with-syntax-hooks fun))))) - - (defmacro without-printing-errors ((&key object stream - (msg \\"<>\\")) - ")) "SWANK") (16 "(SB-INT:SIMPLE-EVAL-IN-LEXENV (SWANK:COMPILE-STRING-REGION-SLT \\"(defmethod xanthypa ((robocop cop)) ..)" sb-int:simple-eval-in-lexenv (:location (:file "/usr/share/sbcl-source/src/code/eval.lisp") (:position 13270) (:snippet "(apply (symbol-function name) (args))) - (%simple-eval exp lexenv)))))) - (t - exp)))))) - ) ; end PROGN - - ;;; This definition will be replaced after the interpreter is compiled. - ;;; Until then we just always compile. - #+sb-f")) "SB-INT") (17 "(EVAL (SWANK:COMPILE-STRING-REGION-SLT \\"(defmethod xanthypa ((robocop cop)) ..)" common-lisp:eval (:location (:file "/usr/share/sbcl-source/src/code/eval.lisp") (:position 14411) (:snippet "(eval-in-lexenv original-exp nil))) - - (defun eval-tlf (original-exp tlf-index &optional lexenv) - (let ((*eval-source-context* original-exp) - (*eval-tlf-index* tlf-index) - (*eval-source-info* sb-c::*source-info*)) - (eval-in-lexenv original-")) "COMMON-LISP") (18 "(SWANK:EVAL-FOR-EMACS (SWANK:COMPILE-STRING-REGION-SLT \\"(defmethod xanthypa ((robocop cop)) ..)" swank:eval-for-emacs (:location (:file "/usr/share/common-lisp/source/swank/swank.lisp") (:position 65853) (:snippet "(eval form)))) - (run-hook *pre-reply-hook*) - (setq ok t)) - (send-to-emacs `(:return ,(current-thread) - ,(if ok - `(:ok ,result) - `(:")) "SWANK") (19 "((LAMBDA NIL :IN SWANK::SPAWN-WORKER-THREAD))" (common-lisp:lambda nil :in swank::spawn-worker-thread) (:location (:file "/usr/share/common-lisp/source/swank/swank.lisp") (:position 37885) (:snippet "(apply #'eval-for-emacs\s - (cdr (wait-for-event `(:emacs-rex . _))))))) - :name \\"worker\\")) - - (defun add-active-thread (connection thread) - (etypecase connection - (multithreaded-connection\s - (push thread (mconn.active-threa")) nil)) (16)) + (defun + buble + (a b c) 0 """; LispCoreProjectEnvironment projectEnvironment = new LispCoreProjectEnvironment(); From 89d69d6bee98743d66492ab34b1558e6695ebfd7 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Fri, 3 Feb 2023 19:15:17 +0100 Subject: [PATCH 21/21] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af7d629..9addbd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.3.1 +## 0.3.1 230203 ### Added