@@ -550,6 +550,33 @@ When there is a possible unfinished ansi control sequence,
550
550
(insert-before-markers (cadr ansi-color-context))
551
551
(setq ansi-color-context nil )))
552
552
553
+ (defvar cider-repl--root-ns-highlitht-template " \\ <%s[^$/: \t\n ]+"
554
+ " Regexp used to highlight root ns in REPL buffers." )
555
+
556
+ (defvar-local cider-repl--root-ns-regexp nil
557
+ " Cache of root ns regexp in REPLs" )
558
+
559
+ (defun cider-repl--apply-current-project-color (string )
560
+ " Fontify project's root namespace to make stacktraces more readable.
561
+ Foreground of `cider-stacktrace-ns-face' is used to propertize matched
562
+ namespaces. STRING is REPL's output."
563
+ (if (null nrepl-project-dir)
564
+ string
565
+ (unless cider-repl--root-ns-regexp
566
+ (let ((root (file-name-nondirectory (directory-file-name nrepl-project-dir))))
567
+ (setq cider-repl--root-ns-regexp
568
+ ; ; Replace _ or - with regexp patter to accommodate "raw" namespaces
569
+ (format cider-repl--root-ns-highlitht-template
570
+ (replace-regexp-in-string " [_-]+" " [_-]+" root)))))
571
+ (let ((start 0 )
572
+ (end 0 ))
573
+ (while (setq start (string-match cider-repl--root-ns-regexp string end))
574
+ (setq end (match-end 0 ))
575
+ (let ((face-spec (list (cons 'foreground-color
576
+ (face-attribute 'cider-stacktrace-ns-face :foreground nil t )))))
577
+ (font-lock-prepend-text-property start end 'face face-spec string)))
578
+ string)))
579
+
553
580
(defun cider-repl--emit-output-at-pos (buffer string output-face position &optional bol )
554
581
" Using BUFFER, insert STRING (applying to it OUTPUT-FACE) at POSITION.
555
582
If BOL is non-nil insert at the beginning of line."
@@ -560,10 +587,14 @@ If BOL is non-nil insert at the beginning of line."
560
587
(goto-char position)
561
588
; ; TODO: Review the need for bol
562
589
(when (and bol (not (bolp ))) (insert-before-markers " \n " ))
563
- (insert-before-markers
564
- (ansi-color-apply (propertize string
565
- 'font-lock-face output-face
566
- 'rear-nonsticky '(font-lock-face))))
590
+ (setq string
591
+ (thread-first string
592
+ (propertize 'font-lock-face output-face
593
+ 'rear-nonsticky '(font-lock-face))
594
+ (ansi-color-apply )
595
+ (cider-repl--apply-current-project-color)
596
+ (propertize 'help-echo 'cider-locref-help-echo )))
597
+ (insert-before-markers string)
567
598
(cider-repl--flush-ansi-color-context)
568
599
(when (and (= (point ) cider-repl-prompt-start-mark)
569
600
(not (bolp )))
@@ -930,7 +961,100 @@ namespace to switch to."
930
961
:both ))
931
962
932
963
933
- ; ;;;; History
964
+ ; ;; Location References
965
+
966
+ (defcustom cider-locref-regexp-alist
967
+ '((stdout-stacktrace " [ \t ]\\ (at \\ ([^$(]+\\ ).*(\\ ([^:()]+\\ ):\\ ([0-9]+\\ ))\\ )" 1 2 3 4 )
968
+ (aviso-stacktrace " ^[ \t ]*\\ (\\ ([^$/ \t ]+\\ ).*? +\\ ([^:]+\\ ): +\\ ([0-9]+\\ )\\ )" 1 2 3 4 )
969
+ (print-stacktrace " \\ [\\ ([^][$ \t ]+\\ ).* +\\ ([^ \t ]+\\ ) +\\ ([0-9]+\\ )\\ ]" 0 1 2 3 )
970
+ (timbre-log " \\ (TRACE\\ |INFO\\ |DEBUG\\ |WARN\\ |ERROR\\ ) +\\ (\\ [\\ ([^:]+\\ ):\\ ([0-9]+\\ )\\ ]\\ )" 2 3 nil 4 ))
971
+ " Alist holding regular expressions for inline location references.
972
+ Each element in the alist has the form (NAME REGEXP HIGHLIGHT VAR FILE
973
+ LINE), where NAME is the identifier of the regexp, REGEXP - regexp matching
974
+ a location, HIGHLIGHT - sub-expression matching region to highlight on
975
+ mouse-over, VAR - sub-expression giving Clojure VAR to look up. FILE is
976
+ currently only used when VAR is nil and must be full resource path in that
977
+ case."
978
+ :type '(alist :key-type sexp)
979
+ :group 'cider-repl
980
+ :package-version '(cider. " 0.16.0" ))
981
+
982
+ (defun cider--locref-at-point-1 (reg-list &optional pos )
983
+ " Workhorse for getting locref at POS.
984
+ REG-LIST is an entry in `cider-locref-regexp-alist' ."
985
+ (save-excursion
986
+ (let ((pos (or pos (point ))))
987
+ (goto-char pos)
988
+ (beginning-of-line )
989
+ (when (re-search-forward (nth 1 reg-list) (point-at-eol ) t )
990
+ (let ((ix-highlight (or (nth 2 reg-list) 0 ))
991
+ (ix-var (nth 3 reg-list))
992
+ (ix-file (nth 4 reg-list))
993
+ (ix-line (nth 5 reg-list)))
994
+ (list
995
+ :type (car reg-list)
996
+ :highlight (cons (match-beginning ix-highlight) (match-end ix-highlight))
997
+ :var (and ix-var
998
+ (replace-regexp-in-string " _" " -"
999
+ (match-string-no-properties ix-var)
1000
+ nil t ))
1001
+ :file (and ix-file (match-string-no-properties ix-file))
1002
+ :line (and ix-line (string-to-number (match-string-no-properties ix-line)))))))))
1003
+
1004
+ (defun cider-locref-at-point (&optional pos )
1005
+ " Return a plist of components of the location reference at POS.
1006
+ Limit search to current line only and return nil if no location has been
1007
+ found. Returned keys are :type, :highlight, :var, :file, :line, where
1008
+ :highlight is a cons of positions, :var and :file are strings or nil, :line
1009
+ is a number. See `cider-locref-regexp-alist' for how to specify regexes
1010
+ for locref look up."
1011
+ (seq-some (lambda (rl ) (cider--locref-at-point-1 rl pos))
1012
+ cider-locref-regexp-alist))
1013
+
1014
+ (defun cider-jump-to-locref-at-point (&optional pos )
1015
+ " Identify location reference at POS and navigate to it.
1016
+ This function is used from help-echo property inside REPL buffers and uses
1017
+ regexes from `cider-locref-regexp-alist' to infer locations at point."
1018
+ (interactive )
1019
+ (if-let ((loc (cider-locref-at-point pos)))
1020
+ (let* ((var (plist-get loc :var ))
1021
+ (line (plist-get loc :line ))
1022
+ (file (if var
1023
+ (or (cider-sync-request:ns-path var)
1024
+ (nrepl-dict-get (cider-sync-request:info var) " file" ))
1025
+ (plist-get loc :file ))))
1026
+ (if file
1027
+ (cider--jump-to-loc-from-info (nrepl-dict " file" file " line" line))
1028
+ (error " No source location for %s " var)))
1029
+ (user-error " No location reference at point" )))
1030
+
1031
+ (defvar cider-locref-hoover-overlay
1032
+ (let ((o (make-overlay 1 1 )))
1033
+ (overlay-put o 'category 'cider-error-hoover )
1034
+ ; ; (overlay-put o 'face 'highlight)
1035
+ (overlay-put o 'pointer 'hand )
1036
+ (overlay-put o 'mouse-face 'highlight )
1037
+ (overlay-put o 'follow-link 'mouse )
1038
+ (overlay-put o 'keymap
1039
+ (let ((map (make-sparse-keymap )))
1040
+ (define-key map [return] 'cider-jump-to-locref-at-point )
1041
+ (define-key map [mouse-2] 'cider-jump-to-locref-at-point )
1042
+ map))
1043
+ o)
1044
+ " Overlay used during hoovering on location references in REPL buffers.
1045
+ One for all REPLs." )
1046
+
1047
+ (defun cider-locref-help-echo (win buffer pos )
1048
+ " Function for help-echo property in REPL buffers.
1049
+ WIN, BUFFER and POS are the window, buffer and point under mouse position."
1050
+ (with-current-buffer buffer
1051
+ (if-let ((hl (plist-get (cider-locref-at-point pos) :highlight )))
1052
+ (move-overlay cider-locref-hoover-overlay (car hl) (cdr hl))
1053
+ (delete-overlay cider-locref-hoover-overlay))
1054
+ nil ))
1055
+
1056
+
1057
+ ; ;; History
934
1058
935
1059
(defcustom cider-repl-wrap-history nil
936
1060
" T to wrap history around when the end is reached."
0 commit comments