Function: logview--initialize-submode
logview--initialize-submode is a natively compiled function defined in
logview.el.
Signature
(logview--initialize-submode NAME DEFINITION STANDARD-TIMESTAMPS &optional TEST-LINE)
Source Code
;; Defined in /nix/store/3zkn9hgpv447zb8nrg55d9x2ynmmrk40-emacs-packages-deps/share/emacs/site-lisp/elpa/logview-20260218.2013/logview.el
;; Returns non-nil if TEST-LINE is "promising".
(defun logview--initialize-submode (name definition standard-timestamps &optional test-line)
(let* ((format (cdr (assq 'format definition)))
(timestamp-names (when test-line (cdr (assq 'timestamp definition))))
(timestamp-options (if timestamp-names
(mapcar (lambda (name)
(logview--get-split-alists name "timestamp format"
logview-additional-timestamp-formats logview-std-timestamp-formats))
;; Don't be too strict to the definition. Many if not most users
;; don't go through customization interface to create it.
(if (listp timestamp-names) timestamp-names (list timestamp-names)))
standard-timestamps))
(search-from 0)
(parts (list "^"))
next
end
starter terminator
levels
timestamp-at
cannot-match
features
have-explicit-message
(add-text-part (lambda (from to)
(push (replace-regexp-in-string "[ \t]+" "[ \t]+" (regexp-quote (substring format from to))) parts))))
(unless (and (stringp format) (> (length format) 0))
(user-error "Invalid submode '%s': no format string" name))
(while (setq next (string-match logview--entry-part-regexp format search-from))
(when (> next search-from)
(funcall add-text-part search-from next))
(setq end (match-end 0)
starter (when (> next 0)
(aref format (1- next)))
terminator (when (< end (length format))
(aref format end)))
(cond ((match-beginning logview--timestamp-group)
(push nil parts)
(push 'timestamp features)
(setq timestamp-at parts))
((match-beginning logview--level-group)
(setq levels (logview--get-split-alists (cdr (assq 'levels definition)) "level mapping"
logview-additional-level-mappings logview-std-level-mappings))
(push (format "\\(?%d:%s\\)" logview--level-group
(regexp-opt (apply #'append (mapcar (lambda (final-level) (cdr (assq final-level levels)))
logview--final-levels))))
parts)
(push 'level features))
((match-beginning logview--message-group)
(unless (= (match-end logview--message-group) (length format))
(user-error "Field `MESSAGE' can only be placed at the very end of format string"))
(setq have-explicit-message t))
(t
(dolist (k (list logview--name-group logview--thread-group logview--ignored-group))
;; See definition of `logview--entry-part-regexp' for the meaning of 4 and 10.
(let ((special-regexp (match-beginning (+ k 4))))
(when (or (match-beginning k) special-regexp)
(push (format "\\(?%s:%s\\)"
(if (/= k logview--ignored-group)
(number-to-string k)
"")
(cond (special-regexp
(let ((forced-regexp (match-string 10 format)))
(unless (logview--valid-regexp-p forced-regexp)
;; Ideally would also ensure that there are no catching groups,
;; but for this we'd need `xr' as dependency. Not now.
(warn "In format specifier `%s': `%s' is not a valid regexp" format forced-regexp)
(setf cannot-match t))
forced-regexp))
((and starter terminator
(or (and (= starter ?\() (= terminator ?\)))
(and (= starter ?\[) (= terminator ?\]))))
;; See https://github.com/doublep/logview/issues/2 We allow _one_
;; level of nested parens inside parenthesized THREAD or NAME.
;; Allowing more would complicate regexp even further. Unlimited
;; nesting level is not possible with regexps at all.
;;
;; 'rx-to-string' is used to avoid escaping things ourselves.
(rx-to-string `(seq (* (not (any ,starter ,terminator ?\n)))
(* ,starter (* (not (any ?\n))) ,terminator
(* (not (any ,starter ,terminator ?\n)))))
t))
((and terminator (/= terminator ? ))
(format "[^%c\n]*" terminator))
(terminator
"[^ \t\n]+")
(t
".+")))
parts)
(push (if (= k logview--name-group) 'name 'thread) features))))))
(setq search-from end))
(unless cannot-match
(when (< search-from (length format))
(funcall add-text-part search-from nil))
;; Unless `MESSAGE' field is used explicitly, behave as if format string ends with whitespace.
(unless (or have-explicit-message (string-match-p "[ \t]$" format))
(push "\\(?:[ \t]+\\|$\\)" parts))
(setq parts (nreverse parts))
(when timestamp-at
;; Speed optimization: if the submode includes a timestamp, but the test line doesn't have even two
;; digits at the expected place, don't even loop through all the timestamp options.
(setcar timestamp-at ".*[0-9][0-9].*")
(when (and test-line (not (string-match-p (apply #'concat parts) test-line)))
(setq cannot-match t))))
(unless cannot-match
(dolist (timestamp-option (if timestamp-at timestamp-options '(nil)))
(let* ((timestamp-pattern (assq 'java-pattern timestamp-option))
(timestamp-locale (cdr (assq 'locale timestamp-option)))
(timestamp-regexp (if timestamp-pattern
(condition-case error
(apply #'datetime-matching-regexp 'java (cdr timestamp-pattern)
:locale timestamp-locale
(append (cdr (assq 'datetime-options timestamp-option)) logview--datetime-matching-options))
;; 'datetime' doesn't mention the erroneous pattern to keep
;; the error message concise. Let's do it ourselves.
(error (warn "In Java timestamp pattern '%s': %s"
(cdr timestamp-pattern) (error-message-string error))
nil))
(cdr (assq 'regexp timestamp-option)))))
(when (or timestamp-regexp (null timestamp-at))
(when timestamp-at
(setcar timestamp-at (format "\\(?%d:%s\\)" logview--timestamp-group timestamp-regexp)))
(let ((regexp (apply #'concat parts))
(level-index 0))
(when (or (null test-line) (string-match-p regexp test-line))
(setq logview--submode-name name
logview--process-buffer-changes t
logview--entry-regexp regexp
logview--submode-features features
logview--submode-level-data nil)
(logview--update-mode-name)
(when (memq 'level features)
(dolist (final-level logview--final-levels)
(dolist (level (cdr (assoc final-level levels)))
(push (cons level (cons level-index (cons (intern (format "logview-%s-entry" (symbol-name final-level)))
(intern (format "logview-level-%s" (symbol-name final-level))))))
logview--submode-level-data)
(setq level-index (1+ level-index)))))
(setq logview--submode-level-faces (make-vector level-index nil))
(dolist (level-data logview--submode-level-data)
(aset logview--submode-level-faces (cadr level-data) (cddr level-data)))
(when (memq 'timestamp features)
(let ((num-fractionals (apply #'datetime-pattern-num-second-fractionals 'java (cdr timestamp-pattern) logview--datetime-parsing-options)))
(setf logview--timestamp-difference-format-string (format "%%+.%df" num-fractionals)
logview--timestamp-gap-format-string (format "%%.%df" num-fractionals)))
;; Largely for catching errors in `datetime's determination of system timezone.
(setf logview--submode-timestamp-parser
(condition-case error
(apply #'datetime-parser-to-float 'java (cdr timestamp-pattern) :locale timestamp-locale :timezone 'system
logview--datetime-parsing-options)
(error (warn "%s" (error-message-string error))
(let ((utc-parser (ignore-errors (apply #'datetime-parser-to-float 'java (cdr timestamp-pattern) :locale timestamp-locale
logview--datetime-parsing-options))))
(if utc-parser
(progn (warn "Using UTC for the log file instead, in hopes it will be good enough")
utc-parser)
;; Only to avoid errors later. Results will be incorrect, of course, but
;; at least the mode everything other than some timestamp-related
;; commands will work. The cause is reported as a warning above.
(lambda (_) 0.0)))))))
(read-only-mode 1)
(when buffer-file-name
(pcase logview-auto-revert-mode
(`auto-revert-mode (auto-revert-mode 1))
(`auto-revert-tail-mode (auto-revert-tail-mode 1))))
(logview--refilter)
(throw 'success nil))))))
;; "Promising" line.
t)))