@@ -550,6 +550,33 @@ When there is a possible unfinished ansi control sequence,
550550 (insert-before-markers (cadr ansi-color-context))
551551 (setq ansi-color-context nil )))
552552
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+
553580(defun cider-repl--emit-output-at-pos (buffer string output-face position &optional bol )
554581 " Using BUFFER, insert STRING (applying to it OUTPUT-FACE) at POSITION.
555582If 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."
560587 (goto-char position)
561588 ; ; TODO: Review the need for bol
562589 (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)
567598 (cider-repl--flush-ansi-color-context)
568599 (when (and (= (point ) cider-repl-prompt-start-mark)
569600 (not (bolp )))
@@ -930,7 +961,100 @@ namespace to switch to."
930961 :both ))
931962
932963
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
9341058
9351059(defcustom cider-repl-wrap-history nil
9361060 " T to wrap history around when the end is reached."
0 commit comments