| [15906] | 1 | ;;;
|
|---|
| 2 | ;;; Copyright (C) 2013 Clozure Associates
|
|---|
| 3 | ;;;
|
|---|
| 4 |
|
|---|
| 5 | (in-package :hemlock)
|
|---|
| 6 |
|
|---|
| 7 | ;; Functions used by the IDE display code.
|
|---|
| 8 |
|
|---|
| 9 | (defmacro with-display-context (view &body body)
|
|---|
| 10 | `(let* ((hi::*current-view* ,view)
|
|---|
| 11 | (hi::*current-buffer* (hemlock-view-buffer hi::*current-view*)))
|
|---|
| 12 | ,@body))
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 | ;; User variable. Maps symbol categories (see compute-symbol-category) to color specs
|
|---|
| 16 | (defvar *lisp-code-colors* '((:string :blue)
|
|---|
| 17 | (:comment :brown)
|
|---|
| 18 | (:double-comment :orange)
|
|---|
| 19 | (:triple-comment :red)
|
|---|
| 20 | (:system-symbol (0 .5 0 1))
|
|---|
| 21 | (:definition (1 0 1 1))
|
|---|
| [15931] | 22 | (:keyword :purple)
|
|---|
| [15966] | 23 | (:unmatched-paren :red)
|
|---|
| 24 | (:matched-paren (:background (0.3 0.875 0.8125 1)))))
|
|---|
| 25 |
|
|---|
| [15930] | 26 | ;; Cache for actual color objects.
|
|---|
| [15966] | 27 | (ccl:defloadvar *lisp-code-colors-cache* nil)
|
|---|
| [15906] | 28 |
|
|---|
| [15930] | 29 | ;; (cached-lisp-code-colors)
|
|---|
| 30 | (defun cached-lisp-code-colors ()
|
|---|
| 31 | (let ((specs (car *lisp-code-colors-cache*))
|
|---|
| 32 | (alist (cdr *lisp-code-colors-cache*))
|
|---|
| 33 | (user-alist *lisp-code-colors*))
|
|---|
| 34 | (flet ((get-spec (cell)
|
|---|
| 35 | (let ((spec (cdr cell)))
|
|---|
| 36 | (if (and (consp spec) (null (cdr spec)))
|
|---|
| 37 | (car spec)
|
|---|
| 38 | spec))))
|
|---|
| 39 | (declare (inline get-spec))
|
|---|
| 40 | (unless (and (eql (length user-alist) (length alist))
|
|---|
| 41 | (loop for spec in specs for cell in alist for user-cell in user-alist
|
|---|
| 42 | always (and (eq (car cell) (car user-cell)) (eq spec (get-spec user-cell)))))
|
|---|
| 43 | (setq specs (mapcar #'get-spec user-alist))
|
|---|
| 44 | (setq alist (mapcar #'(lambda (user-cell spec)
|
|---|
| [15966] | 45 | (cons (car user-cell)
|
|---|
| 46 | (if (and (consp spec) (keywordp (car spec)) (null (cddr spec)))
|
|---|
| 47 | (cons (car spec) (hemlock-ext:lookup-color (cadr spec)))
|
|---|
| 48 | (cons :foreground (hemlock-ext:lookup-color spec)))))
|
|---|
| [15930] | 49 | user-alist specs))
|
|---|
| 50 | (setq *lisp-code-colors-cache* (cons specs alist)))
|
|---|
| 51 | alist)))
|
|---|
| [15906] | 52 |
|
|---|
| [15966] | 53 | (defun hemlock:compute-paren-highlighting ()
|
|---|
| 54 | "Compute the positions of the characters to be shown as matching parens"
|
|---|
| 55 | (let* ((point (current-point))
|
|---|
| 56 | (color-alist (cached-lisp-code-colors))
|
|---|
| 57 | (color (cdr (assq :matched-paren color-alist))))
|
|---|
| 58 | (when color
|
|---|
| 59 | (cond ((test-char (next-character point) :lisp-syntax :open-paren)
|
|---|
| 60 | (pre-command-parse-check point)
|
|---|
| 61 | (when (valid-spot point t)
|
|---|
| 62 | (with-mark ((temp point))
|
|---|
| 63 | (when (list-offset temp 1)
|
|---|
| 64 | (list (cons (mark-absolute-position point) color)
|
|---|
| 65 | (cons (1- (mark-absolute-position temp)) color))))))
|
|---|
| 66 | ((test-char (previous-character point) :lisp-syntax :close-paren)
|
|---|
| 67 | (pre-command-parse-check point)
|
|---|
| 68 | (when (valid-spot point nil)
|
|---|
| [15906] | 69 | (with-mark ((temp point))
|
|---|
| 70 | (when (list-offset temp -1)
|
|---|
| [15966] | 71 | (list (cons (mark-absolute-position temp) color)
|
|---|
| 72 | (cons (1- (mark-absolute-position point)) color))))))))))
|
|---|
| [15906] | 73 |
|
|---|
| 74 |
|
|---|
| 75 | ;; Return nil to use the default Cocoa selection, which will be word for double-click, line for triple.
|
|---|
| 76 | (defun hemlock:selection-for-click (mark paragraph-mode-p)
|
|---|
| 77 | ;; Handle lisp mode specially, otherwise just go with default Cocoa behavior
|
|---|
| 78 | (when (string= (buffer-major-mode (mark-buffer mark)) "Lisp")
|
|---|
| 79 | (unless paragraph-mode-p
|
|---|
| 80 | (let ((region (word-region-at-mark mark)))
|
|---|
| 81 | (when region
|
|---|
| 82 | (return-from selection-for-click region))))
|
|---|
| 83 | (pre-command-parse-check mark)
|
|---|
| 84 | (form-region-at-mark mark)))
|
|---|
| 85 |
|
|---|
| 86 | (defun hemlock:move-point-for-click (buffer index)
|
|---|
| 87 | (let* ((point (buffer-point buffer))
|
|---|
| 88 | (mark (and (%buffer-region-active-p buffer) (buffer-mark buffer))))
|
|---|
| 89 | (setf (hi::buffer-region-active buffer) nil)
|
|---|
| 90 | (unless (eql (mark-absolute-position point) index) ;; if point is already at target, leave mark alone
|
|---|
| 91 | (if (and mark (eql (mark-absolute-position mark) index))
|
|---|
| 92 | (move-mark mark point)
|
|---|
| 93 | (push-new-buffer-mark point))
|
|---|
| 94 | (move-to-absolute-position point index))))
|
|---|
| 95 |
|
|---|
| 96 |
|
|---|
| 97 | (defun shortest-package-name (package)
|
|---|
| 98 | (let* ((name (package-name package))
|
|---|
| 99 | (len (length name)))
|
|---|
| 100 | (dolist (nick (package-nicknames package) name)
|
|---|
| 101 | (let* ((nicklen (length nick)))
|
|---|
| 102 | (if (< nicklen len)
|
|---|
| 103 | (setq name nick len nicklen))))))
|
|---|
| 104 |
|
|---|
| [15926] | 105 | (defun hemlock:update-current-package (&optional pkg (buffer (current-buffer)))
|
|---|
| 106 | (when (equalp (buffer-major-mode buffer) "Lisp")
|
|---|
| [15906] | 107 | (unless pkg
|
|---|
| 108 | (setq pkg (or (package-at-mark (current-point))
|
|---|
| [15926] | 109 | (variable-value 'default-package :buffer buffer))))
|
|---|
| [15906] | 110 | (when pkg
|
|---|
| 111 | (let* ((name (if (packagep pkg) (package-name pkg) (string pkg)))
|
|---|
| [15926] | 112 | (curname (variable-value 'current-package :buffer buffer)))
|
|---|
| [15906] | 113 | (when (setq pkg (find-package name))
|
|---|
| 114 | (setq name (shortest-package-name pkg)))
|
|---|
| 115 | (if (or (null curname)
|
|---|
| 116 | (not (string= curname name)))
|
|---|
| [15926] | 117 | (setf (variable-value 'current-package :buffer buffer) name))))))
|
|---|
| [15906] | 118 |
|
|---|
| 119 | ;; advance to next symbol, ignoring form boundaries, strings, etc.
|
|---|
| 120 | (defun %scan-to-symbol (mark)
|
|---|
| 121 | (loop while (%scan-to-form mark t)
|
|---|
| 122 | do (unless (test-char (next-character mark) :lisp-syntax (or :string-quote :open-paren :close-paren))
|
|---|
| 123 | (return mark))
|
|---|
| 124 | do (mark-after mark)))
|
|---|
| 125 |
|
|---|
| 126 | ;; Advance to next atom, ignoring open parens (but not close parens, unlike above).
|
|---|
| 127 | (defun %scan-down-to-atom (mark)
|
|---|
| 128 | (loop while (%scan-to-form mark t)
|
|---|
| 129 | do (unless (test-char (next-character mark) :lisp-syntax :open-paren)
|
|---|
| 130 | (return mark))
|
|---|
| 131 | do (mark-after mark)))
|
|---|
| 132 |
|
|---|
| 133 | #+debug
|
|---|
| 134 | (defun buffer-short-name ()
|
|---|
| 135 | (let* ((full-name (buffer-name (current-buffer)))
|
|---|
| 136 | (pos (position #\space full-name)))
|
|---|
| 137 | (if pos (subseq full-name 0 pos) full-name)))
|
|---|
| 138 |
|
|---|
| 139 | ;; When get a cache miss, means we'll fill in parsing and line-origin caches for the whole buffer, so might
|
|---|
| 140 | ;; as well get a little extra coloring pre-computed in as well, for smoother scrolling...
|
|---|
| 141 | (defparameter $coloring-cache-extra 1000)
|
|---|
| 142 |
|
|---|
| 143 | (defstruct coloring-cache
|
|---|
| 144 | (tick nil)
|
|---|
| 145 | (start 0)
|
|---|
| 146 | (end 0)
|
|---|
| [15930] | 147 | (colors nil)
|
|---|
| [15906] | 148 | (data nil))
|
|---|
| 149 |
|
|---|
| 150 | (defun make-sym-vec ()
|
|---|
| 151 | (make-array 0 :displaced-to "" :adjustable t))
|
|---|
| 152 |
|
|---|
| 153 | (defun displace-to-region (sym-vec start-mark end-mark)
|
|---|
| 154 | (let* ((sym-line (mark-line start-mark))
|
|---|
| 155 | (line-str (line-string sym-line))
|
|---|
| 156 | (start-pos (mark-charpos start-mark))
|
|---|
| 157 | (end-pos (if (eq sym-line (mark-line end-mark))
|
|---|
| 158 | (mark-charpos end-mark)
|
|---|
| 159 | (progn
|
|---|
| 160 | (setq line-str (region-to-string (region start-mark end-mark)))
|
|---|
| 161 | (setq start-pos 0)
|
|---|
| 162 | (length line-str)))))
|
|---|
| 163 | (ccl::%displace-array sym-vec nil (- end-pos start-pos) line-str start-pos T)))
|
|---|
| 164 |
|
|---|
| 165 | #+debug
|
|---|
| 166 | (defmethod print-object ((cache coloring-cache) stream)
|
|---|
| 167 | (print-unreadable-object (stream cache :identity nil :type t)
|
|---|
| 168 | (format stream "~s:~s @~s" (coloring-cache-start cache) (coloring-cache-end cache) (coloring-cache-tick cache))))
|
|---|
| 169 |
|
|---|
| 170 | (defun hemlock:compute-syntax-coloring (start-pos length)
|
|---|
| 171 | (let* ((buffer (current-buffer))
|
|---|
| 172 | (end-pos (+ start-pos length))
|
|---|
| 173 | (tick (buffer-signature buffer))
|
|---|
| [15930] | 174 | (colors (cached-lisp-code-colors))
|
|---|
| [15906] | 175 | (cache (or (getf (buffer-plist buffer) 'coloring-cache)
|
|---|
| 176 | (setf (getf (buffer-plist buffer) 'coloring-cache) (make-coloring-cache)))))
|
|---|
| 177 | (unless (and (eql (coloring-cache-tick cache) tick)
|
|---|
| 178 | (<= (coloring-cache-start cache) start-pos)
|
|---|
| 179 | (<= end-pos (coloring-cache-end cache))
|
|---|
| [15930] | 180 | (eq colors (coloring-cache-colors cache)))
|
|---|
| [15906] | 181 | (setq start-pos (max 0 (- start-pos $coloring-cache-extra)))
|
|---|
| 182 | (setq end-pos (+ end-pos $coloring-cache-extra))
|
|---|
| 183 | (let ((res (compute-syntax-coloring-in-region buffer start-pos end-pos)))
|
|---|
| 184 | (setf (coloring-cache-start cache) start-pos
|
|---|
| 185 | (coloring-cache-end cache) end-pos
|
|---|
| [15930] | 186 | (coloring-cache-colors cache) colors
|
|---|
| [15906] | 187 | (coloring-cache-data cache) res
|
|---|
| 188 | (coloring-cache-tick cache) tick)))
|
|---|
| 189 | (coloring-cache-data cache)))
|
|---|
| 190 |
|
|---|
| 191 |
|
|---|
| 192 | ;; Map strings to symbols, to avoid consing strings for upcasing
|
|---|
| 193 | (defvar *string-to-symbol-cache* (make-hash-table :test #'equalp))
|
|---|
| 194 |
|
|---|
| 195 | (defun case-insensitive-string-to-symbol (string pkg)
|
|---|
| 196 | (when (null pkg) (setq pkg *package*))
|
|---|
| 197 | (let* ((pkg-alist (gethash string *string-to-symbol-cache*))
|
|---|
| 198 | (known (assoc pkg pkg-alist)))
|
|---|
| 199 | (if known
|
|---|
| 200 | (cdr known)
|
|---|
| 201 | (let* ((str (coerce string 'simple-string))
|
|---|
| 202 | (*package* pkg)
|
|---|
| 203 | (*read-eval* nil)
|
|---|
| 204 | (sym (ignore-errors (read-from-string str))))
|
|---|
| [15911] | 205 | (unless (symbolp sym) (setq sym nil))
|
|---|
| [15906] | 206 | (setf (gethash str *string-to-symbol-cache*) (cons (cons pkg sym) pkg-alist))
|
|---|
| 207 | sym))))
|
|---|
| 208 |
|
|---|
| 209 |
|
|---|
| 210 | ;; Try to exclude use of symbol in data.
|
|---|
| 211 | (defun mark-at-invocation-p (start-mark)
|
|---|
| 212 | (and (test-char (previous-character start-mark) :lisp-syntax :open-paren)
|
|---|
| 213 | (prog2
|
|---|
| 214 | (mark-before start-mark)
|
|---|
| [15930] | 215 | (not (test-char (previous-character start-mark) :lisp-syntax (or :prefix :open-paren)))
|
|---|
| [15906] | 216 | (mark-after start-mark))))
|
|---|
| 217 |
|
|---|
| 218 | (defun compute-symbol-category (start-mark sym)
|
|---|
| 219 | (when (ccl::non-nil-symbol-p sym)
|
|---|
| 220 | (cond ((and (or (macro-function sym)
|
|---|
| 221 | (ccl::special-form-p sym))
|
|---|
| 222 | (mark-at-invocation-p start-mark))
|
|---|
| 223 | :system-symbol)
|
|---|
| 224 | ((keywordp sym)
|
|---|
| 225 | :keyword)
|
|---|
| 226 | (t nil))))
|
|---|
| 227 |
|
|---|
| 228 | (defvar *defining-symbols*
|
|---|
| 229 | '(defun defgeneric defmethod defmacro
|
|---|
| 230 | define-compiler-macro define-modify-macro define-symbol-macro
|
|---|
| 231 | define-setf-expander defsetf
|
|---|
| 232 | defvar defparameter defconstant
|
|---|
| 233 | define-method-combination
|
|---|
| 234 | defclass defstruct deftype define-condition
|
|---|
| 235 | defpackage
|
|---|
| 236 | ccl:advise
|
|---|
| 237 | ccl:def-load-pointers
|
|---|
| 238 | ccl:define-definition-type
|
|---|
| 239 | ccl:defloadvar
|
|---|
| 240 | ccl:defglobal ccl:defstaticvar ccl:define-declaration ccl:defstatic ccl:defcallback ccl:define-setf-method
|
|---|
| 241 | ccl:define-character-encoding
|
|---|
| 242 | ccl:defglobal
|
|---|
| 243 | hemlock-interface:defcommand
|
|---|
| 244 | hemlock-interface:define-file-option
|
|---|
| 245 | hemlock-interface:define-file-type-hook
|
|---|
| 246 | hemlock-interface:define-keysym-code
|
|---|
| 247 | gui::def-cocoa-default
|
|---|
| 248 | objc:define-objc-class-method
|
|---|
| 249 | objc:define-objc-method
|
|---|
| 250 | objc:defmethod))
|
|---|
| 251 |
|
|---|
| 252 | ;; If true, the next atom following this sym will be automatically categorized as :definition, without going through compute-symbol-category.
|
|---|
| 253 | (defun defining-symbol-p (start-mark sym)
|
|---|
| 254 | (and (mark-at-invocation-p start-mark)
|
|---|
| 255 | (or (member sym *defining-symbols*) ;; recognize these even if indented or embedded.
|
|---|
| 256 | (and (eql (mark-charpos start-mark) 1) ;; but accept any toplevel "(def".
|
|---|
| 257 | (or (let ((str (string sym)))
|
|---|
| 258 | (and (> (length str) 3) (string-equal "def" str :end2 3)))
|
|---|
| 259 | ;; color top-level setq's, just for fun
|
|---|
| 260 | (eq sym 'setq))))))
|
|---|
| 261 |
|
|---|
| 262 |
|
|---|
| 263 | (defun compute-string/comment-coloring-in-region (region-start region-end)
|
|---|
| 264 | (let* ((lisp-code-colors (cached-lisp-code-colors))
|
|---|
| 265 | (start-line (mark-line region-start))
|
|---|
| 266 | (end-line (line-next (mark-line region-end)))
|
|---|
| 267 | (start-charpos (mark-charpos region-start)))
|
|---|
| 268 | (assert (not (eq start-line end-line)))
|
|---|
| 269 | (loop
|
|---|
| 270 | for line = start-line then (line-next line) until (eq line end-line)
|
|---|
| 271 | for info = (getf (line-plist line) 'lisp-info)
|
|---|
| 272 | when info
|
|---|
| 273 | nconc (loop with origin = (hi::line-origin line)
|
|---|
| 274 | for last-end = 0 then end-offset
|
|---|
| 275 | for (start-offset . end-offset) in (lisp-info-ranges-to-ignore info)
|
|---|
| 276 | for syntax = (if (eql start-offset 0)
|
|---|
| 277 | (lisp-info-begins-quoted info)
|
|---|
| 278 | (if (< last-end start-offset)
|
|---|
| 279 | (character-attribute :lisp-syntax (line-character line (1- start-offset)))
|
|---|
| 280 | :comment))
|
|---|
| 281 | do (when (member syntax '(:symbol-quote :string-quote))
|
|---|
| [15909] | 282 | (when (< 0 start-offset)
|
|---|
| 283 | (decf start-offset))
|
|---|
| 284 | (when (< end-offset (line-length line))
|
|---|
| 285 | (incf end-offset)))
|
|---|
| [15906] | 286 | unless (and (eq line start-line) (<= end-offset start-charpos))
|
|---|
| 287 | nconc (let* ((type (case syntax
|
|---|
| [15909] | 288 | ((:char-quote :symbol-quote) nil)
|
|---|
| 289 | (:string-quote :string)
|
|---|
| [15906] | 290 | (t (loop for i from start-offset as nsemi upfrom 0
|
|---|
| 291 | until (or (eql nsemi 3)
|
|---|
| 292 | (eql i end-offset)
|
|---|
| 293 | (not (test-char (line-character line i) :lisp-syntax :comment)))
|
|---|
| 294 | finally (return (case nsemi
|
|---|
| 295 | (2 :double-comment)
|
|---|
| 296 | (3 :triple-comment)
|
|---|
| 297 | (t :comment)))))))
|
|---|
| 298 | (color (and type (cdr (assq type lisp-code-colors)))))
|
|---|
| 299 | (when color
|
|---|
| 300 | (list (list* (+ origin start-offset) (- end-offset start-offset) color))))))))
|
|---|
| 301 |
|
|---|
| 302 | (defun coloring-region (start-mark end-mark color)
|
|---|
| 303 | (when color
|
|---|
| 304 | (let* ((start (mark-absolute-position start-mark))
|
|---|
| 305 | (end (mark-absolute-position end-mark))
|
|---|
| 306 | (len (- end start)))
|
|---|
| 307 | (when (> len 0)
|
|---|
| 308 | (list* start len color)))))
|
|---|
| 309 |
|
|---|
| 310 | (defun compute-symbol-coloring-in-region (region-start region-end)
|
|---|
| 311 | (let* ((sym-vec (make-sym-vec))
|
|---|
| 312 | (pkg nil)
|
|---|
| 313 | (lisp-colors (cached-lisp-code-colors))
|
|---|
| 314 | (defn-color (cdr (assq :definition lisp-colors))))
|
|---|
| 315 | (with-mark ((start-mark region-start)
|
|---|
| 316 | (end-mark region-start))
|
|---|
| 317 | (let ((pkgname (package-at-mark region-end end-mark)))
|
|---|
| 318 | (when pkgname
|
|---|
| 319 | (when (mark< region-start end-mark)
|
|---|
| 320 | ;; Argh, more than one package in region. KLUDGE!!
|
|---|
| 321 | (return-from compute-symbol-coloring-in-region
|
|---|
| 322 | (nconc (compute-symbol-coloring-in-region region-start (mark-before end-mark))
|
|---|
| 323 | (compute-symbol-coloring-in-region (mark-after end-mark) region-end))))
|
|---|
| 324 | (setq pkg (find-package pkgname))))
|
|---|
| 325 | (loop
|
|---|
| 326 | while (and (%scan-to-symbol start-mark) (mark< start-mark region-end))
|
|---|
| 327 | for sym = (progn
|
|---|
| 328 | (move-mark end-mark start-mark)
|
|---|
| 329 | (unless (forward-form end-mark) (move-mark end-mark region-end))
|
|---|
| 330 | (case-insensitive-string-to-symbol (displace-to-region sym-vec start-mark end-mark) pkg))
|
|---|
| 331 | for type = (compute-symbol-category start-mark sym)
|
|---|
| 332 | for reg = (when type
|
|---|
| 333 | (let ((color (cdr (assq type lisp-colors))))
|
|---|
| 334 | (when color
|
|---|
| 335 | (coloring-region start-mark end-mark color))))
|
|---|
| 336 | when reg collect reg
|
|---|
| 337 | ;; if we're at start of a defining form, color the thing being defined.
|
|---|
| 338 | when (and defn-color
|
|---|
| 339 | (defining-symbol-p start-mark sym)
|
|---|
| 340 | (form-offset (move-mark start-mark end-mark) 1)
|
|---|
| 341 | (%scan-down-to-atom end-mark)
|
|---|
| 342 | (mark< end-mark region-end))
|
|---|
| 343 | collect (progn
|
|---|
| 344 | (move-mark start-mark end-mark)
|
|---|
| 345 | (unless (and (forward-form end-mark)
|
|---|
| 346 | (mark<= end-mark region-end))
|
|---|
| 347 | (move-mark end-mark region-end))
|
|---|
| 348 | (unless (mark< start-mark end-mark)
|
|---|
| 349 | (warn "definition got start ~s end ~s region-end ~s" start-mark end-mark
|
|---|
| 350 | region-end)
|
|---|
| 351 | (move-mark end-mark start-mark))
|
|---|
| 352 | (coloring-region start-mark end-mark defn-color))
|
|---|
| 353 | do (rotatef start-mark end-mark)))))
|
|---|
| 354 |
|
|---|
| [15931] | 355 | (defun compute-unmatched-parens-coloring-in-region (start-mark end-mark)
|
|---|
| 356 | (macrolet ((scan-loop (forwardp open-key buffer-start-mark start-line end-line close-key)
|
|---|
| 357 | `(loop with paren-count = 0 with limit-line = (neighbor-line ,end-line ,forwardp) with in-region-p = nil
|
|---|
| 358 | for line = (mark-line (,buffer-start-mark (mark-buffer m))) then (neighbor-line line ,forwardp)
|
|---|
| 359 | until (eq line limit-line)
|
|---|
| 360 | for info = (or (getf (line-plist line) 'lisp-info) (return nil))
|
|---|
| 361 | as parens-on-line = ,(if forwardp '(lisp-info-net-close-parens info) '(lisp-info-net-open-parens info))
|
|---|
| 362 | do (when (eq line ,start-line) (setq in-region-p t))
|
|---|
| 363 | do (decf paren-count parens-on-line)
|
|---|
| 364 | do (when (< paren-count 0)
|
|---|
| 365 | (when in-region-p
|
|---|
| 366 | ,(if forwardp '(line-start m line) '(line-end m line))
|
|---|
| 367 | (loop with net-count = (+ paren-count parens-on-line) doing
|
|---|
| 368 | (unless (scan-direction-valid m ,forwardp :lisp-syntax (or :close-paren :open-paren :newline))
|
|---|
| 369 | (error "couldn't find ~s mismatches" (- paren-count)))
|
|---|
| 370 | (ecase (character-attribute :lisp-syntax (direction-char m ,forwardp))
|
|---|
| 371 | (,open-key (incf net-count))
|
|---|
| 372 | (,close-key (when (< (decf net-count) 0)
|
|---|
| 373 | (push (cons ,(if forwardp
|
|---|
| 374 | '(mark-absolute-position m)
|
|---|
| 375 | '(1- (mark-absolute-position m)))
|
|---|
| 376 | coloring-data) result)
|
|---|
| 377 | (when (eql (incf paren-count) 0) (return))
|
|---|
| 378 | (setq net-count 0))))
|
|---|
| 379 | (neighbor-mark m ,forwardp)))
|
|---|
| 380 | (setq paren-count 0))
|
|---|
| 381 | do (incf paren-count ,(if forwardp '(lisp-info-net-open-parens info) '(lisp-info-net-close-parens info))))))
|
|---|
| 382 | (with-mark ((m start-mark))
|
|---|
| 383 | (let* ((end-line (mark-line end-mark))
|
|---|
| 384 | (start-line (mark-line start-mark))
|
|---|
| 385 | (color (or (cdr (assq :unmatched-paren (cached-lisp-code-colors)))
|
|---|
| 386 | (return-from compute-unmatched-parens-coloring-in-region nil)))
|
|---|
| 387 | (coloring-data (cons 1 color))
|
|---|
| 388 | (result nil))
|
|---|
| 389 | (scan-loop t :open-paren buffer-start-mark start-line end-line :close-paren) ; Compute unmatched close parens, top down.
|
|---|
| 390 | (scan-loop nil :close-paren buffer-end-mark end-line start-line :open-paren) ; Compute umatched open parens, bottom up.
|
|---|
| 391 | result))))
|
|---|
| 392 |
|
|---|
| [15906] | 393 | (defun compute-syntax-coloring-in-region (buffer start-pos end-pos)
|
|---|
| 394 | (let* ((some-mark (buffer-point buffer)))
|
|---|
| 395 | (with-mark ((start-mark some-mark)
|
|---|
| 396 | (end-mark some-mark))
|
|---|
| 397 | (unless (move-to-absolute-position start-mark start-pos)
|
|---|
| 398 | (buffer-end start-mark))
|
|---|
| 399 | (unless (move-to-absolute-position end-mark end-pos)
|
|---|
| 400 | (buffer-end end-mark))
|
|---|
| 401 | (assert (mark<= start-mark end-mark))
|
|---|
| 402 | (when (mark< start-mark end-mark)
|
|---|
| 403 | (pre-command-parse-check start-mark)
|
|---|
| 404 | (sort (nconc (compute-string/comment-coloring-in-region start-mark end-mark)
|
|---|
| [15931] | 405 | (compute-symbol-coloring-in-region start-mark end-mark)
|
|---|
| 406 | (compute-unmatched-parens-coloring-in-region start-mark end-mark))
|
|---|
| [15906] | 407 | #'< :key #'car)))))
|
|---|
| 408 |
|
|---|